diff options
| author | Sssnowyyy <78863999+Sssnowyyy@users.noreply.github.com> | 2026-11-02 11:28:52 -0500 |
|---|---|---|
| committer | Sssnowyyy <78863999+Sssnowyyy@users.noreply.github.com> | 2026-11-02 14:53:47 -0500 |
| commit | bda49e810b5955bff8474e7b8f2b09eab51e9be2 (patch) | |
| tree | 41ef797d37bfb265a978185b1af4cc5f7f73b5a5 /src/shader_recompiler/ir_opt/texture_pass.cpp | |
| parent | e277b4ba61694f229b38ec0dc62f31c35d0cbff3 (diff) | |
shader: evaluate handle programs for image and texture buffer descriptors
561f87abec only gave TextureDescriptor a handle_program. Image load/store/atomics
and texture/image buffers whose handle comes from a storage buffer still got the
placeholder constant buffer address (index 0, offset 0), so the pipelines read
cbuf 0 word 0 as the handle (and asserted if cbuf 0 was unbound). Add
handle_program to TextureBufferDescriptor, ImageBufferDescriptor and
ImageDescriptor, compare it when merging, and let all four pipelines evaluate it
for every descriptor kind instead of only TextureDescriptor.
ImageQueryDimensions on such a handle was always declared Color2D, so array,
cube and 3D views got a 2D declaration. The instruction carries no type, so take
it from another instruction using the same handle program, falling back to
Color2D when there is none.
Follow-up to 561f87abec. The OpenGL pipeline edits are the same change as the
Vulkan ones but were not compiled here.
Assisted-by: Claude Sonnet 5.5 (implementation and commit message)
Diffstat (limited to 'src/shader_recompiler/ir_opt/texture_pass.cpp')
| -rw-r--r-- | src/shader_recompiler/ir_opt/texture_pass.cpp | 34 |
1 files changed, 29 insertions, 5 deletions
diff --git a/src/shader_recompiler/ir_opt/texture_pass.cpp b/src/shader_recompiler/ir_opt/texture_pass.cpp index 514cd9b2b6..db8f1ac716 100644 --- a/src/shader_recompiler/ir_opt/texture_pass.cpp +++ b/src/shader_recompiler/ir_opt/texture_pass.cpp @@ -345,7 +345,8 @@ static inline u32 GetTextureHandleCached(Environment& env, const ConstBufferAddr // Cached variants of existing helpers // A handle computed per draw has no descriptor to read at translation time: assume an ordinary -// floating-point 2D texture, the instruction's own type deciding the rest. +// floating-point 2D texture, the instruction's own type deciding the rest (see the TexturePass +// ImageQueryDimensions case, which has none). static inline TextureType ReadTextureTypeCached(Environment& env, const ConstBufferAddr& cbuf) { if (cbuf.handle_program != ~0U) return TextureType::Color2D; return env.ReadTextureType(GetTextureHandleCached(env, cbuf)); @@ -1010,7 +1011,8 @@ public: desc.secondary_cbuf_offset == existing.secondary_cbuf_offset && desc.secondary_shift_left == existing.secondary_shift_left && desc.count == existing.count && desc.size_shift == existing.size_shift && - desc.has_secondary == existing.has_secondary; + desc.has_secondary == existing.has_secondary && + desc.handle_program == existing.handle_program; }); } @@ -1018,7 +1020,8 @@ public: const u32 index{Add(image_buffer_descriptors, desc, [&desc](const auto& existing) { return desc.format == existing.format && desc.cbuf_index == existing.cbuf_index && desc.cbuf_offset == existing.cbuf_offset && desc.count == existing.count && - desc.size_shift == existing.size_shift; + desc.size_shift == existing.size_shift && + desc.handle_program == existing.handle_program; })}; image_buffer_descriptors[index].is_written |= desc.is_written; image_buffer_descriptors[index].is_read |= desc.is_read; @@ -1050,7 +1053,8 @@ public: return desc.type == existing.type && desc.format == existing.format && desc.cbuf_index == existing.cbuf_index && desc.cbuf_offset == existing.cbuf_offset && desc.count == existing.count && - desc.size_shift == existing.size_shift; + desc.size_shift == existing.size_shift && + desc.handle_program == existing.handle_program; })}; image_descriptors[index].is_written |= desc.is_written; image_descriptors[index].is_read |= desc.is_read; @@ -1186,6 +1190,18 @@ void TexturePass(Environment& env, IR::Program& program, const HostTranslateInfo has_last_is_integer = true; return last_is_integer; }}; + // A handle program has no descriptor to read a type from, and ImageQueryDimensions carries + // none: it takes the type of another instruction using the same handle. + std::unordered_map<u32, TextureType> handle_program_types; + for (const TextureInst& texture_inst : to_replace) { + const IR::Opcode opcode{IndexedInstruction(*texture_inst.inst)}; + if (texture_inst.cbuf.handle_program != ~0U && opcode != IR::Opcode::ImageQueryDimensions && + !IsStorageImageOpcode(opcode)) { + handle_program_types.try_emplace( + texture_inst.cbuf.handle_program, + texture_inst.inst->Flags<IR::TextureInstInfo>().type.Value()); + } + } for (TextureInst& texture_inst : to_replace) { // TODO: Handle arrays IR::Inst* const inst{texture_inst.inst}; @@ -1196,7 +1212,12 @@ void TexturePass(Environment& env, IR::Program& program, const HostTranslateInfo bool is_multisample{false}; switch (inst->GetOpcode()) { case IR::Opcode::ImageQueryDimensions: - flags.type.Assign(ReadTextureTypeCached(env, cbuf)); + if (const auto it{handle_program_types.find(cbuf.handle_program)}; + it != handle_program_types.end()) { + flags.type.Assign(it->second); + } else { + flags.type.Assign(ReadTextureTypeCached(env, cbuf)); + } inst->SetFlags(flags); break; case IR::Opcode::ImageSampleImplicitLod: @@ -1261,6 +1282,7 @@ void TexturePass(Environment& env, IR::Program& program, const HostTranslateInfo .cbuf_offset = cbuf.offset, .count = count, .size_shift = size_shift, + .handle_program = cbuf.handle_program, }); } else { index = descriptors.Add(ImageDescriptor{ @@ -1273,6 +1295,7 @@ void TexturePass(Environment& env, IR::Program& program, const HostTranslateInfo .cbuf_offset = cbuf.offset, .count = count, .size_shift = size_shift, + .handle_program = cbuf.handle_program, }); } break; @@ -1289,6 +1312,7 @@ void TexturePass(Environment& env, IR::Program& program, const HostTranslateInfo .secondary_shift_left = cbuf.secondary_shift_left, .count = count, .size_shift = size_shift, + .handle_program = cbuf.handle_program, }); } else { count = std::min(count, sampled_dynamic_cap); |
