fix(vk): render BC targets through raw views, and stop leaving out OoT's noise volume pass #1338
No reviewers
Labels
No labels
accessibility
autorelease: pending
autorelease: tagged
bug
dependencies
documentation
duplicate
enhancement
github_actions
good first issue
help wanted
invalid
question
testing wanted
wontfix
No milestone
No assignees
1 participant
Due date
No due date set.
Dependencies
No dependencies set
Reference
MagicBeanDev/Hookshot!1338
Loading…
Reference in a new issue
No description provided.
Delete branch "fix/bc-raw-render-targets"
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?
What this fixes
Trees lose their needles or leaves at mid distance, full again from far and near (#1151, part of #994).
OoT renders the slices of two 64³ BC4 noise volumes while an area loads (program
53509044401d78d2, 128 draws). Each slice is an RGBA16UI target with one texel per BC block. The foliage's two LODs crossfade with a dither read from that noise. In a spruce's fragment stages, the near LOD (68e4ed4beeba2155) fades out over a view depth of 34→65, and the far LOD (2ee91258acc43828) fades in over 32→60. Each fragment keeps the needle whenalpha + fade + noise >= 0.5.The volumes were always zero, so the crossfade became a hard cut on each side, and trees went bare in between:
53509044401d78d2is onRX_VK_SKIP_PROG's default list, because it lost the device on about half the first starts (7 of 14 in the comment there);view of texture 0x1133ccb000 (vk 139) as vk 95 type 1 ... not made, for every slice;targets()sized the pass in texels (64×64) over a view that is 16×16 blocks.Change
gpu/vk/vk_texture.cpp: BC images takeCOLOR_ATTACHMENTusage when the raw format supports it. 3D ones take it too, for their per-slice views.gpu/vk/vk_draw.cpp:targets()sizes raw views of BC targets in blocks;RX_VK_SKIP_PROGstill takes keys.tests/test_bc_raw_targets.pychecks all three. It fails on main and passes here.How it was tested
RTX 3070 8 GB, Windows 11.
RX_VK_SKIP_FILEto the two LOD programs;RX_VK_DUMP_SAMPLED: the noise volume (#171,0x1133ccb000) was all zero before. With the change, the pass writes it (RX_VK_WATCH_TEX:written, render area 16x16) and the needles stay.tests/run_all.py(llvm-mingw) fails only on four tests that fail the same way on main:nup_read_name,nup_paths,fps_overlay_order,precompile_compute_guard.Not tested: AMD and Intel, Linux. The usage is added only where the driver reports it for the raw format, as the storage usage next to it is.
No game data included.
🤖 Generated with Claude Code
Note for reviewers: #1332 (@BiasedMonkey, opened just before this one) makes the same BC views and block-sized render area, found from the AMD side. It is enabled on RADV only, and it keeps
53509044401d78d2on the default skip list. What this PR adds is the skip-list change, NVIDIA, and the link to #1151. Details in #1332. I'm fine with whichever of the two lands, as long as the noise pass runs.Nice find, and the write-up makes it easy to follow. The raw-view approach is valid Vulkan: the image already has MUTABLE_FORMAT | BLOCK_TEXEL_VIEW_COMPATIBLE | EXTENDED_USAGE, an RGBA16UI/RG32UI view of a 64-bit BC block is in the size-compatible class, and with extended usage a view's COLOR_ATTACHMENT usage only has to be supported by the view format. Both R32G32_UINT (what you query) and R16G16B16A16_UINT (what the game uses) are mandatory colour attachment formats. Sizing a block view in blocks (ceil(mip texels / 4)) is right too. Main questions are about drivers you couldn't test, and about the overlap with #1332.
Things I'd like to see addressed:
No fallback if image creation is refused. For 3D images the usage is added even when the driver's query says no (the 3D branch of the
ifbelow). On main the retry chain increate()only drops STORAGE for BC/ASTC images, so if any driver refuses a 3D BC image with COLOR_ATTACHMENT (the query also runs before the 3D-only 2D_ARRAY_COMPATIBLE flags are added, so it isn't a faithful test either), the image isn't created at all, and OoT's noise volumes would be sampled as the dummy texture. #1332 retries without COLOR_ATTACHMENT first; something like that here would make this safe to turn on everywhere.The skip list is dropped for every driver, but this was only run on one NVIDIA card. The 7 of 14 device-lost figure is on Windows/NVIDIA, and I can't tell from the PR whether the render-area bug was the whole cause. Since #1332 (RADV) found the same views and left the skip in place, I think it's worth a test on AMD and Intel before it's the default there. Alternatively keep the skip list default-on where the usage isn't added, so the pass only runs where the views can be made.
clear_tex()invk_xfer.cpphas the same texel-vs-block render area (ri.renderArea = {{0, 0}, {lw, lh}}), and its clear rect is in texels. Before this PR those views weren't made, so it was skipped (if (!view) continue;). With the attachment usage added, a clear through a block view will now begin rendering with a 64x64 area over a 16x16 view, which is invalid. I don't know if OoT clears these textures on every path, but #1332 covers it (view_texels()plus clamping the rect), and this PR doesn't.On #1332 vs this PR: they make the same two core changes (COLOR_ATTACHMENT on BC images for the raw views, and block-sized render area in
targets()). #1332 is more complete on the plumbing: query done separately from STORAGE, create retry without the usage,clear_tex()sizing, "not made" diagnostics, and an opt-out env var, but it's RADV-only and leaves53509044401d78d2on the skip list, so the noise volumes still never get written. This PR is the one that actually fixes #1151 (skip list, NVIDIA data), but it's missing the retry and theclear_tex()fix. I'd suggest folding the two: #1332's create/clear changes, enabled by default where the query says OK, plus this PR's skip-list change and test. Those are the maintainers' call, but as they stand neither alone does the job.Smaller things:
x.bc), which the game never renders to. #1332 skips those.tests/test_bc_raw_targets.pychecks source text with regexes, so it's only a tripwire, not a test of the behaviour. Fine given there's no GPU in CI, but it will break on any reformat of those lines.CI is green. Not run or built locally.
Looks right: mip texels rounded up to blocks.
clear_tex()in vk_xfer.cpp still sizes its render area in texels for the same views (see the review body).@ -1660,0 +1668,4 @@: VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT | (dev.view_2d_of_3d ? VK_IMAGE_CREATE_2D_VIEW_COMPATIBLE_BIT_EXT : 0u));const VkResult r = vkGetPhysicalDeviceImageFormatProperties(dev.physical, x.format, x.type, VK_IMAGE_TILING_OPTIMAL,x.usage | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, asked, &limits);if (r == VK_SUCCESS || x.type == VK_IMAGE_TYPE_3D) x.usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;For 3D this adds COLOR_ATTACHMENT even when
ris a failure, and nothing retries without it ifcreate_imagethen fails (main only retries without STORAGE). A driver that rejects it would lose the whole texture. Suggest a retry without the usage in the create chain, like #1332.@hckrman101 thanks for the review. All three points are addressed in
5daa99c:COLOR_ATTACHMENTfirst, then withoutSTORAGE, as in #1332;2D_ARRAY_COMPATIBLE/2D_VIEW_COMPATIBLEflags.53509044401d78d2stays left out by default, but only while its targets have no view, i.e. where the raw views could not be made. Where the driver takes the usage, the pass runs.RX_VK_SKIP_PROG=-still runs it anyway.clear_tex(): a clear through a raw view of a BC image is sized in blocks, with the rect converted to blocks and clamped.tests/test_bc_raw_targets.pycovers all three.Re-tested on the RTX 3070 with the final build:
run_all.pylocally: only the four Windows-local failures that main has too.I also posted NVIDIA results for #1332 there. I'm still fine with whichever of the two lands.
Thanks for the quick turnaround. I went through
5daa99c, and all three points from my last review are handled:x.usage = ci.usagekeeps the texture's usage in step, andmake_view()refuses any view whose usage the image lacks, so nothing later tries an attachment view the image doesn't have. The query now passes the 3D image's 2D_ARRAY_COMPATIBLE / 2D_VIEW_COMPATIBLE flags.bare_targets(s, targets(s)), so the views already exist when the pass is considered.targets()trims trailing view-less targets, so!at.nreally means "no colour view", and it's checked per draw (only the env lookup is static). Where the retry dropped the usage, the views fail,at.nis 0 and the pass stays out. That's what I asked for.clear_tex(): both the render area and the rect are in blocks. The rect is floored at the start and rounded up at the end, then clamped to the block extent, so a clear that isn't a multiple of 4 covers its partial blocks and doesn't overrun. Non-BC clears are unchanged.One blocker: CI is red because of this change.
tests/test_vulkan_clear_mip.py(on main sinced7a1207) extractsclear_tex()and compiles it against a stubTexturethat has noformatmember, so the news.tex->formatread fails to compile on both Linux and Windows (test.cpp:168:37: error: no member named 'format' in 'Texture'). That's probably why it didn't show up locally: run_all only runs it with--cxx/--headers. AddingVkFormat format=VK_FORMAT_R8G8B8A8_UNORM;to the stub should fix it. While you're there, a BC case in that harness (a 3D BC4 tex, an odd-sized region, then check the render area and rect in blocks) would test the new arithmetic itself, which the regex test can't.Nits:
vk_texture.cpp: the comment above the query still says it "does not cover 2D_ARRAY_COMPATIBLE", but now it does. 3D images also still take the usage when the query says no. With the retry that can't lose the texture any more, and it's the same approach the STORAGE bit takes for amdvlk, so I'm OK with it. But the comment should say why it's still forced rather than give the old reason.x.bc) also get the usage, thoughtexture_view()never makes non-sample views of them. Harmless.On #1332: with this commit, #1338 covers everything #1332 does that matters for the fix: attachment usage gated on the query, the retry chain, block-sized
targets()andclear_tex(). On top of that it runs on every driver that takes the usage, not just RADV, and it brings back the noise pass that actually fixes #1151. What #1332 still has on its own is the RADV-only gate /RX_VK_BC_TARGETSopt-in and some extra "not made" diagnostics, and none of those is needed here. So I'd land this one and close #1332 in its favour, with credit to BiasedMonkey for the same views found on AMD. AMD/Intel are still untested on this PR, but now a refusing driver just falls back to the old behaviour (no views, pass skipped), which is where main is today.I'll approve once the clear_mip stub is fixed and CI is green. Not built or run locally.
@ -1660,0 +1660,4 @@// (and colour attachment views, raw too: OoT renders the slices of two 64^3 BC4 noise volumes as RGBA16UI targets, one// texel a block (53509044401d78d2, while an area loads). Without the usage those views were not made, the volumes// stayed zero, and the foliage's dithered LOD crossfade, which reads them, left trees bare at mid distance, #1151.// 3D images take the usage on the driver's word for the 2D one: the query does not cover 2D_ARRAY_COMPATIBLE'snit: this reason is stale now that the query below does pass the 3D flags. If 3D still takes the usage when the query says no, say why (e.g. as with STORAGE: drivers that say no but make it; a refusal is retried below).
This new
s.tex->formatread is what breakstests/test_vulkan_clear_mip.py: its stubTexturehas noformat, so the extractedclear_tex()no longer compiles. AddingVkFormat format=VK_FORMAT_R8G8B8A8_UNORM;to the stub (and maybe a BC case there) should turn CI green. The block arithmetic below looks right to me: start floored, end rounded up, clamped toaw/ah.@ -1660,0 +1668,4 @@: VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT | (dev.view_2d_of_3d ? VK_IMAGE_CREATE_2D_VIEW_COMPATIBLE_BIT_EXT : 0u));const VkResult r = vkGetPhysicalDeviceImageFormatProperties(dev.physical, x.format, x.type, VK_IMAGE_TILING_OPTIMAL,x.usage | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, asked, &limits);if (r == VK_SUCCESS || x.type == VK_IMAGE_TYPE_3D) x.usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;Fixed in
5daa99c: a refused BC image is retried without COLOR_ATTACHMENT, then without STORAGE, and x.usage follows, so no attachment view is attempted afterwards.clear_tex() is now sized in blocks too (area and rect), fixed in
5daa99c. It does break test_vulkan_clear_mip.py's stub, though; see the new review.Test results on another machine, merged on today's main (
bbdc3704+ this PR), RTX 3070 8 GB, Windows 11, NVIDIA driver 610.88 as Vulkan reports it.First starts with the noise pass on (the PR's default, empty skip list):
not madein the log.53509044401d78d2shows up in play in the first cold start's log.Kakariko entrance, scripted camera, 4 runs (with / without, then again), the "without" runs with
RX_VK_SKIP_PROG=53509044401d78d2:A teleport tour of 26 areas on the same build (Kokiri Forest to Ganon's Castle, skipping 4 my teleport script doesn't handle): all in game, 0 device lost, 0
not made.I didn't test the Lon Lon spruce or AMD/Intel.
Fixed in
d171852: the stub hasformatnow, and the clear_mip test passes in CI.d171852addsformatto theTexturestub intest_vulkan_clear_mip.py, which was the one blocker. CI is green now on Linux and Windows, and the PR merges cleanly.Still open, both nits and neither blocks the merge: the stale comment above the COLOR_ATTACHMENT query in
vk_texture.cpp(it still says the query doesn't cover 2D_ARRAY_COMPATIBLE), and a BC case in the clear_mip harness to test the block arithmetic itself. Either can go in a follow-up.Approving. As I said last time, this covers what #1332 does for the fix, so I'd close #1332 in its favour, with credit to BiasedMonkey. Not built or run locally.
This landed in the v2.0.12 branch (merged there for testing; it reaches
mainwith that release), so closing. Thanks!Reopened: closing this was a mistake on my side. It was tested in the v2.0.12 branch, and it will be merged into main here, so it shows as merged. Sorry for the noise.
github-sync referenced this pull request2026-11-12 06:22:54 +00:00