Repository navigation
BC3 re-encode of ASTC arrays: one layer a run (Hyrule Field grid lines) - #956
Conversation
When the BC3 path re-encodes an ASTC texture array, it decoded and encoded up to kBcLayers consecutive layers in one run. In the smaller levels, every layer after the run's first came out wrong. Single-layer textures were unaffected. The terrain's material arrays (1365 x 1365 x 90, ASTC 8x8) are sampled at those levels from a distance, so Hyrule Field's ground showed its tiles outlined in dark lines that went away up close. On an RX 6600 the lines went away with one layer a run, with the arrays kept as RGBA8, and with samplers capped at mip 0. One layer a run keeps the arrays BC3, so there is no VRAM cost (RGBA8 cost ~1.3 GB, too much for an 8 GB card). RX_VK_BC_LAYERS=<n>: up to n layers a run, as before with 8. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Thanks for isolating this. I wrote #705 (the AMD resize these arrays go through), so I checked your theory against the shaders: the encoder's addressing is fine, and the multi-layer step that goes wrong is most likely driver-side. The shaders handle layers correctly. I disassembled both SPIR-V headers with spirv-cross (Vulkan SDK):
What changes with n > 1 is driver-side. On AMD both terrain arrays are resized (#705), so each run does:
AMD packs small levels into a mip tail. A driver issue with multi-layer blits or copies there would match what you saw: only the small levels, only the layers after the first. Same family as the AMD BC level bug #705 works around. Suggested narrower fix: keep runs of 8 and split only those two calls into one region per layer (no extra dispatches or barriers): // bc_encode_into
const uint64_t layer_bytes = (uint64_t)pc.blocks_x * pc.blocks_y * 16;
VkBufferImageCopy c[kBcLayers];
for (uint32_t z = 0; z < n; z++)
c[z] = {z * layer_bytes, 0, 0, {VK_IMAGE_ASPECT_COLOR_BIT, level, layer + z, 1}, {dx, dy, 0}, {w, h, 1}};
vkCmdCopyBufferToImage(cmd, bc_out, dst.image, VK_IMAGE_LAYOUT_GENERAL, n, c);
// bc_encode_resized
VkImageBlit bl[kBcLayers]{};
for (uint32_t z = 0; z < n; z++) {
bl[z].srcSubresource = bl[z].dstSubresource = {VK_IMAGE_ASPECT_COLOR_BIT, 0, z, 1};
bl[z].srcOffsets[1] = {(int32_t)w, (int32_t)h, 1};
bl[z].dstOffsets[1] = {(int32_t)ow, (int32_t)oh, 1};
}
vkCmdBlitImage(cmd, bc_scratch, VK_IMAGE_LAYOUT_GENERAL, bc_scratch2, VK_IMAGE_LAYOUT_GENERAL, n, bl, VK_FILTER_LINEAR);Testing them one at a time (copy only, then blit only) would show which call it is. Why this over 1 layer a run:
Heads-up: this and #900 edit the same run loop, so whichever merges second needs a rebase. |
Hyrule Field's ground shows its tiles outlined in dark lines when seen from a distance; up close the lines go away. Seen on an RX 6600 (Windows 11), likely part of #468.
Cause
When the BC3 path re-encodes an ASTC texture array,
upload_astc_gpudecodes and encodes up tokBcLayers(8) consecutive layers in one run. In the smaller mip levels, every layer after the run's first comes out wrong; single-layer textures are unaffected. The terrain's material arrays (1365 x 1365 x 90, ASTC 8x8) are sampled at those levels from a distance, hence the lines.How it was isolated (RX 6600): the lines went away
Fix
One layer a run by default. The arrays stay BC3, so there is no VRAM cost (RGBA8 cost ~1.3 GB, too much for an 8 GB card).
RX_VK_BC_LAYERS=<n>allows up to n layers a run (8: as before).I couldn't read
bc_encoder.comp(only its SPIR-V header is in the tree), so this works around the multi-layer path rather than fixing its addressing. If you have the shader source, the per-layer output offset for levels smaller than the first is probably what's off; with that fixed, runs could go back to 8.Tested: RX 6600 + Ryzen 5 5600G, Windows 11: lines gone in Hyrule Field, no other texture changes seen in Kokiri. Builds on current main (32df58e). Not tested on NVIDIA/Intel/Linux; the change applies to every GPU that takes the BC3 path.
🤖 Generated with Claude Code