fix(vk): allow raw colour attachment usage and views on 2D BC textures on AMD #2001
Open
1conver wants to merge 1 commit from
1conver/fix/amd-bc-raw-attachment-views into main
pull from: 1conver/fix/amd-bc-raw-attachment-views
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
2 participants
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!2001
Loading…
Reference in a new issue
No description provided.
Delete branch "1conver/fix/amd-bc-raw-attachment-views"
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?
Resolves the issue where 2D block-compressed textures (such as BC6H/BC5 crystal emissive lights in Dodongo's Cavern) fail to receive colour attachment usage or valid views on AMD Windows drivers, resulting in skipped render passes and unwritten multicoloured/rainbow block artifacts. Closes #1801.
Why this is needed
== VK_SUCCESS\ for 2D images, \x.usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT\ was not set.
Solution
Passes \ ests/test_bc_raw_targets.py\ cleanly. Tested and confirmed on AMD Radeon RX 6600 XT.
Thanks for digging into #1801, and the -11 from the image-format query on the 2D BC6H/BC5 images is a useful lead. A few things before this can go in, though.
It conflicts with main. #2046 (HKSTATE2) moved the view-format choice out of
texture_view()intoview_format_of(), whichattachment_format()also uses to build the pipeline state list. So after a rebase the second change has to go there. It then also changes which formats the prebuilt pipelines expect, so please check that the state-list side still agrees with whattargets()binds.The new usage condition is always true. The whole block sits inside
if (format_props(raw).optimalTilingFeatures & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT), so the added|| (format_props(raw)... & COLOR_ATTACHMENT_BIT)always holds. The result is that every 2D BC image gets the attachment usage on every vendor, and the query's answer is ignored. That may be what you need on AMD (it's how the STORAGE comment above describes amdvlk: it says no, then makes the image anyway). If so, please say it in the code: drop the query for 2D, or scope the override to the case you saw, and update the comment above the block, which still says the usage is taken "on the driver's word". As it stands it reads like a check but isn't one. Also, creating an image with a usage the driver said it doesn't support is outside the spec. The refusal fallback only catches a driver that actually failsvkCreateImage, so it's worth running with validation on once.The attachment-view change needs a reason. When the game uses a raw view (RGBA16UI/RGBA32UI and so on, as with the #1151 noise volumes),
fis already not BC and was never blocked here. This line only matters when the view's own format is BC6H/BC5, and then the draw's fragment shader writes whatever it was compiled for (float outputs for a BC6H "target") into anR32G32B32A32_UINTattachment. Per the spec that's undefined when the numeric types differ. Do you have a log or capture showing that path is hit in Dodongo's Cavern? If the first change alone fixes the crystals, I'd leave this line out.Testing: the description says
test_bc_raw_targets.pypasses, but there's no in-game confirmation yet. Has the reporter or anyone with an RX 6700 XT (or another AMD card) tried it in Dodongo's Cavern? Before/after screenshots there would help (CONTRIBUTING asks for them on visual changes). A quick check on NVIDIA/Intel would also help, since the usage now changes there too. lucasmsqt pointed the reporter at their fork on the issue, so it's worth checking it doesn't overlap with this.CI: the one failure is
tests/test_bake_skeleton.pytiming out on Windows. That's unrelated to this diff.This always holds, since the enclosing
ifalready requiresformat_props(raw).optimalTilingFeatures & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT. Sorno longer decides anything for 2D or 3D, and the log's "(raw format: taken)" prints for every refused 2D image on any GPU. If ignoring the query is the intent, please make that explicit (and limit it to where it's needed).This is only reached when the view format itself is BC (raw views are already non-BC). The shader then writes its own output type, e.g. float for BC6H, into an
R32G32B32A32_UINTattachment, which is undefined. On main this logic now lives inview_format_of()and feedsattachment_format()too. Is this path actually hit in Dodongo's Cavern?Thanks for the detailed review @hckrman101!
1. Rebase & HKSTATE2 (
view_format_of)Rebased onto
upstream/main(ceb8745). As requested, the attachment mapping is now placed inview_format_of():Because
attachment_format()also delegates toview_format_of(), the prebuilt pipeline state records (state_targets) match the exact raw attachment format (R32G32B32A32_UINTfor 16-byte blocks,R32G32_UINTfor 8-byte blocks) thattargets()binds during draws.2. Usage condition & AMD driver behavior
You were spot on about the redundant check inside
if (format_props(raw).optimalTilingFeatures & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT).We updated the condition to:
and updated the code comment to explain the AMD driver (
amdvlk) behavior: queries for compressed formats withCOLOR_ATTACHMENT_BITreturn-11(VK_ERROR_FORMAT_NOT_SUPPORTED) because the driver checks the base compressed format directly rather than raw block-texel views. But withEXTENDED_USAGEandBLOCK_TEXEL_VIEW_COMPATIBLE,vkCreateImagesucceeds and allows attaching the raw view. If any driver were to strictly refuse the usage duringvkCreateImage, the existing fallback at line 2030 (!((ci.usage & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT) && is_bc(x.format)...)) catches it and retries without the flag.3. Empirical In-Game Testing & Why Both Changes Are Strictly Required
We tested this directly in-game on an AMD Radeon RX 6600 XT (Adrenalin drivers on Windows) at the entrance of Dodongo's Cavern.
The first change alone did NOT fix the issue. Here is why:
In
targets(NvnState& s)(gpu/vk/vk_draw.cpp:3735), Hookshot acquires the view for each attachment:With only the usage bit on
VkImage,view_format_of()returnedVK_FORMAT_UNDEFINED, which ledtexture_view()to returnVK_NULL_HANDLE.Because
viewwas null,targets()skipped adding the attachment (if (!view) continue;). This leftat.n == 0(or the color slot empty), causing the draw to skip the render pass entirely.Because the emissive pass never executed into the target, the texture retained uninitialized VRAM memory from prior allocations, manifesting on AMD as solid, saturated rainbow diamond blocks on the crystals:
When
view_format_of()maps BC attachment views tostorage_view_format(f):texture_view()produces a valid block-texel view (R32G32B32A32_UINT).targets()invk_draw.cpp:3742already contains logic specifically anticipating raw views of BC targets: This scales the render area to blocks matching the attachment view extent.This conflicts with main in
gpu/vk/vk_texture.cpp, and the code it changes has been reworked. #2327 (device loss rendering to 3D BC slices) took 3D BC images off the raw-attachment path: they now render through a separate uncompressed mip, and the usage block at vk_texture.cpp:2043 isx.type != VK_IMAGE_TYPE_3Donly. So the "3D: taken" half of this diff no longer applies.Two points from the earlier review are still open after the rebase. First,
|| x.type == VK_IMAGE_TYPE_2Dgives every 2D BC image the attachment usage on every vendor, whatevervkGetPhysicalDeviceImageFormatPropertiessays. That's outside the spec, and it changes NVIDIA and Intel too, not only amdvlk. Please scope it to the AMD driver where you saw -11, or show a validation-clean run. Second, theview_format_ofchange at line 159 attaches a BC-format view as R32G32B32A32_UINT, which the fragment shader writes float outputs into. The screenshot shows the crystals change, but not that the write is defined. A RenderDoc capture of the Dodongo's Cavern pass would settle it. The issue is now tracked in #1006, and it's listed as a regression since v2.0.12, so it's worth checking which commit caused it.This now conflicts with main in
gpu/vk/vk_texture.cpp. Could you merge main into the branch (or rebase) when you get a chance? I'll take another look once it's up to date.Rebased onto the latest \upstream/main\ (\ce53453) and addressed both points from @Joey-Magnus:
Rebase & #2327 alignment:
Resolved the conflict cleanly with #2327. Since #2327 migrated 3D BC attachments to separate uncompressed mips with copy-back, the 3D path here is left entirely untouched.
Scoped 2D usage override to AMD:
The override is now strictly scoped to AMD (\dev.props.vendorID == 0x1002):
\\cpp
const bool is_amd = dev.props.vendorID == 0x1002;
if (x.type != VK_IMAGE_TYPE_3D && (format_props(raw).optimalTilingFeatures & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT)) {
const VkResult r = vkGetPhysicalDeviceImageFormatProperties(dev.physical, x.format, x.type, VK_IMAGE_TILING_OPTIMAL,
x.usage | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, flags, &limits);
if (r == VK_SUCCESS || is_amd) x.usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
...
\\
On NVIDIA and Intel, the driver's query response (
== VK_SUCCESS) is strictly obeyed without overrides. On AMD, where \mdvlk\ returns -11\ on compressed format queries despite accepting raw block-texel attachment views via \EXTENDED_USAGE, the usage is granted (with the existing \kCreateImage\ refusal retry fallback retained below if a driver were to fail creation).
Format mapping in \iew_format_of\ & v2.0.12 regression:
Prior to HKSTATE2 (#2046), \ exture_view\ did not discard BC under \ViewUse::Attachment\ (\if (use == ViewUse::Attachment && is_astc(f)) return VK_NULL_HANDLE;\ only checked ASTC). HKSTATE2 introduced \if (use == ViewUse::Attachment && (is_astc(f) || is_bc(f))) return VK_FORMAT_UNDEFINED;\ on the assumption that compressed formats are never targets. However, OoT does bind raw block views for BC targets (which \ argets()\ in \k_draw.cpp:3842\ explicitly accommodates via \if (bc(tex->format) && !bc(f)) w = (w + 3) / 4, h = (h + 3) / 4;). Mapping \is_bc(f)\ to \storage_view_format(f)\ restores that raw view, allowing the render pass to execute and clear/write the crystal data.
Passes \ est_bc_raw_targets.py\ cleanly. Ready for another look @hckrman101!
Thanks for scoping the usage override. The rebase onto #2327 is clean: the 3D path is untouched. I merged this into current main and ran the texture, BC, view and pipeline-state checks. All pass except
nx2/test_bc_storage_views, which fails the same way on main on Linux.Two points still stand:
gpu/vk/vk_texture.cpp:159:view_format_ofnow turns every BC-format attachment view intoR32G32B32A32_UINT/R32G32_UINTon every vendor, not just AMD.attachment_format()uses the same function, so the pipeline state list changes for everyone too. The fragment shader still writes float outputs into a UINT attachment, which the spec leaves undefined. The screenshot shows the crystals change, but it doesn't show that the write is defined. Please scope this to the case you saw, or show a RenderDoc capture of the pass.vk_texture.cpp:2064:vendorID == 0x1002covers RADV, so the Steam Deck too, as well as AMD's Windows driver, not only amdvlk as the comment says. Has the -11 been seen on RADV? If not, please gate ondriverIDand run once with validation on.#1006 lists this as a regression since v2.0.12. Finding the commit that caused it may give a smaller fix.