re(gfx): decode sleep 0xc8 timing (non-blocking ms timer) + 0x20c present

- sleep_op_0xc8 @0x420ec0: arms a non-blocking main-loop-polled timer
  (sleep_timer_arm @0x44cff0); operand = milliseconds. Also carries
  anti-tamper + gfx cmd-type 3 (not needed host-side).
- 0x20c = gfx_op_0x20c_present_frame (host presents continuously -> noop_headless).
- Ghidra annotated + saved; opcodes.toml rebuilt (lint clean); engine-re.md.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
gamer147
2026-07-08 08:57:22 -04:00
parent afb76c66aa
commit 6ce4da05a1
3 changed files with 57 additions and 22 deletions

View File

@@ -2036,17 +2036,18 @@ abi_source = "kelebek+decode-validated"
[opcode.semantics]
name = "sleep"
category = "unknown"
summary = ""
category = "control"
summary = "Pause the script for <duration> milliseconds while rendering continues (frame pacing)."
details = "Native handler sleep_op_0xc8 @0x420ec0 is NON-BLOCKING: it arms a timer (sleep_timer_arm @0x44cff0 at ctx+0x5f304 = active flag + start tick + duration) that the engine main loop polls, resuming the script when elapsed. Operand UNIT = MILLISECONDS (start = ms tick source DAT_0056f3d4, timeGetTime/GetTickCount class). duration<10 fast-paths via [0x56f0b8]; all real scene sleeps (100/750/1000) are >=10. The handler also writes gfx cmd-type 3 + runs anti-tamper checks, neither needed host-side. Port equivalent: the Godot host blocks the VM background thread <duration> ms while the per-frame compositor keeps presenting -> the sleep-paced opening AE* burst animates. Headless hosts no-op it (parity)."
noop_headless = false
source = "kelebek"
confidence = "med"
source = "investigation"
confidence = "high"
depends_on = []
evidence = ""
evidence = "Ghidra: dispatch ctx[0x26c93+0xc8]=0x420ec0; sleep_op_0xc8 + sleep_timer_arm decoded/annotated 2026-07-08. docs/engine-re.md sleep section."
[[opcode.semantics.args]]
i = 1
role = ""
role = "duration_ms"
observed_types = ["imm"]
[[opcode]]
@@ -5101,19 +5102,20 @@ observed_types = ["imm", "l-int"]
[[opcode]]
op = 0x20c
label = "u00416200"
label = "present-frame"
argc = 0
abi_source = "kelebek+decode-validated"
[opcode.semantics]
name = "u00416200"
category = "unknown"
summary = ""
noop_headless = false
source = "kelebek"
confidence = "low"
name = "present-frame"
category = "draw"
summary = "Present the composited frame (native gfx_render_frame). Host-implicit: our compositor presents every frame."
details = "Native handler gfx_op_0x20c_present_frame (dispatch ctx[0x26c93+0x20c]) -> gfx_render_frame @0x4820b0 flips the composited buffers. Our Godot host runs a continuous per-frame compositor (Main.Recomposite in _Process), so an explicit present is redundant and the VM can skip it. noop_headless=true -> scene coverage classifies it safe-noop. Kelebek label u00416200 was VA-drift (unrelated fn); real handler resolved via the dispatch table."
noop_headless = true
source = "investigation"
confidence = "high"
depends_on = []
evidence = ""
evidence = "Ghidra: dispatch table FUN_00413860 param_1[0x26e9f]=gfx_op_0x20c_present_frame; 0x26e9f-0x26c93=0x20c. 2026-07-08."
[[opcode]]
op = 0x20d