Fix the black screen on Intel iGPUs after loading a save #1960
Closed
thomas-montano wants to merge 2 commits from
fix/intel-black-screen-rgb9e5 into main
pull from: fix/intel-black-screen-rgb9e5
merge into: MagicBeanDev:main
MagicBeanDev:main
MagicBeanDev:github/pr/2893
MagicBeanDev:github/pr/2890
MagicBeanDev:github/pr/2887
MagicBeanDev:github/pr/2878
MagicBeanDev:github/pr/2875
MagicBeanDev:github/pr/2874
MagicBeanDev:github/pr/2873
MagicBeanDev:github/pr/2871
MagicBeanDev:github/pr/2756
MagicBeanDev:github/pr/2897
MagicBeanDev:github/pr/2896
MagicBeanDev:github/pr/2718
MagicBeanDev:github/pr/2842
MagicBeanDev:github/pr/2691
MagicBeanDev:github/pr/2895
MagicBeanDev:github/pr/2743
MagicBeanDev:github/pr/2765
MagicBeanDev:github/pr/2708
MagicBeanDev:github/pr/2732
MagicBeanDev:github/pr/2755
MagicBeanDev:github/pr/2817
MagicBeanDev:github/pr/2876
MagicBeanDev:release-please--branches--main
MagicBeanDev:release-please--branches--main--release-notes
MagicBeanDev:github/pr/2778
MagicBeanDev:github/pr/2888
MagicBeanDev:github/pr/2866
MagicBeanDev:github/pr/2877
MagicBeanDev:github/pr/2800
MagicBeanDev:github/pr/2829
MagicBeanDev:github/pr/2850
MagicBeanDev:github/pr/2889
MagicBeanDev:github/pr/2882
MagicBeanDev:github/pr/2860
MagicBeanDev:github/pr/2849
MagicBeanDev:github/pr/2886
MagicBeanDev:github/pr/2794
MagicBeanDev:github/pr/2840
MagicBeanDev:github/pr/2830
MagicBeanDev:github/pr/2834
MagicBeanDev:github/pr/2719
MagicBeanDev:github/pr/2742
MagicBeanDev:github/pr/2741
MagicBeanDev:github/pr/2820
MagicBeanDev:github/pr/2771
MagicBeanDev:github/pr/2859
MagicBeanDev:github/pr/2858
MagicBeanDev:github/pr/2823
MagicBeanDev:github/pr/2757
MagicBeanDev:github/pr/2769
MagicBeanDev:github/pr/2844
MagicBeanDev:github/pr/2843
MagicBeanDev:github/pr/2673
MagicBeanDev:github/pr/2855
MagicBeanDev:github/pr/2739
MagicBeanDev:github/pr/2807
MagicBeanDev:github/pr/2851
MagicBeanDev:github/pr/2789
MagicBeanDev:github/pr/2814
MagicBeanDev:github/pr/2818
MagicBeanDev:github/pr/2774
MagicBeanDev:github/pr/2772
MagicBeanDev:github/pr/2750
MagicBeanDev:github/pr/2786
MagicBeanDev:github/pr/2785
MagicBeanDev:github/pr/2782
MagicBeanDev:github/pr/2779
MagicBeanDev:github/pr/2775
MagicBeanDev:github/pr/2706
MagicBeanDev:github/pr/2766
MagicBeanDev:github/pr/2747
MagicBeanDev:github/pr/2759
MagicBeanDev:github/pr/2745
MagicBeanDev:github/pr/2740
MagicBeanDev:github/pr/2733
MagicBeanDev:github/pr/2725
MagicBeanDev:github/pr/2727
MagicBeanDev:github/pr/2728
MagicBeanDev:github/pr/2729
MagicBeanDev:github/pr/2721
MagicBeanDev:github/pr/2722
MagicBeanDev:github/pr/2715
MagicBeanDev:github/pr/2714
MagicBeanDev:github/pr/2707
MagicBeanDev:github/pr/2703
MagicBeanDev:github/pr/2705
MagicBeanDev:github/pr/2697
MagicBeanDev:github/pr/2679
MagicBeanDev:github/pr/2676
MagicBeanDev:github/pr/2669
MagicBeanDev:docs/what-hookshot-connects-to
MagicBeanDev:fix/hdr-encode-test
MagicBeanDev:fix/main-tests
MagicBeanDev:fix/play-cache-files
MagicBeanDev:perf/game-barrier-order
MagicBeanDev:feat/heap-lazy
MagicBeanDev:feat/texture-detail
MagicBeanDev:perf/astc-opaque-bc1
MagicBeanDev:fix/fs-dir-lock
MagicBeanDev:fix/framegen-native-kept
MagicBeanDev:fix/update-no-downgrade
MagicBeanDev:port/k10-gcn-f16-mirrors
MagicBeanDev:fix/framegen-mult-cap
MagicBeanDev:chore/release-as-2.1.1
MagicBeanDev:perf/pcache-load-switch
MagicBeanDev:fix/prepare-progress-log
MagicBeanDev:fix/update-closes-stale-game
MagicBeanDev:fix/hdr-scaled-sampled
MagicBeanDev:perf/first-start-preset
MagicBeanDev:perf/zero-upload
MagicBeanDev:fix/vcore-escape-2s
MagicBeanDev:test/fake-gh-atomic
MagicBeanDev:perf/batch-idle-flush
MagicBeanDev:test/finish-stub-a
MagicBeanDev:chore/record-2.1.0
MagicBeanDev:fix/main-red-tests
MagicBeanDev:fix/test-display-startup-driver-cache
MagicBeanDev:feat/mesh-shader-mode
MagicBeanDev:fix/menu-probes-at-startup
MagicBeanDev:fix/fps-counter-classic
MagicBeanDev:fix/test-log-batch-flake
MagicBeanDev:fix/narrow-screen-hud
MagicBeanDev:ci/prereleases
MagicBeanDev:release/v2.0.15
MagicBeanDev:hotfix/v2.0.15
MagicBeanDev:fix/present-ahead-replay
MagicBeanDev:release/v2.0.13
MagicBeanDev:fix/bracket-paths-2013
MagicBeanDev:fix/hdr-overlays-2013
MagicBeanDev:fix/fps-counter-scale-2013
MagicBeanDev:fix/stick-seen-at-rest
MagicBeanDev:hotfix/menu-fits-screen
MagicBeanDev:fix/f1-always-opens-menu
MagicBeanDev:fix/ini-keep-lines
MagicBeanDev:claude/cranky-pike-7cf247
MagicBeanDev:perf/texture-answer-flat
MagicBeanDev:fix/stamp-test-modules
MagicBeanDev:fix/appimage-fonts
MagicBeanDev:fix/display-awake
MagicBeanDev:release/v2.0.12
MagicBeanDev:fix/discord-windows
MagicBeanDev:rc/v2.0.12-tests
MagicBeanDev:fix/dlss-keep-feature
MagicBeanDev:rc/v2.0.12
MagicBeanDev:button-icons
No reviewers
Labels
Clear labels
accessibility
Barrier affecting people with disabilities
autorelease: pending
autorelease: tagged
bug
Something isn't working
dependencies
Pull requests that update a dependency file
documentation
Improvements or additions to documentation
duplicate
This issue or pull request already exists
enhancement
New feature or request
github_actions
Pull requests that update GitHub Actions code
good first issue
Good for newcomers
help wanted
Extra attention is needed
invalid
This doesn't seem right
question
Further information is requested
testing wanted
wontfix
This will not be worked on
No labels
accessibility
autorelease: pending
autorelease: tagged
bug
dependencies
documentation
duplicate
enhancement
github_actions
good first issue
help wanted
invalid
question
testing wanted
wontfix
Milestone
Clear milestone
No items
No milestone
Assignees
Clear assignees
No assignees
1 participant
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".
No due date set.
Dependencies
No dependencies set
Reference
MagicBeanDev/Hookshot!1960
Loading…
Reference in a new issue
No description provided.
Delete branch "fix/intel-black-screen-rgb9e5"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
On Intel iGPUs like the Iris Xe, loading a save gives a black screen with only the HUD on top. The scene is rendered as B10G11R11, but the fallback upscaler reads it back as RGB9E5, so almost all of the brightness is lost.
These GPUs don't have cooperative matrices, so the upscale networks get left out and stand-ins run instead:
upscale_stubat 50% andtaau_stand_inat 75%. Both sampled the scene through an RGB9E5 view. In Link's house at 50% the input averaged 0.033 and the output 0.00018.The fix tracks the format a render pass last drew an image in (
Texture::written_as, cleared by a shader store).upscale_stubskips the RGB9E5 decode when its input was rendered in its own format, andtaau_stand_inhands such an input toupscale_stub. Inputs a shader stored as RGB9E5 (#425) still get decoded.Tested on an Iris Xe (Raptor Lake-P), Mesa 26.2.4, Bazzite/KDE Wayland, i9-13900H. I loaded a save in Link's house at 50% (Minimum preset) and at 75%: the room shows up properly at both now. 16-21 fps at 50%. GPUs with cooperative matrices don't take these paths.
Tests: new cases in
test_upscale_fallback.pyandtest_taau_env_lookup.py; the rendered ones fail on main. The other tests that read the changed functions still pass.Refs #999, #1001. Not tested on Arc, so this may not cover every report there.
Screenshots:
Before:
After:
Thanks for tracking this down. The numbers (0.033 in, 0.00018 out) and the before/after shots make the symptom clear, and deciding the decode by what last wrote the image is a better test than checking the vendor.
Root cause. The description shows how it breaks: a B10G11R11 input that a pass rendered gets read through an RGB9E5 view. It doesn't say why Iris Xe ends up there when #425 found real RGB9E5 bits in the same image on AMD. The game samples this image as RGB9E5 on the console too, so something normally stores RGB9E5 bits there after the scene pass, and on Iris Xe that store seems not to happen. If that's a pass that gets skipped or fails on ANV, this PR makes the fallback cope with it, which is worth having. But the missing writer is the real cause and may matter elsewhere. Could you say which program last writes the stub's input on Iris Xe (the img/watch logs show it), and whether it's the same on an AMD card without cooperative matrices?
Gating. You're right that GPUs with cooperative matrices never get here:
taau_keyonly stands in undermma_software/RX_VK_NO_F16, and the networks are only left out without cooperative matrices. It isn't Intel-only, though. Steam Deck, RDNA1/2, Polaris and Pascal take both paths as well. Inupscale_stubthe new check only skips the decode when the input really was last rendered in its own format, so on those GPUs it's harmless or a fix. Thetaau_stand_inchange reaches further (see inline): it can replace the 75% stand-in on those GPUs, and it can leave the output unwritten. A Steam Deck or RDNA2 run at 75% before/after would settle it.Sync / memory / cost. No new barriers, images or allocations.
upscale_stubdoes its ownend_pass+full_barrier. The extra work is one loop over the dispatch's sampled textures, so no measurable cost. Nit:written_asis set inbegin_passunderParLock(marks)(often not taken) and read unlocked in the stub. WithRX_VK_PARALLEL, segments record out of order, so the stub can see another segment's value. Parallel replay is off by default, so this is minor. The bigger gap is the writers that don't touch the field at all (inline).Description vs testing. Tested on one machine: Iris Xe, Mesa 26.2.4 on Linux, 50% and 75%, game upscaler. Not tested on Intel's Windows driver, on Arc (which you call out), or on the non-Intel GPUs without cooperative matrices that this also reaches. I'd add that last point to the description.
Tests / CI. The new cases go into
test_upscale_fallback.pyandtest_taau_env_lookup.py, whichrun_all.pyalready discovers, so nothing extra to declare. There's no case forupscale_stubreturning false fromtaau_stand_in, or for a texture the TAAU samples that isn't its input. CI hasn't run yet: the three workflows are waiting for maintainer approval ("action required"). The patch applies cleanly to current main (48 commits behind).The direction looks right to me. Once the two inline points on
taau_stand_inare addressed and there's a run on a non-Intel GPU without cooperative matrices, I'd be happy with it.written_asis only updated here and in the storage-image path.copy_t2t(vkCmdCopyImageis a bit copy), buffer-to-texture copies,clear_texand CPU uploads all leave it alone. So an image that was rendered once and later refilled with RGB9E5 bits by a copy or an upload keepswritten_as == format, and the #425 decode is skipped. Resetting it toVK_FORMAT_UNDEFINEDinsidetexture_written()(vk_texture.cpp) would cover every GPU writer in one place.begin_passalready calls that before setting it here, and the explicit reset inbuild_descriptorswould then be redundant.upload()doesn't go throughtexture_written, so it needs the same reset.Follow-up, not blocking:
temporal_rejected_networkruns above this when an upscaler other than the game's is picked, and it still samples the input through its RGB9E5 view. So with FSR or the temporal upscaler at 50% on Iris Xe, I'd expect the same dark picture. Untested on my side; worth a quick run.Two things here:
upscale_stubreturns false, this returns false too. That happens when its input/output pick fails,out_area <= in_area, orRX_VK_NO_UPSCALE_STUBis set. A stood-in network is never compiled, so the dispatch is then skipped and the output isn't written at all, where beforetyped_upscalebelow ran. Suggestif (upscale_stub(cmd, s, p.key)) return true;and let it fall through.upscale_stubthen also makes its own pick of the input, which may not be the texture that matched here. Narrower: get theTexturebehindtexture_descriptors[0](the onedw().imgs[0]views) withtexture_view_of, as you already do forout, and test only that one.Thanks for the review. Your root-cause question turned out to be the key one. On current main I can't reproduce the black screen anymore: on the Iris Xe (Mesa 26.2.4), plain main's renderer gives a lit Link's house at 50% and 75%, with buffer mirrors off and an empty shader cache. The writer you were asking about is compute
6637ac1d052d22d4. It stores RGB9E5 bits into the input (768×432 at 50%) after graphics22ffdff3renders it as B10G11R11, and it runs every frame. So the typed decode is correct, and the fallback in this PR never triggers. I don't know why the writer was missing on the build I first tested (e7210437), and my logs from back then never got past the menus.I've reworked the PR with your inline points (input-only check with fall-through,
written_asreset intexture_written()/upload(), more tests), but without a reproduction I'd rather not add code that never runs, so I'm closing this.Separately: at a 100% render resolution the picture is completely black on this machine on current main. No upscale network runs there, so it's a different bug. I'll look into it and open an issue.