diff options
| author | Takoroka <137927095+Takoroka@users.noreply.github.com> | 2026-11-01 13:25:40 -0500 |
|---|---|---|
| committer | Takoroka <137927095+Takoroka@users.noreply.github.com> | 2026-11-01 13:25:40 -0500 |
| commit | 235e2f5f5548e20620c247b76586cbb559f4158d (patch) | |
| tree | 4b282626b7d70498cb493653a585ac9d8a4f074c /src/video_core/shader_cache.cpp | |
| parent | 6bde8c20d1f7c020a920e59a989c03822a08445d (diff) | |
| parent | 004ca96531812ea3674273ed568e3a672e664932 (diff) | |
Merge remote-tracking branch 'origin/feat/nx2-mesh-shaders' into test/linux-all-prs
Diffstat (limited to 'src/video_core/shader_cache.cpp')
| -rw-r--r-- | src/video_core/shader_cache.cpp | 27 |
1 files changed, 27 insertions, 0 deletions
diff --git a/src/video_core/shader_cache.cpp b/src/video_core/shader_cache.cpp index dfe80abac3..f03df6bac5 100644 --- a/src/video_core/shader_cache.cpp +++ b/src/video_core/shader_cache.cpp @@ -14,6 +14,7 @@ #include <boost/container/small_vector.hpp> #include "common/assert.h" +#include "common/cityhash.h" #include "shader_recompiler/frontend/maxwell/control_flow.h" #include "shader_recompiler/exception.h" #include "shader_recompiler/object_pool.h" @@ -48,6 +49,22 @@ void ShaderCache::SyncGuestHost() { ShaderCache::ShaderCache(Tegra::MaxwellDeviceMemoryManager& device_memory_) : device_memory{device_memory_} {} +// Task and mesh programs are translated with the mesh registers and the header of the pass-through +// geometry program (per-primitive outputs), so pipelines are keyed by them too. +u64 ShaderCache::MeshStateHash() const { + using Regs = Tegra::Engines::Maxwell3D::Regs; + const auto& regs{maxwell3d->regs}; + std::array<u32, 3 + 20> state{regs.reg_array[Regs::MeshShaderA], regs.reg_array[Regs::MeshShaderB], + regs.reg_array[Regs::MeshInitShader]}; + if (regs.IsShaderConfigEnabled(Regs::ShaderType::Geometry)) { + const auto& geometry{regs.pipelines[static_cast<size_t>(Regs::ShaderType::Geometry)]}; + const GPUVAddr address{(static_cast<u64>(geometry.reserved[0] & 0xff) << 32) | + geometry.reserved[1]}; + gpu_memory->ReadBlockUnsafe(address, state.data() + 3, 20 * sizeof(u32)); + } + return Common::CityHash64(reinterpret_cast<const char*>(state.data()), sizeof(state)) | 1; +} + bool ShaderCache::RefreshStages(std::array<u64, 6>& unique_hashes) try { auto& dirty{maxwell3d->dirty.flags}; if (!dirty[VideoCommon::Dirty::Shaders]) { @@ -57,6 +74,7 @@ bool ShaderCache::RefreshStages(std::array<u64, 6>& unique_hashes) try { const GPUVAddr base_addr{maxwell3d->regs.program_region.Address()}; const bool native = maxwell3d->GetNativeMacroEngine().native_turing; + const bool mesh{native && maxwell3d->regs.IsMeshEnabled()}; for (size_t index = 0; index < Tegra::Engines::Maxwell3D::Regs::MaxShaderProgram; ++index) { if (!maxwell3d->regs.IsShaderConfigEnabled(index)) { unique_hashes[index] = 0; @@ -69,6 +87,11 @@ bool ShaderCache::RefreshStages(std::array<u64, 6>& unique_hashes) try { unique_hashes[index] = 0; continue; } + if (mesh && program == Tegra::Engines::Maxwell3D::Regs::ShaderType::Geometry) { + // A header without code: the mesh program's environment reads its output map. + unique_hashes[index] = 0; + continue; + } const GPUVAddr shader_addr{native ? (static_cast<u64>(shader_config.reserved[0] & 0xff) << 32) | shader_config.reserved[1] : base_addr + shader_config.offset}; @@ -111,6 +134,10 @@ bool ShaderCache::RefreshStages(std::array<u64, 6>& unique_hashes) try { } shader_infos[index] = shader_info; unique_hashes[index] = shader_info->unique_hash; + if (mesh && (program == Tegra::Engines::Maxwell3D::Regs::ShaderType::VertexB || + program == Tegra::Engines::Maxwell3D::Regs::ShaderType::Tessellation)) { + unique_hashes[index] ^= MeshStateHash(); + } } last_shaders_valid = true; return true; |
