From 461fa8ab6e7dc4fe179da931e25e3be1971e838a Mon Sep 17 00:00:00 2001 From: CamilleLaVey Date: Tue, 28 Jul 2026 01:09:16 -0400 Subject: [PATCH] [TEST] Another miscellaneous change 2 --- src/shader_recompiler/environment.h | 5 ++ src/shader_recompiler/ir_opt/texture_pass.cpp | 2 +- src/video_core/buffer_cache/buffer_cache.h | 5 +- src/video_core/engines/kepler_compute.h | 16 ++++++ .../renderer_opengl/gl_compute_pipeline.cpp | 24 ++++++--- .../renderer_vulkan/vk_compute_pipeline.cpp | 24 ++++++--- src/video_core/shader_environment.cpp | 52 ++++++++++++++++++- src/video_core/shader_environment.h | 5 ++ 8 files changed, 116 insertions(+), 17 deletions(-) diff --git a/src/shader_recompiler/environment.h b/src/shader_recompiler/environment.h index 20381cf467..d46d1c890e 100644 --- a/src/shader_recompiler/environment.h +++ b/src/shader_recompiler/environment.h @@ -78,6 +78,11 @@ public: [[nodiscard]] virtual TextureType ReadTextureType(u32 raw_handle) = 0; + [[nodiscard]] virtual u32 ResolveBindlessHandle(u32 cbuf_index, u32 cbuf_offset, + u32 raw_handle) { + return raw_handle; + } + [[nodiscard]] virtual TexturePixelFormat ReadTexturePixelFormat(u32 raw_handle) = 0; [[nodiscard]] virtual bool IsTexturePixelFormatInteger(u32 raw_handle) = 0; diff --git a/src/shader_recompiler/ir_opt/texture_pass.cpp b/src/shader_recompiler/ir_opt/texture_pass.cpp index 0d0144fcab..cd306038ff 100644 --- a/src/shader_recompiler/ir_opt/texture_pass.cpp +++ b/src/shader_recompiler/ir_opt/texture_pass.cpp @@ -502,7 +502,7 @@ u32 GetTextureHandle(Environment& env, const ConstBufferAddr& cbuf) { const u32 lhs_raw{env.ReadCbufValue(cbuf.index, cbuf.offset) << cbuf.shift_left}; const u32 rhs_raw{env.ReadCbufValue(secondary_index, secondary_offset) << cbuf.secondary_shift_left}; - return lhs_raw | rhs_raw; + return env.ResolveBindlessHandle(cbuf.index, cbuf.offset, lhs_raw | rhs_raw); } [[maybe_unused]] TextureType ReadTextureType(Environment& env, const ConstBufferAddr& cbuf) { diff --git a/src/video_core/buffer_cache/buffer_cache.h b/src/video_core/buffer_cache/buffer_cache.h index 7b7247e6e5..23efcea560 100644 --- a/src/video_core/buffer_cache/buffer_cache.h +++ b/src/video_core/buffer_cache/buffer_cache.h @@ -1430,8 +1430,9 @@ void BufferCache

::UpdateComputeUniformBuffers() { Binding& binding = channel_state->compute_uniform_buffers[index]; binding = NULL_BINDING; const auto& launch_desc = kepler_compute->launch_description; - if (((launch_desc.const_buffer_enable_mask >> index) & 1) != 0) { - const auto& cbuf = launch_desc.const_buffer_config[index]; + const u32 resolved_index = launch_desc.ResolveConstBufferIndex(index); + if (((launch_desc.const_buffer_enable_mask >> resolved_index) & 1) != 0) { + const auto& cbuf = launch_desc.const_buffer_config[resolved_index]; const std::optional device_addr = gpu_memory->GpuToCpuAddress(cbuf.Address()); if (device_addr) { binding.device_addr = *device_addr; diff --git a/src/video_core/engines/kepler_compute.h b/src/video_core/engines/kepler_compute.h index 4f7242f804..f35de64ae9 100644 --- a/src/video_core/engines/kepler_compute.h +++ b/src/video_core/engines/kepler_compute.h @@ -171,6 +171,22 @@ public: }; std::array const_buffer_config; + static constexpr u32 NvnShaderSlotBias = 2; + + u32 ResolveConstBufferIndex(u32 shader_index) const { + const u32 mask = const_buffer_enable_mask.Value(); + if (((mask >> shader_index) & 1) != 0) { + return shader_index; + } + if (shader_index >= NvnShaderSlotBias) { + const u32 biased = shader_index - NvnShaderSlotBias; + if (((mask >> biased) & 1) != 0) { + return biased; + } + } + return shader_index; + } + union { BitField<0, 20, u32> local_pos_alloc; BitField<27, 5, u32> barrier_alloc; diff --git a/src/video_core/renderer_opengl/gl_compute_pipeline.cpp b/src/video_core/renderer_opengl/gl_compute_pipeline.cpp index f0a7baf9aa..bef7825635 100644 --- a/src/video_core/renderer_opengl/gl_compute_pipeline.cpp +++ b/src/video_core/renderer_opengl/gl_compute_pipeline.cpp @@ -10,6 +10,7 @@ #include "common/cityhash.h" #include "common/settings.h" #include "video_core/renderer_opengl/gl_compute_pipeline.h" +#include "video_core/shader_environment.h" #include "video_core/renderer_opengl/gl_shader_manager.h" #include "video_core/renderer_opengl/gl_shader_util.h" @@ -104,25 +105,36 @@ void ComputePipeline::Configure() { const auto& qmd{kepler_compute->launch_description}; const auto& cbufs{qmd.const_buffer_config}; const bool via_header_index{qmd.linked_tsc != 0}; + const u32 tic_limit{kepler_compute->regs.tic.limit}; const auto read_handle{[&](const auto& desc, u32 index) { - ASSERT(((qmd.const_buffer_enable_mask >> desc.cbuf_index) & 1) != 0); + const u32 resolved_index{qmd.ResolveConstBufferIndex(desc.cbuf_index)}; + ASSERT(((qmd.const_buffer_enable_mask >> resolved_index) & 1) != 0); const u32 index_offset{index << desc.size_shift}; const u32 offset{desc.cbuf_offset + index_offset}; - const GPUVAddr addr{cbufs[desc.cbuf_index].Address() + offset}; + const GPUVAddr addr{cbufs[resolved_index].Address() + offset}; if constexpr (std::is_same_v || std::is_same_v) { if (desc.has_secondary) { - ASSERT(((qmd.const_buffer_enable_mask >> desc.secondary_cbuf_index) & 1) != 0); + const u32 resolved_secondary{ + qmd.ResolveConstBufferIndex(desc.secondary_cbuf_index)}; + ASSERT(((qmd.const_buffer_enable_mask >> resolved_secondary) & 1) != 0); const u32 secondary_offset{desc.secondary_cbuf_offset + index_offset}; - const GPUVAddr separate_addr{cbufs[desc.secondary_cbuf_index].Address() + + const GPUVAddr separate_addr{cbufs[resolved_secondary].Address() + secondary_offset}; const u32 lhs_raw{gpu_memory->Read(addr) << desc.shift_left}; const u32 rhs_raw{gpu_memory->Read(separate_addr) << desc.secondary_shift_left}; - return TexturePair(lhs_raw | rhs_raw, via_header_index); + const u32 combined{VideoCommon::ResolveBindlessHandleTable( + *gpu_memory, addr, lhs_raw | rhs_raw, + TexturePair(lhs_raw | rhs_raw, via_header_index).first, tic_limit)}; + return TexturePair(combined, via_header_index); } } - return TexturePair(gpu_memory->Read(addr), via_header_index); + const u32 single_raw{gpu_memory->Read(addr)}; + return TexturePair(VideoCommon::ResolveBindlessHandleTable( + *gpu_memory, addr, single_raw, + TexturePair(single_raw, via_header_index).first, tic_limit), + via_header_index); }}; const auto add_image{[&](const auto& desc, bool blacklist) { for (u32 index = 0; index < desc.count; ++index) { diff --git a/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp b/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp index 006bfc0a09..5d48ff8417 100644 --- a/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp +++ b/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp @@ -14,6 +14,7 @@ #include "video_core/renderer_vulkan/pipeline_statistics.h" #include "video_core/renderer_vulkan/vk_buffer_cache.h" #include "video_core/renderer_vulkan/vk_compute_pipeline.h" +#include "video_core/shader_environment.h" #include "video_core/renderer_vulkan/vk_descriptor_pool.h" #include "video_core/renderer_vulkan/vk_pipeline_cache.h" #include "video_core/renderer_vulkan/vk_scheduler.h" @@ -148,24 +149,35 @@ void ComputePipeline::Configure(Tegra::Engines::KeplerCompute& kepler_compute, const auto& qmd{kepler_compute.launch_description}; const auto& cbufs{qmd.const_buffer_config}; const bool via_header_index{qmd.linked_tsc != 0}; + const u32 tic_limit{kepler_compute.regs.tic.limit}; const auto read_handle{[&](const auto& desc, u32 index) { - ASSERT(((qmd.const_buffer_enable_mask >> desc.cbuf_index) & 1) != 0); + const u32 resolved_index{qmd.ResolveConstBufferIndex(desc.cbuf_index)}; + ASSERT(((qmd.const_buffer_enable_mask >> resolved_index) & 1) != 0); const u32 index_offset{index << desc.size_shift}; const u32 offset{desc.cbuf_offset + index_offset}; - const GPUVAddr addr{cbufs[desc.cbuf_index].Address() + offset}; + const GPUVAddr addr{cbufs[resolved_index].Address() + offset}; if constexpr (std::is_same_v || std::is_same_v) { if (desc.has_secondary) { - ASSERT(((qmd.const_buffer_enable_mask >> desc.secondary_cbuf_index) & 1) != 0); + const u32 resolved_secondary{ + qmd.ResolveConstBufferIndex(desc.secondary_cbuf_index)}; + ASSERT(((qmd.const_buffer_enable_mask >> resolved_secondary) & 1) != 0); const u32 secondary_offset{desc.secondary_cbuf_offset + index_offset}; - const GPUVAddr separate_addr{cbufs[desc.secondary_cbuf_index].Address() + + const GPUVAddr separate_addr{cbufs[resolved_secondary].Address() + secondary_offset}; const u32 lhs_raw{gpu_memory.Read(addr) << desc.shift_left}; const u32 rhs_raw{gpu_memory.Read(separate_addr) << desc.secondary_shift_left}; - return TexturePair(lhs_raw | rhs_raw, via_header_index); + const u32 combined{VideoCommon::ResolveBindlessHandleTable( + gpu_memory, addr, lhs_raw | rhs_raw, + TexturePair(lhs_raw | rhs_raw, via_header_index).first, tic_limit)}; + return TexturePair(combined, via_header_index); } } - return TexturePair(gpu_memory.Read(addr), via_header_index); + const u32 single_raw{gpu_memory.Read(addr)}; + return TexturePair(VideoCommon::ResolveBindlessHandleTable( + gpu_memory, addr, single_raw, + TexturePair(single_raw, via_header_index).first, tic_limit), + via_header_index); }}; const auto add_image{[&](const auto& desc, bool blacklist) { for (u32 index = 0; index < desc.count; ++index) { diff --git a/src/video_core/shader_environment.cpp b/src/video_core/shader_environment.cpp index 4d5db7e511..1d075ca8aa 100644 --- a/src/video_core/shader_environment.cpp +++ b/src/video_core/shader_environment.cpp @@ -281,6 +281,34 @@ std::optional GenericEnvironment::TryFindSize() { return std::nullopt; } +u32 ResolveBindlessHandleTable(Tegra::MemoryManager& gpu_memory, GPUVAddr record_addr, + u32 raw_handle, u32 tic_index, u32 tic_limit) { + static constexpr u32 HandleRecordSize = 16; + static constexpr u32 MaxHandleTableBytes = 64 * 1024; + + if (tic_index <= tic_limit) { + return raw_handle; + } + const u32 addr_low{gpu_memory.Read(record_addr)}; + const u32 addr_high{gpu_memory.Read(record_addr + 4)}; + const u32 table_size{gpu_memory.Read(record_addr + 8)}; + const GPUVAddr table_addr{(static_cast(addr_high) << 32) | + static_cast(addr_low)}; + if (table_addr == 0 || table_size < HandleRecordSize || table_size > MaxHandleTableBytes) { + return raw_handle; + } + const u32 count{table_size / HandleRecordSize}; + for (u32 i = 0; i < count; ++i) { + const GPUVAddr entry_addr{table_addr + static_cast(i) * HandleRecordSize}; + const u32 handle{gpu_memory.Read(entry_addr)}; + const u32 live{gpu_memory.Read(entry_addr + 4)}; + if (live != 0 && handle != 0 && handle <= tic_limit) { + return handle; + } + } + return raw_handle; +} + Tegra::Texture::TICEntry GenericEnvironment::ReadTextureInfo(GPUVAddr tic_addr, u32 tic_limit, bool via_header_index, u32 raw) { const auto handle{Tegra::Texture::TexturePair(raw, via_header_index)}; @@ -421,8 +449,9 @@ ComputeEnvironment::ComputeEnvironment(Tegra::Engines::KeplerCompute& kepler_com u32 ComputeEnvironment::ReadCbufValue(u32 cbuf_index, u32 cbuf_offset) { const auto& qmd{kepler_compute->launch_description}; - ASSERT(((qmd.const_buffer_enable_mask.Value() >> cbuf_index) & 1) != 0); - const auto& cbuf{qmd.const_buffer_config[cbuf_index]}; + const u32 resolved_index{qmd.ResolveConstBufferIndex(cbuf_index)}; + ASSERT(((qmd.const_buffer_enable_mask.Value() >> resolved_index) & 1) != 0); + const auto& cbuf{qmd.const_buffer_config[resolved_index]}; u32 value{}; if (cbuf_offset < cbuf.size) { value = gpu_memory->Read(cbuf.Address() + cbuf_offset); @@ -431,6 +460,25 @@ u32 ComputeEnvironment::ReadCbufValue(u32 cbuf_index, u32 cbuf_offset) { return value; } +u32 ComputeEnvironment::ResolveBindlessHandle(u32 cbuf_index, u32 cbuf_offset, u32 raw_handle) { + const auto& regs{kepler_compute->regs}; + const auto& qmd{kepler_compute->launch_description}; + const auto pair{Tegra::Texture::TexturePair(raw_handle, qmd.linked_tsc != 0)}; + if (pair.first <= regs.tic.limit) { + return raw_handle; + } + const u32 resolved_index{qmd.ResolveConstBufferIndex(cbuf_index)}; + if (((qmd.const_buffer_enable_mask.Value() >> resolved_index) & 1) == 0) { + return raw_handle; + } + const auto& cbuf{qmd.const_buffer_config[resolved_index]}; + if (cbuf_offset + 12 > cbuf.size) { + return raw_handle; + } + return ResolveBindlessHandleTable(*gpu_memory, cbuf.Address() + cbuf_offset, raw_handle, + pair.first, regs.tic.limit); +} + Shader::TextureType ComputeEnvironment::ReadTextureType(u32 handle) { const auto& regs{kepler_compute->regs}; const auto& qmd{kepler_compute->launch_description}; diff --git a/src/video_core/shader_environment.h b/src/video_core/shader_environment.h index 95c6d72f89..d0b897c1a4 100644 --- a/src/video_core/shader_environment.h +++ b/src/video_core/shader_environment.h @@ -29,6 +29,9 @@ class Memorymanager; namespace VideoCommon { +[[nodiscard]] u32 ResolveBindlessHandleTable(Tegra::MemoryManager& gpu_memory, GPUVAddr record_addr, + u32 raw_handle, u32 tic_index, u32 tic_limit); + class GenericEnvironment : public Shader::Environment { public: explicit GenericEnvironment() = default; @@ -140,6 +143,8 @@ public: u32 ReadCbufValue(u32 cbuf_index, u32 cbuf_offset) override; + u32 ResolveBindlessHandle(u32 cbuf_index, u32 cbuf_offset, u32 raw_handle) override; + Shader::TextureType ReadTextureType(u32 handle) override; Shader::TexturePixelFormat ReadTexturePixelFormat(u32 handle) override;