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:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user