Skip to content

[GBug] Ocarina of Time (0400486024DEC000): black screen after the intro, main scene draws skipped, compute rejected at op 4a4 and matrix multiply 23c #589

Open

Description

@CloudP4bbs

Before submitting

  • I searched existing issues and found no duplicate
  • I'm using the latest build
  • My game is legally dumped from my own console

Emulator build

Clean local build of b6706b0c29 (master base 2965d15677 plus merged #567), Visual Studio 2022, MSVC 14.44.35207, Qt 6.8.3.

Regression

  • This is a regression (it worked in an older build)

Last known working build

No response

Game

Other / not listed: The Legend of Zelda: Ocarina of Time (Switch 2 remake), title ID 0400486024DEC000, .nup version 131072.

Graphics card

AMD RX 5700 (RDNA1), driver amdvlk 32.0.21045.1000

Operating system

Windows 11, Xeon E5-2667 v4, 32 GB RAM

Steps to reproduce

  1. Launch the .nup.
  2. Boot now works with Fix OOT startup abort by implementing WaitIfEqual64 #567 merged: title screen with the 3D Hyrule field, intro tapestry, then in engine scenes, all at 31 to 32 FPS, no panic.
  3. Around 200 s the picture goes black and stays black while the process keeps presenting. At 400 s and 480 s the render area was fully black, OSD showed 14 FPS, and the game never recovered.

Log / crash dump

Counted over a 600 s run (max_present=13800, process alive at the end, no crash):

Native compute shader rejected      41
Native QMD failed                   41
Draw skipped (no pipeline)          64
last 600 presents: frame 65285 us (max 138137)

Skipped draws by render target size, which points at the main scene and not an effect:

28  128x128
13  16x16
11  1440x810
 5  368x202
 3  360x202
 2  384x202
 1  720x405

The compute rejections name the missing work:

kepler_compute.cpp:586 DispatchNativeCompute: Native compute shader rejected: Native shader at 0x216cebd700, instruction 0x4330: unsupported native opcode [op 4a4 040e74a4 00003c00 0f8e020e 000fc400]
kepler_compute.cpp:586 ... instruction 0x1eb0: native matrix multiply (set EDEN_NX2_TENSOR to emulate) [op 23c 3400723c 0000000a 000008ff 041ff000]
kepler_compute.cpp:586 ... instruction 0x790:  native matrix multiply (set EDEN_NX2_TENSOR to emulate) [op 23c 1800723c 0000000c 000008ff 006fe600]
kepler_compute.cpp:586 ... instruction 0x3440: native matrix multiply (set EDEN_NX2_TENSOR to emulate) [op 23c ...]
kepler_compute.cpp:434 ProcessNativeMethod: Native compute dispatch unsupported: method=0xb0, value=0x3
kepler_compute.cpp:840 DescribeNativeResources: Native resources: cbuf0 0x210b130500 size 0x100, grid 720x1x1, block 32x1x1

EDEN_NX2_TENSOR=1 is not a workaround

Same dump and build with EDEN_NX2_TENSOR=1:

Native compute shader rejected       4   (41 without)
Native QMD failed                    7   (41 without)
Draw skipped (no pipeline)           0   (64 without)

The rejection count drops as advertised, but the frame counter stalls: max_present=8 and at 195 s the frontend asked to shut down while the emulation thread had to be force stopped. Emulating the matrix multiplies is far slower than the frame budget, so the picture never advances.

What would help

Knowing whether the black screen at 200 s is expected to be fixed by the 0x23c matrix multiply path landing, or whether the op 4a4 and the 1440x810 pipeline skips are a separate missing lowering. I can rerun any build with this dump and post counts, including a second GPU. No game files or keys here, only log lines.

Activity

  1. n0ble2 commented on Nov 5, 2026

    @n0ble2
    Image

    Hello, I built the repository myself using CMake after merging the commit with the this code: e736dfd.
    I’m using an RX 9070XT graphics card, and I’ve tested all the APIs but couldn’t get any in-game visuals.
    There’s also audio lag during cutscenes.

  2. Suhas-kc commented on Nov 5, 2026

    @Suhas-kc

    Same bug on RDNA4 (RX 9060 XT), but it ends in a hard crash instead of a black screen

    Build: nx2-aed5a8c8-e736dfde9e (same commit as the RX 9070 XT comment above), MSVC 19.44, Qt 6.8.3
    GPU: AMD Radeon RX 9060 XT, AMD proprietary driver 2.0.395, Vulkan 1.4.349
    CPU / OS: Ryzen 5 5600X, 16 GB RAM, Windows 11 25H2 (26200)
    Game: Ocarina of Time 0400486024DEC000, booted from .nup (standalone update), no firmware installed
    Notable settings: Vulkan, GPU accuracy Low, CPU accuracy Unsafe, async GPU + async shaders on, EDS2, 12 GB memory layout

    Symptom

    The game boots and plays the intro cutscene. About 4 s after the cutscene ends (~276 s after boot) the emulator crashes. It doesn't stay alive on a black screen like in the original report.

    Same signature as this issue

    The draw-skip numbers match the original report almost exactly:

    Draw skipped (no pipeline)      64
    Native compute shader rejected  16
    
    28  128x128
    13  16x16
    11  1440x810
     5  368x202
     2  384x202
     2  360x202
     1  720x405
     1  32x1
     1  1920x1080
    

    The compute rejections start ~15 s after boot and hit the same instruction offsets: op 4a4 at 0x4330, and matrix multiply op 23c at 0x1eb0, 0x790 and 0x3440.

    New: more unsupported instructions once gameplay starts (after the cutscene)

    kepler_compute.cpp:586  native global reduction mode          [op 98e ff00798e ...]
    shader_cache.cpp:165    native funnel-shift mode               [op 819 0e0e7819 ...]
    shader_cache.cpp:165    native extended integer comparison mode [op c0c ff007c0c ...]   (repeated, stage 1 and stage 5)
    kepler_compute.cpp:586  native float-to-integer conversion mode [op 305 00037305 ...]
    shader_cache.cpp:165    native texture gather mode             [op b63 ...]
    vk_pipeline_cache.cpp:1401 CreateComputePipeline: SPIR-V Instruction is not implemented
    format_lookup_table.cpp:280 assert texture format=0 srgb=false components={2 2 2 2}
    

    New: the crash sequence

    The skipped compute work looks like it never releases a semaphore. After that the GPU reads garbage state and command data:

    [2072.270] nx2_gsv.h:1935 WaitForFrame: nx2:vi2 present #12112 fence (1, 38388) not reached in 4 s (now 38383)
    [2077.015] puller.cpp:109 CanResumeAcquire: Channel 2 waits on semaphore 0x2113cd1044 (op 1, 0x2f5f, now 0x0) for 2 s
    [2078.160] surface.cpp:226 PixelFormatFromRenderTargetFormat: Unimplemented format=1048609 (0x100021), using A8B8G8R8_UNORM
    [2078.172] vulkan_memory_allocator.cpp:282 CreateImage: Image 1x1595430400x2 (1 levels, 1 layers, format 51) does not fit; using an unbacked sparse image
    [2078.172] texture_cache.h:2934 FindRenderTargetView: Render target in unbacked image 0xa0040e0200000008 ... 1x1595430400
    [2078.172] surface.cpp:99  assert Unimplemented format=5767200
    [2078.344] puller.cpp:179  assert Unimplemented engine -5FF9F1AE
    [2078.354] puller.cpp:434  Special puller engine method 1 / 3 / E..19 not implemented   (~1000 lines, log ends here)
    

    My read: the semaphore at 0x2113cd1044 should be released by one of the rejected compute dispatches (the QMD release words just before it reference 13cd10xx). Because it never gets released, channel 2 stalls. After that the render target and pushbuffer state are garbage: a 1×1.6-billion RT, then a bogus engine ID. On this driver that leads to a crash, where the original report only got a black screen.

    Full log available if useful.

  3. CloudP4bbs commented on Nov 5, 2026

    @CloudP4bbs
    ContributorAuthor

    Both reports together are a much better picture than mine alone, thanks.

    @Suhas-kc, your skipped draw histogram is identical to mine on RDNA1, down to the ordering:

    28  128x128
    13  16x16
    11  1440x810
     5  368x202
     2  384x202
     2  360x202
     1  720x405
     1  32x1
    

    Same for the rejection offsets: op 4a4 at 0x4330, matrix multiply op 23c at 0x1eb0, 0x790 and 0x3440. So this is one bug across RDNA1 and RDNA4, and the difference between "black screen forever" and "crash at 276 s" is only what the driver does after the fence stalls. Your chain explains the black screen as well: a rejected dispatch never releases the semaphore, the channel stalls, and everything drawn after that is garbage, which is why the picture stays black rather than showing a half-rendered scene.

    The second half of your log is the useful part, because it names the work that is missing once gameplay starts. Mapping each line to what already exists in the most complete OOT bring-up I know, zortos293/Lichii PR 87, which lists the lowerings it needed for this exact game:

    your line lowering that handles it
    native global reduction mode [op 98e] RED/REDUX reductions, signed included
    native funnel-shift mode [op 819] 64 bit SHF funnel shifts, uniform and register
    native extended integer comparison mode [op c0c] extended .EX integer compares
    native float-to-integer conversion mode [op 305] negated F2I (`F2I.U32.CEIL.NTZ R, -
    native texture gather mode [op b63] not in that list, so likely still open
    SPIR-V Instruction is not implemented in CreateComputePipeline also still open there

    They report 2759 of 2768 programs lowering with that branch. So the fix for the black screen is not one change, it is that list.

    Two things I am working on that touch your cases:

    1. op 23c (matrix multiply) currently only lowers when EDEN_NX2_TENSOR is set, and the software expansion is expensive enough that the driver takes minutes to compile it. There is a native lowering in heydemoura/EglantinePS5 (tools/eglantine-patches/0013-native-ampere-hmma.patch) that emits one pseudo-instruction translated straight to IR, 32 lane shuffles instead of 96. I ported it onto current nx2 and am building it now; if it works, the compute passes stop being rejected and the semaphore you traced should get released.

    2. @n0ble2, when you say no in-game visuals on the 9070 XT with any API, is the picture black from the first frame or does the intro cutscene play and then go black? The distinction matters: the cutscene is the same 64 skipped draws, but if audio also lags there it may be a second issue. If you can attach the log, the counts will tell which of the two you are hitting.

    If either of you can run the Lichii build 70, that is the fastest way to see this game with a picture, and reporting the RDNA4 result there would help them as well.

  4. ThomSimoneau commented on Nov 5, 2026

    @ThomSimoneau

    Same bug as well, with lichii version 75. no crash, just black screen. I was able to make a save file in the menu so I can check more easily for potential fix with config switches / different setups. Here are the logs:

    eden_log.txt.old.txt

    I do have some audio lag as well, but it seems to be related to the shader compiling / building.

  5. CloudP4bbs commented on Nov 5, 2026

    @CloudP4bbs
    ContributorAuthor

    One more data point from a build with the native matrix multiply lowering ported in, because it moves the target.

    With a native op 23c lowering present (from heydemoura/EglantinePS5, patch 0013, ported onto current nx2 and built clean here) and EDEN_NX2_TENSOR=1, the matrix multiply rejections disappear and what is left at boot is only this:

    Native compute shader rejected: instruction 0x4330: unsupported native opcode [op 4a4 040e74a4 00003c00 0f8e020e 000fc400]
    Native compute shader rejected: instruction 0x2830: unsupported native opcode [op 4a4 040474a4 00003c00 0f8e0208 000fe200]
    Native compute shader rejected: instruction 0x47e0: unsupported native opcode [op 4a4 040974a4 00003c00 0f8e0209 000fe200]
    Native compute shader rejected: instruction 0x3ec0: unsupported native opcode [op 4a4 040474a4 00003c00 0f8e0206 000fc600]
    
    4 rejections, 7 "Native QMD failed", 1 skipped draw, all inside the first 21 s
    

    So at boot the blocker is op 4a4, not the tensor work. 0x4a4 is uniform arithmetic (the UIMAD/uniform path), and the lowering for it lives in zortos293/Lichii together with the uniform register mirroring it depends on (uniform registers mapped onto the R216 to R231 bank, plus the guarded forms). That is a bigger port than a single case, so I would rather not pretend it is a one line fix.

    Measured effect of the native HMMA lowering on OOT right now: none visible, both builds present 8 frames in 180 s with EDEN_NX2_TENSOR=1, because the game never reaches the points where the matrix multiply matters. It may still matter later, since it cuts the expansion from 96 shuffles to 32, but it is not the boot blocker.

    Correcting the priority order I suggested earlier: op 4a4 first, then the gameplay set (98e, c0c, 819, 305, b63), then the tensor cost.

  6. CloudP4bbs commented on Nov 5, 2026

    @CloudP4bbs
    ContributorAuthor

    Progress on the boot blocker, with a correction: my first op 4a4 test was invalid because the incremental build did not pick up the header change (11 files compiled, header untouched). Forcing the two translation units that include lower_to_maxwell.h to rebuild changed the result.

    0x4a4 is uniform arithmetic, and the tree already has the whole uniform machinery (UR0 to UR21 mapped onto R216 to R237, high uniforms below R216, guarded forms). The only thing missing was the opcode itself in that list and its mapping to 0x424, exactly like 0x2a4 maps to 0x224. Two lines:

    if (opcode == 0x2a4 || opcode == 0x4a4 || opcode == 0x8a4 || ...
    opcode = opcode == 0x2a4 ? 0x224 : opcode == 0x4a4 ? 0x424 : ...

    Measured on OOT with EDEN_NX2_TENSOR=1, clean cache, 180 s:

    before   4 rejections, all "unsupported native opcode [op 4a4 ...]", 7 QMD failed, 8 presents
    after    1 rejection,   "native integer carry mode [op 290 0f067290 00000000 06 0ff5e03f ...]", 1 QMD failed, 8 presents
    

    So the 4a4 sites lower now and the chain moved to one op 290 (a UIADD3 that needs a carry out to a predicate). Frames do not appear yet, but the rejection count went from 4 to 1 and QMD failures from 7 to 1, which means the quad is almost at the point where the compute pass dispatches.

    I will send the 0x4a4 half as a PR with the two measurements above if you want it, since it is small and self contained. The carry form of 0x290 is the next item and it is not a one liner: the carry output has to reach a guest predicate and the guard forms share that path.

  7. n0ble2 commented on Nov 5, 2026

    @n0ble2

    Hello @CloudP4bbs

    I am dropping my log file below and I truly hope it helps you debug this issue.

    eden_log.txt

    • The main menu of the game functions perfectly fine.
    • The initial intro cutscene plays completely fine as well.
    • However, as soon as the game transitions into the actual in-engine gameplay scenes, the picture goes completely black.
    • Interestingly, the UI elements and subtitles still render and show up on the screen, but the main environment remains black. I also noticed that the audio starts lagging/stuttering during these transitions.

    I am also attaching a screenshot of the in-game pause menu to better illustrate the pipeline/draw behavior.

    Image

    As you can see, when entering the in-game inventory/pause menu, the entire 2D UI overlay, text strings, and icons (like the Kokiri Wallet, Heart Containers, and Button Prompts) render absolutely flawlessly.

  8. CloudP4bbs commented on Nov 5, 2026

    @CloudP4bbs
    ContributorAuthor

    For anyone working on this: the full lowering set for this game already exists in a public fork, in four commits, and it is worth reading before writing new code.

    zortos293/Lichii, in order:

    a7f2ee336  kernel: port upstream WaitIfEqual64 fix for Ocarina boot        (this is our e736dfde9e)
    3aa89d1cd  shader: compile Ocarina comparison, reduction and atomic max forms
    35c043b3e  shader: lower more Ocarina compute and high-register graphics forms
    a4cc1e680  shader: lower Ocarina CALL helpers, 64-bit shifts and high uniform forms
    

    The last one's message is a checklist of what the boot path needs, quoted: CALL.REL.NOINC has to be treated as a call because its callee returns through RET.REL.NODEC, so programs whose helpers sit after the EXIT end at the last RET instead of running into the next program; the call proof has to accept MUFU, STL, discard and RZ-destination writes; USHF/SHF.R.U64 (899/219) lower to a full 64-bit right shift clamped at 64; USEL accepts a UPn guard; UBREV, UFLO and UPOPC map every uniform register; F2I accepts -|x|.

    I downloaded their oot-bloom-3 package, which is built from a4cc1e680 and ships build.json with the commit, so the mapping is not guesswork.

    What it does on this machine (RDNA1, RX 5700, Windows), 180 s run:

    shader loading reaches 127/129 and stops, "Estimated Time 00:00"
    compute rejections: 0
    Native QMD failed:  0
    presents:           0
    

    So their build does not reject anything, it tries to compile the bloom compute and stalls on the last two programs. Compare with my earlier numbers on stock nx2, which rejects four programs and shows the stand-in. Two different failure modes on the same game and the same GPU, which suggests the remaining blocker on AMD is one or two specific compute programs rather than the lowering as a whole.

    Also from that package, and useful independently of this issue, nx2_switches.txt documents performance switches that are off by default: EDEN_NX2_SPLIT=2 (offloads GPU method and macro execution to the back thread, reported as up to +54% FPS), EDEN_NX2_FENCE_BATCH=1, EDEN_NX2_FRAMES_AHEAD=2, and EDEN_NX2_RESETFIX for the Bananza terrain path.

    My 0x4a4 change in #604 is the smallest piece of this and the measurement showed it moves the boot program from four rejections to one, so it is a step toward the same set from the other direction.

  9. CloudP4bbs commented on Nov 5, 2026

    @CloudP4bbs
    ContributorAuthor

    Measured the Lichii build-75 release (c9ebb5c, the one whose notes say the game "boots, gets through the intro and plays") on the same machine as my numbers above: RDNA1, RX 5700, Windows 11, Vulkan, EDEN_NX2_SPLIT=2 and EDEN_NX2_FENCE_BATCH=1.

    Title screen, no input:

    presents 4800 in 180 s, ~32 FPS, frame 31.23 ms
    compute rejections 0, "Native QMD failed" 0, skipped draws 0
    the title, the logo and the menu render correctly
    

    After pressing the mapped A button to start a new game, 540 s run:

    max present 16800, sustained 31 FPS, frame 31.25 ms
    every screenshot from 180 s to 480 s is a black frame
    no rejection, no skipped draw, no error line in the log
    

    So on this GPU the build gets past everything my earlier numbers were blocked on, the 2D path renders perfectly, and the 3D scene comes out black with the frame loop running at full rate. That is the opposite shape from stock nx2, where nothing presents at all, and it narrows the black screen to the 3D path rather than to the pipeline being rejected.

    Two things I ruled out here: raising gpu_accuracy from Normal to High changes nothing, the frame is still black; and the black is not a captured-window artifact, because the same capture shows the window chrome and status bar with 32 FPS while the content area is black.

    Their branch fix/oot-fog (82b95a65d) has commits after build-75 that look aimed exactly at this: "shader: prove guarded per-tap offsets and finish Ocarina compute lowering", "shader: lower F16 per-tap gathers with proven literal offsets", "shader: lower native 2D depth comparison gathers" and "video_core: probe alpha test, alpha-to-coverage and discard per draw". I am building that branch now to see whether the black scene is fixed there, and will post the numbers.

    If anyone reading this has an NVIDIA card and can run the same 540 s test with a screenshot after starting the game, that comparison settles whether the black 3D path is AMD specific or affects everyone.

  10. CloudP4bbs commented on Nov 5, 2026

    @CloudP4bbs
    ContributorAuthor

    Found a reproducible trap that explains a lot of the "zero presents" reports in this thread, including mine.

    Test sequence on the same machine and the same game:

    clean shader cache, Lichii build-75 (clang)          4800 presents in 180 s, then 9000 more
    run a locally built binary (MSVC) on the same game   8 presents, then the log stops
    go back to build-75 without touching the cache       8 presents, stuck at "Loading Shaders 26/27"
    delete cache/shader/0400486024dec000, build-75       9000 presents again
    

    So the local build does not merely fail on its own: it writes pipeline cache entries that the other build then loads, and that build stalls while building the pipelines that come back from disk. Presence of a shared cache/shader/<title id>/vulkan.bin across different binaries is enough to produce a hard stall, with no error, no rejection and no skipped draw in the log.

    That matches what I reported earlier with the 9.4 MB file: the entries read back fine as far as the loader is concerned, the precompile finishes, and then nothing is presented. It is not a corrupt tail, it is an entry that came from a different binary.

    Practical consequence for testing: when comparing two builds of this emulator on the same title, give each one its own user data directory, or delete the title's shader cache between runs. Otherwise the second build inherits the first one's pipelines and the measurement is meaningless. Half of my own earlier numbers in this issue were taken without doing that.

    Two things still open from my side, both on AMD:

    1. The 3D scene stays black even with a clean cache, 31 FPS sustained, 0 rejections, 0 skipped draws. The 2D title and menus render correctly at the same frame time, so the frame submission path is fine.
    2. EDEN_NX2_FRAME_DUMP with _AT and _SAMPLED set did not produce any file for me. If it needs a different form, or if it only dumps on presentation, a pointer would help, since dumping one in-game frame is the fastest way to see whether the 3D draws are arriving at all.
  11. A-Man-With-A-Plan-dev commented on Nov 5, 2026

    @A-Man-With-A-Plan-dev

    Opened #614 with the fix for the black 3D scene in gameplay. It's a port of @kraibse's scratch/oot-shader-lab (11 commits, cherry-picked with -x, authorship kept), so credit goes to kraibse, @zortos293 (Lichii) and Franseven.

    Cause on stock nx2: in gameplay the network's final pass is rejected for a TLD4 F16 per-tap-offset gather, not for matrix multiply, so the upscale stand-in never ran, and where it did run it picked the wrong image pairs from cbuf0+0x80..0x11c. dbf3417099 plus the gather lowerings fix both.

    Tested on RTX 5090 / Windows 11 / Vulkan: Kokiri Forest now renders from a save. Before it was black with only the HUD.

    Before / After:

    Image Image

    @kraibse, if you'd rather send this from your own branch, I'm happy to close #614.

    Tip for eden-cli testers: check backend= in sdl2-config.ini. Mine was 2 (Null), so nothing rendered.

    (AI-assisted: used to diagnose, port and run the headless captures.)

  12. IORITHEGOD-create commented on Nov 5, 2026

    @IORITHEGOD-create

    Hello. I would like to provide some information regarding a crash that occurs on my system with Ocarina of Time.

    I have a Radeon RX 6700 XT, Ryzen 7 5700G, and Windows 11. On build nx2-aed5a8c8-e736dfde9e, the menu and opening cutscenes appear normally. Afterwards, during the Deku Tree dialogue, the screen goes black while the audio keeps playing, and the emulator eventually crashes.

    I don't know how to code myself, but I understand the basic concepts. I used ChatGPT and Antigravity to help me gather and analyze the logs and dumps, and to generate a standalone reproduction program. I want to be transparent about this AI assistance.

    From the tests conducted on my PC:

    The standalone program triggers the exact same crash signature as Eglantine: 0xC0000005 in amdvlk64.dll+0xAFF2E7, attempting to read 0x28 with R15=0.

    Using the same configuration and the same vertex shader, two control fragment shaders successfully create the pipeline.

    The candidate fragment shader causes the crash during vkCreateGraphicsPipelines.

    With the Khronos validation layer and a verified persistent message receiver, no Vulkan violations were recorded prior to the crash.

    The file version of amdvlk64.dll is 32.0.21045.16010.

    I have prepared an approximately 161 KB ZIP file containing the reproducer code, captured shaders, instructions, and logs. We have not yet identified the exact root cause.

    Eglantine_AMD_reproducer_v3_1_reviewed.zip

  13. FabianZettl commented on Nov 5, 2026

    @FabianZettl

    Linux / AMD data point for #614 (the PR's test matrix only has Windows / NVIDIA).

    Setup: CachyOS, Ryzen 7 3700X, Radeon RX 7800 XT (RADV, Mesa), Docked, 2560x1440. Built nx2 at e736dfde plus #614 (b536a97). Ocarina of Time 0400486024DEC000, 1.1.1, .nup, loaded from a save in Kokiri Forest.

    #614 on its own

    • The 3D world renders in gameplay; before it was black with only the HUD.
    • Log: 0 graphics programs rejected, 0 "Draw skipped (no pipeline)". The only rejected programs are the 11 HMMA compute programs of the DLSS network, so the upscale stand-in runs.
    • EDEN_NX2_TENSOR=1 (real network) and the stand-in give nearly the same image here, so the stand-in is not what causes the brightness below.
    • Frame time in gameplay was 37-55 ms (looks like slow motion).

    Added from Lichii (all merged there)

    Still wrong (agrees with Lichii#101 and the notes in Lichii#102)

    • The image is too bright, with heavy bloom. Skipping only the upsample vertex shader f2b14c43ca0e4300 barely changes it (mean centre brightness 79 % to 77 %, same scene, taken when the HUD first appears).
    • Skipping all 12 compute programs that contain RED (a test, not a fix): the HUD never appeared within 190 s, so they are needed.
    • Frame generation (FSR3) on top of a 20-30 fps base adds ghosting and looks like a transparent character, so turn it off for this game.
    • Settings trap: use_docked_mode defaults to Handheld (ENUM(ConsoleMode, Handheld, Docked)), so a default install runs this game in handheld mode.

    Lichii#102 describes the likely cause of the brightness: texture handles chosen per pixel at run time (zero-format TICs, trees without leaves). I have not looked into that part.

    Analysis and text by Claude Code (AI). I ran the builds and read the logs myself on the machine above.

  14. 29 remaining items

  15. matheusdotto commented on Nov 6, 2026

    @matheusdotto

    @IORITHEGOD-create
    Sorry, the attachments didn’t come through. Here they are in one zip: the four patches (01 is the fix), the trace, the frame-dump entries, and the SPIR-V for e40561a7a0f7a0b3 before (old reorder) and after (guard). Both SPIR-V files are 4800 bytes and differ in 209 of them. They have the same number of labels, branches and demotes and no OpPhi, so the change looks like a reordering of the same blocks. I didn’t run spirv-val myself.

    matheusdotto-demote-fix-attachments.zip

  16. brandonbunnelle commented on Nov 6, 2026

    @brandonbunnelle

    Data points from a Linux perf day on OoT (Ryzen 7 9800X3D / RTX 3080, Accurate mode, 1x, FSR replacement off/on both tested):

    GPU thread is latency-bound in the heavy vistas, not throughput-bound. At ~30 FPS the GPU thread sits at ≤60% and the six emulated cores at ~30% each. The frame time is the serial chain game CPU → command list → GPU thread → host GPU → fence → syncpoint → game CPU, with a fence signaled per compute dispatch. Local hot spots from perf (no app profiler): memory-manager page walks ~15% (MaxContinuousRangeUncached, GpuToCpuAddress, GetPointer, all from per-draw vertex/SSBO binding), GPU-thread ↔ fencing-thread lock overhead ~8%, method dispatch ~10%, macro execution ~5% (already JIT'd).

    EDEN_NX2_GPU_PROFILE=1 costs 27% of the GPU thread on Linux — WallClock::GetTimeNS is the #1 perf symbol (zone scopes run ~150k/s). Removing it from a vista run took the frame 40 ms → 33 ms alone. Anyone benchmarking with it on is measuring the profiler.

    Preflushable readback storm, quantified + a negative result. Forest scenes copy marked ranges back at 1.9 GiB/s in 135k copies/s (a fence per compute dispatch × marked ranges) against ~571 real guest reads/s (single pages). Four throttle variants each broke the image path differently — the tonemap/gamma reader's freshness contract is tighter than one frame. The eager scheme is FPS-neutral here (the fencing thread is ~5% busy), so correctness wins. Code + full story in #686.

    Macro flood characterized (EDEN_NX2_MME_RECORD): 893k calls/s, avg 2.9 param words, 15 calls/draw, 2,360 draws/frame in a vista. Memoization is a dead end for this title — the top macro (22% of calls) has a genuinely dynamic parameter, weighted LRU-4 hit ~35%.

    Frame generation does not engage on this title: present rate unchanged, zero FG log lines. With FG on, the game also starts calling nx2:IGraphicsScaleController cmd 1050 (unimplemented — only cmd 10 exists), nx2:gsv cmd 903 and nx2:vi2 cmd 201; all three also appear once at boot with FG off.

    A residual 2-state gamma flicker survives with: all readback-throttle variants off, the macro stack path off, the FSR replacement off, and async shaders off. Given the scale-controller probing above, unimplemented nx2: graphics-scale service commands are a plausible parent.

    Measurements and env-gated code: #686 (base fix/oot-blackscreen).

  17. CloudP4bbs commented on Nov 6, 2026

    @CloudP4bbs
    ContributorAuthor

    Two measurements from this morning that shorten the queue for anyone else on this title.

    1. The gather rejection after the intro was one shader, and it is fixed in #685

    The pixel shader at 0x1148ed8200 was rejected at 0x1650 and its draws skipped. Accepting the encoding with insn.Bits(77, 3) == 2 gives the title and the intro at 60 FPS with no skipped draw. I also built the same base with the whole insn.Bits(77, 3) condition removed and the image is identical, so the field is not doing anything the plain gather4 lowering cannot express.

    2. What is left in the first gameplay scene, decoded

    The next blocker is native funnel-shift mode at 0x790 in the graphics shader 0x115c2b3c00:

    [op 819 0e0e7819 00000015 00001211 020fe200]
    
    dest(16,8)      = 14        low(24,8)   = 14
    high(64,8)      = 17        shift(w1)   = 21
    bits(73,2)      = 1         bit75       = 0
    bit76           = 1         bit80       = 0
    

    Against the case at lower_to_maxwell.h, two conditions fail: insn.Bits(73, 2) != 3 && !is_signed and !insn.Bits(80, 1). The bit76 branch that exists for the right shift requires low == 255 and does not apply, because low is 14 here.

    I am not touching it. The shift amount feeds the result directly, so a wrong guess does not show up as a wrong colour, it shows up as geometry in the wrong place a scene later, and I have no way to tell from a screenshot. If someone knows what bits(73,2) and bit80 select on Ampere's SHF, the lowering is one emit and I can have a build measured in twenty minutes.

    For reference, the scene also issues 46 native shader dispatch required compute dispatches (native_qmd.h:96, shared memory). The QMD still completes, so those do not block the frame, but the results the scene expects from them are not there.

  18. CloudP4bbs commented on Nov 6, 2026

    @CloudP4bbs
    ContributorAuthor

    Result of the funnel-shift experiment, so nobody repeats it blind.

    I added the missing case: insn.Bits(73, 2) == 1 with bit76 set and both words real, as a right funnel of (high:low), mirroring the left funnel already there but with the 0x3828 opcode:

    if (insn.Bits(73, 2) == 1 && insn.Bits(76, 1) && !insn.Bits(75, 1) &&
        insn.words[1] <= 32 && insn.Bits(24, 8) != 255 && insn.Bits(64, 8) != 255) {
        emit(base(0x3828000000000000ULL) | (u64{insn.Bits(24, 8)} << 8) |
             (u64{insn.Bits(64, 8)} << 39) | (u64{insn.words[1]} << 20));
        break;
    }

    What happened:

    • native funnel-shift mode no longer appears for 0x115c2b3c00, so the encoding is accepted;
    • no crash, no device loss, 12,000 frames, 26 draws still skipped;
    • the first gameplay scene is still black with the HUD drawn over it.

    So the funnel shift was not what removes those draws. I cannot tell whether the emit is correct, because the scene never gets far enough to show whether the value is right, and I am not sending it upstream on that basis. It is on a local branch with that note.

    What is left in that scene: native texture gather mode twice (other encodings than the 2 in #685), native matrix multiply nine times, native global reduction mode six, one warp sum and one opcode. The HUD renders, so this is purely the 3D pipeline.

    One thing that may help whoever picks this up: my 0x1148c8b800 cast of the map was wrong earlier. The skipped draws are 0x1148c8b800, 0x1148c9a600, 0x115b570d00, 0x115b59a800, and the rejected programs in the same session are 0x11485bae00, 0x11485d5300, 0x1148c6e800, 0x1148c6fe00, which are not the same addresses. I had been assuming the rejected program and the skipped draw were the same shader because it was true for the gather; here they are not, so the mapping needs the log lines next to each other rather than my inference.

  19. IORITHEGOD-create commented on Nov 6, 2026

    @IORITHEGOD-create

    @matheusdotto Thank you for reattaching everything in one ZIP. The four patches, trace excerpt, frame records and before/after SPIR-V are received. I checked the 4800-byte pair and the 209-byte difference; both have no OpPhi. We will keep the CFG/SSA explanation open until the relevant validation and case comparison are done. Your files now let us examine the guard directly and compare its remaining coverage against #127, instead of guessing what the missing patch contained. There is no need to attach them again.

    @CloudP4bbs Thank you for answering the map's questions and documenting both the successful checkpoints and the experiments that did not recover gameplay. The distinction between TFB, gather rejection, the local funnel-shift experiment and the still-skipped draws is especially useful. Your corrected program/draw mapping prevents us from carrying the earlier association into another test. I have linked #673 and #685 and kept the HMMA/funnel results with their stated limits.

    The central AMD map is updated, including the new RX 6650 XT and RX 6750 XT results. The requested Jon package is now delivered and checked. We will first compare that identified build on the RX 6700 XT, recording the driver crash, image and session separately. The second-card TFB validation remains a separate task; we have not established that our PC reaches that particular stall.

    Thank you for making both the changes and the limits of the evidence available.

    AI assistance: ChatGPT helped inspect the attachments, compare dependencies and draft this reply; Antigravity assists our local experiments.

  20. kanelakis commented on Nov 6, 2026

    @kanelakis

    eden_log.txt

    Hello, I’m also getting a black screen; I’ve attached the log.
    I have an RTX 3060 12GB, an Intel Core i9-9900K, and 32GB of RAM.

  21. CloudP4bbs commented on Nov 7, 2026

    @CloudP4bbs
    ContributorAuthor

    A comparison that corrects something I had assumed, and that may point at the real cause of the black scene.

    I ran Lichii build-93 on the same card (RX 5700, Windows 11, AMD proprietary 2.0.353) and it renders OoT's gameplay: Link, Navi, the Deku Tree interior and Link's house, correct textures and shadows, 23-24 FPS.

    The draws it skips are the same ones Eglantine skips

    Lichii build-93    Draw skipped (no pipeline): vs=0x115b4b3c00 ps=...
                       29 skipped draws over 10,800 frames, world renders
    Eglantine nx2      Draw skipped (no pipeline): vs=0x115b4b3c00 ps=...
                       26-27 skipped draws, world black with HUD over it
    

    Same vertex program, same rejection on both sides. So on this title the skipped draws are not what makes the 3D scene disappear, which is what I had been assuming for the last several hours of my own notes. They are probably an effect pass, and the world is drawn by something else.

    What that leaves

    Two candidates, both in Lichii and neither in the Eglantine base I can build here:

    • Lichii PR qt: ask about the recommended MKW settings only when booting MKW #354, "Fix Ocarina of Time's green tint on AMD: bind light-table shadow maps through descriptor arrays". Clustered lighting loops over per-pixel lights and samples each light's shadow map with depth comparison, reading handles from a light table. If the Eglantine side binds the wrong words there, the lighting result is garbage rather than black, so this is a weaker match for a fully black scene.
    • Lichii PR MKW 1.8.0 on a Ryzen 7 170 laptop: GPUBack-bound profile data, and a frame-gen pacer fix (patch included) #395, "vulkan: rebuild native compute pipelines whose point...", which touches native compute pipelines. Ocarina issues 46 native shader dispatch required compute dispatches per frame in the first scene on the Eglantine side. If those produce the textures the scene samples, a black world with a working HUD is exactly what you would see.

    I have no way to test either from the Eglantine side here, and I am not going to guess which it is. What I can say with a measurement is that the skipped draws are a red herring, and that build-93 on the same hardware renders the scene Eglantine does not.

  22. CloudP4bbs commented on Nov 7, 2026

    @CloudP4bbs
    ContributorAuthor

    Your log names the cause, and it is not the same one as mine.

    Build in the log: daily-20261106-0ca2032bff. Rejections in it, counted:

    65  native extended integer comparison mode
    10  native texture gather mode
     9  native matrix multiply
     7  native program uses lowering scratch register
     6  native global reduction mode
     1  unsupported native opcode
    
    64 draws skipped (no pipeline)
    46 native shader dispatch required
    2400 frames, then the black scene you describe
    

    The 65 extended integer comparisons are the bulk of it. That lowering is the one that landed with the predicate-combined ISETP work (91d525da3e on the nx2 branch), and a daily- build from the same day may predate it or be cut from a different branch. With those shaders rejected, the draws that use them are skipped, and on this title that is enough to leave a black scene with the HUD drawn over it.

    If you can, try the newest nx2 artifact rather than the daily, and post the same grep from its log:

    grep -o "instruction 0x[0-9a-f]*: [a-z0-9 -]*" eden_log.txt | sed 's/.*: //' | sort | uniq -c | sort -rn
    

    If the extended integer comparison line is gone and something else has taken its place, that tells whoever is fixing this which lowering to work on next. On my card the equivalent line is a tessellation program at stage 3, so the two cards are failing on different shaders, which is why one fix never seems to clear the screen for everybody.

  23. CloudP4bbs commented on Nov 7, 2026

    @CloudP4bbs
    ContributorAuthor

    I think this narrows the black scene to one mechanism, and it is not the skipped draws.

    Ran both emulators on the same card, same driver, same game file, back to back, counting the same log lines:

                            Lichii build-93    Eglantine nx2 (built from efd41e36)
    frames                  4,200              10,800
    Draw skipped (no pipeline)  26             26-27
    shader rejected         0                  30 (8 tessellation at stage 3, rest compute)
    native shader dispatch required  0         46
    world                   renders            black, HUD drawn over it
    

    The zero is the interesting number. Both builds skip the same 26 draws and both present frames at a similar rate, so the skipped draws are not what differs. What differs is that Lichii dispatches every compute program and Eglantine refuses 46 of them per frame with native shader dispatch required, which comes from native_qmd.h:96 when a QMD carries shared memory and no native program can run it.

    Same 46 show up in the RTX 3060 log posted above, on a completely different driver, so it is not an AMD quirk either.

    What I would look at

    The scene still issues its draws, they reach the rasterizer, they just have nothing in the textures the compute would have written. That matches Lichii PR #395, "rebuild native compute pipelines whose pointer slot was null at translation": if the pipeline is cached from a translation where a constant-buffer slot was not yet a storage buffer, it stays wrong, and every dispatch built from it fails the same way forever. On this title the foliage culling compute is named there, and the first scene is full of instanced vegetation.

    I cannot test that from the Eglantine side because the build I can produce from the current base hangs at Loading Shaders 13 / 14 and writes no log, and the older base I can run is the one in the table above. But the comparison is reproducible: run build-93, count native shader dispatch required in its log, and the number is zero.

  24. matheusdotto commented on Nov 7, 2026

    @matheusdotto

    @CloudP4bbs and @IORITHEGOD-create

    I’ve been working on a native Windows port of the Switch 2 Ocarina of Time (0400486024DEC000, v131072). It works like the static-recompilation ports some of you know from Switch 1 titles. It’s still very much in progress, so this is a progress update, not a release.

    The idea

    Instead of emulating the CPU at runtime (a JIT translating ARM instructions while you play), the game’s code is translated once, ahead of time, from AArch64 into C. That C is compiled into a native x86-64 DLL, so the game logic runs directly on your PC’s CPU, with no JIT and no CPU emulation.

    The Switch 2 system layer (services, files, audio, input) and the graphics translation (NVN2 → Vulkan) come from Lichii, which already handles them well, including several AMD fixes. That’s the same split the Switch 1 PC ports use: native CPU code, with a translation layer for the GPU.

    What’s done

    Recompiler (a fork of MZ Labs’ SwitchRecomp, extended for Switch 2):
    reads the ZBIC-compressed executables;
    supports the ARMv8.1+/8.3 instructions the game uses: pointer authentication, LSE atomics, CAS/CASP, LDAPR and MTE tag stores.
    Result: all four modules (main, sdk, subsdk0, rtld), about 17.6 million instructions, translate with 0 unknown instructions and compile into one native DLL of about 480 MB.
    Built-in patches: Lichii’s Max Resolution and Dynamic FPS patches are applied at translation time, so the native code includes them.
    Testing: every new instruction has tests against reference semantics; there are 70+ tests so far.
    What’s in progress

    New AOT CPU backend inside a Lichii build-93 fork. It loads the translated DLL instead of running Dynarmic. It handles system calls and thread switching synchronously on each guest thread, preemption checkpoints so busy loops can’t hang a core, and GPU-cache page-protection faults.
    Where it stands:
    The runtime itself boots to the title screen (on Dynarmic, as a baseline).
    With the translated code, the game is running for several seconds and making real system calls.
    We’re now working through the issues this exposes one by one. The latest was the game’s own fiber switching (nn::os::SwitchToFiber).
    Next goal: reaching the title screen entirely on translated code.
    What comes after

    Playing from Link’s house to Kokiri Forest with saves, at least as fast as Lichii.
    A standalone executable that boots straight into the game (no emulator UI), plus a setup that builds the port from your own dump.
    Polish: settings, controls and shader precompilation.
    Legal note: this will only ever work with a game you dumped from your own console. The project contains no game code, assets, keys or firmware. Everyone generates the native code from their own dump, and that output must not be shared.

    Credits: MZ Labs for SwitchRecomp (Apache-2.0), the Lichii/Eden/Eglantine developers and community (GPL-3.0), and kinnay’s zbic. Many of the graphics fixes this relies on came out of the community’s work in the Eglantine issue tracker.

    More updates when it reaches the title screen on native code.

  25. guillaumespitz commented on Nov 7, 2026

    @guillaumespitz

    Apple Silicon data point: M2 Max, macOS 15.7.3, MoltenVK 1.4.1, Eglantine nightly nx2-experimental-efb9fb18, Ocarina of Time 1.1.1 (0400486024DEC000). Two runs on the same nightly ended in a GPU-side SIGABRT:

    1. New game: at the end of the opening cinematic, the last critical line was vk_master_semaphore.cpp:112:Wait: Waiting for GPU tick 26881 failed: VK_ERROR_DEVICE_LOST. The crashing thread was GPUBack, in Vulkan::MasterSemaphore::Wait via BufferCache::DownloadBufferMemory.
    2. Continue: with an imported Lost Woods in-game save (slot 0) in a separate test profile, I clicked Continue and the emulator exited before I could control Link. At ~78 s the renderer logged vulkan_device.cpp:983:ReportLoss: Device loss occurred!. The crashing thread was GPU, in Vulkan::MasterSemaphore::Wait via BufferCache::Nx2ReadListCopy / RasterizerVulkan::ReadGpuWrittenCommandList. The log confirms the save filesystem opened, not that slot 0 finished loading.

    So starting from Continue did not avoid the crash on this Mac. Both failures involve device loss, but these traces do not establish that the same shader or command caused both.

  26. IORITHEGOD-create commented on Nov 7, 2026

    @IORITHEGOD-create

    @matheusdotto Huge props for this, what you've achieved so far is genuinely insane. Getting all 17.6 million instructions across four modules to translate with zero unknown opcodes—especially with ARMv8.1/8.3 instructions in the mix—and already seeing real syscalls on an AOT backend is massive progress. Massive respect for taking this on.

    I saw you mentioned AMD fixes in Lichii, so if you ever need someone to test builds, pull logs, or reproduce issues on an all-AMD rig, I’d be more than happy to help out:

    • CPU: AMD Ryzen 7 5700G
    • GPU: AMD Radeon RX 6700 XT
    • RAM: 32 GB DDR4
    • OS: Windows 11

    Just to be upfront: I’m not a programmer and I don't write code from scratch, but I understand the technical concepts and terminology, and I’m very familiar with how emulators and recomp projects work under the hood. On my end, I also work with Antigravity Pro (for handling test runs, compilation, and light code tweaks) combined with ChatGPT Pro (for auditing, planning, and digging through issues/logs), and I know how to chain them together to troubleshoot effectively without wasting your time.

    Quick heads-up on my schedule: I’ll be completely offline tomorrow, but starting this Sunday and throughout the entire week, I’ll have plenty of time available if you need someone to test commits or check AMD-specific behavior.
    No pressure at all, just wanted to put the hardware and time on the table if it helps the project. Keep up the awesome work!

  27. CloudP4bbs commented on Nov 7, 2026

    @CloudP4bbs
    ContributorAuthor

    Tried the newest nightly artifact instead of building here, and it does not reach a frame on this card.

    artifact   eglantine-windows-x86_64-pgo-baa6d295ac (built 2026-11-07 12:05Z)
    title      0400486024DEC000, v131072
    machine    RX 5700 (RDNA1), Windows 11, AMD 2.0.353, 32 GB
    

    What it shows, from the window itself:

    Loading Shaders 27 / 28
    Estimated Time 00:22
    Building: 28 shader(s)  Scale: 1x  Game: 0 FPS  Frame: nan ms
    GPU accuracy in the status bar: FAST
    

    It never leaves that screen. The estimate expired more than a minute before the second screenshot, and the two captures are the same frame (identical file size, 27573 bytes), so nothing is progressing. No log file is written in this configuration, so there is nothing to grep for the rejections.

    For comparison, on the same machine and title, Lichii build-93 renders normally:

    Kokiri Forest, 15 minutes, 13,200 frames, 0.5 s worst frame
    interior 22-24 FPS, open area 14-15 FPS
    26 draws skipped, 0 compute rejections
    

    So the remaining gap on this title is not just the black scene: the current nx2 does not get past shader loading at all here.

    Two smaller notes that may save someone time:

    1. Building nx2-experimental locally at efd41e3619 with MSVC 19.44 and Qt 6.8.3 produces a binary that faults on boot (0xC0000005) for both Ocarina and Bananza, before any log file is created, while the same tree's GUI starts. The prebuilt CI artifact does not fault, so this is a local build problem, not something in the tree. If anyone else builds on Windows, be aware.
    2. I applied shader: keep depth-compare texture descriptors float on integer formats #721 locally to test it (depth descriptors forced to float). It compiles clean, but I cannot report a result, because the binary from that tree never gets far enough to render. It still looks correct to me on inspection: taking the sampled type from a garbage TIC entry can only produce an image type that disagrees with OpImageSampleDref.
  28. matheusdotto commented on Nov 7, 2026

    @matheusdotto

    @IORITHEGOD-create Hey, thanks a lot for the kind words and for offering to help! I really appreciate it!

    I’d definitely be happy to have your help throughout the project, especially with testing builds and investigating AMD-specific issues. I believe a few other developers are also working on similar things, so it’s great to see more people getting involved!

    I’ll be away for the weekend, and I imagine there might already be some new progress by the time I’m back.

    I also noticed that the DK PC port was released recently. Maybe there’s something useful in that project that could help us figure out some instructions or improve the recompilation process.

    Thanks again for the support and for offering your time and hardware. Every bit of help is appreciated! Let’s see how things progress! 😄

  29. guillaumespitz commented on Nov 8, 2026

    @guillaumespitz

    Follow-up on Apple Silicon: the official daily-20261107 build (216d3e2) reproduces the same crash after Continue as nightly efb9fb18. Apple M2 Max, macOS 15.7.3, Zelda 1.1.1, fresh shader cache, copy of a Lost Woods save. The title menu loads; selecting Continue aborts. Final errors:

    [73.198946] vk_master_semaphore.cpp:112:Wait: Waiting for GPU tick 6354 failed: VK_ERROR_DEVICE_LOST
    [73.198960] vk_master_semaphore.cpp:112:Wait: Waiting for GPU tick 6355 failed: VK_ERROR_DEVICE_LOST
    

    macOS reports SIGABRT on GPUFencingThread. No files attached.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions