diff --git a/src/video_core/shader/decode/image.cpp b/src/video_core/shader/decode/image.cpp index 66fdf5714..199b6b793 100644 --- a/src/video_core/shader/decode/image.cpp +++ b/src/video_core/shader/decode/image.cpp @@ -55,8 +55,9 @@ u32 ShaderIR::DecodeImage(NodeBlock& bb, u32 pc) { coords.push_back(GetRegister(instr.gpr8.Value() + i)); } - ASSERT(instr.sust.is_immediate); - const auto& image{GetImage(instr.image, instr.sust.image_type)}; + const auto type{instr.sust.image_type}; + const auto& image{instr.sust.is_immediate ? GetImage(instr.image, type) + : GetBindlessImage(instr.gpr39, type)}; MetaImage meta{image, values}; const Node store{Operation(OperationCode::ImageStore, meta, std::move(coords))}; bb.push_back(store); @@ -86,4 +87,29 @@ const Image& ShaderIR::GetImage(Tegra::Shader::Image image, Tegra::Shader::Image return *used_images.emplace(entry).first; } +const Image& ShaderIR::GetBindlessImage(Tegra::Shader::Register reg, + Tegra::Shader::ImageType type) { + const Node image_register{GetRegister(reg)}; + const Node base_image{ + TrackCbuf(image_register, global_code, static_cast(global_code.size()))}; + const auto cbuf{std::get_if(base_image)}; + const auto cbuf_offset_imm{std::get_if(cbuf->GetOffset())}; + const auto cbuf_offset{cbuf_offset_imm->GetValue()}; + const auto cbuf_index{cbuf->GetIndex()}; + const auto cbuf_key{(static_cast(cbuf_index) << 32) | static_cast(cbuf_offset)}; + + // If this image has already been used, return the existing mapping. + const auto itr{std::find_if(used_images.begin(), used_images.end(), + [=](const Image& entry) { return entry.GetOffset() == cbuf_key; })}; + if (itr != used_images.end()) { + ASSERT(itr->GetType() == type); + return *itr; + } + + // Otherwise create a new mapping for this image. + const std::size_t next_index{used_images.size()}; + const Image entry{cbuf_index, cbuf_offset, next_index, type}; + return *used_images.emplace(entry).first; +} + } // namespace VideoCommon::Shader diff --git a/src/video_core/shader/node.h b/src/video_core/shader/node.h index 8b8d83ae7..2bf535928 100644 --- a/src/video_core/shader/node.h +++ b/src/video_core/shader/node.h @@ -270,6 +270,15 @@ public: explicit Image(std::size_t offset, std::size_t index, Tegra::Shader::ImageType type) : offset{offset}, index{index}, type{type}, is_bindless{false} {} + explicit Image(u32 cbuf_index, u32 cbuf_offset, std::size_t index, + Tegra::Shader::ImageType type) + : offset{(static_cast(cbuf_index) << 32) | cbuf_offset}, index{index}, type{type}, + is_bindless{true} {} + + explicit Image(std::size_t offset, std::size_t index, Tegra::Shader::ImageType type, + bool is_bindless) + : offset{offset}, index{index}, type{type}, is_bindless{is_bindless} {} + std::size_t GetOffset() const { return offset; } diff --git a/src/video_core/shader/shader_ir.h b/src/video_core/shader/shader_ir.h index c7f264371..e22548208 100644 --- a/src/video_core/shader/shader_ir.h +++ b/src/video_core/shader/shader_ir.h @@ -262,6 +262,9 @@ private: /// Accesses an image. const Image& GetImage(Tegra::Shader::Image image, Tegra::Shader::ImageType type); + /// Access a bindless image sampler. + const Image& GetBindlessImage(Tegra::Shader::Register reg, Tegra::Shader::ImageType type); + /// Extracts a sequence of bits from a node Node BitfieldExtract(Node value, u32 offset, u32 bits);