diff --git a/src/graphics/host_gpu/renderer/pipeline/pipelineCache.cpp b/src/graphics/host_gpu/renderer/pipeline/pipelineCache.cpp index 9bb210fc8..42cc0f6f5 100644 --- a/src/graphics/host_gpu/renderer/pipeline/pipelineCache.cpp +++ b/src/graphics/host_gpu/renderer/pipeline/pipelineCache.cpp @@ -165,6 +165,32 @@ bool ValidateShaderSpirv(const char* label, uint64_t shader_hash, } // namespace +std::size_t PipelineCache::GraphicsPipelineKeyHash::operator()(const GraphicsPipelineKey& key) const { + std::size_t hash = 0; + PipelineKeyHash::Mix(hash, key.rendering.color_count); + for (uint32_t i = 0; i < key.rendering.color_count; i++) { + PipelineKeyHash::Mix(hash, static_cast(key.rendering.color_formats[i])); + } + PipelineKeyHash::Mix(hash, static_cast(key.rendering.depth_format)); + PipelineKeyHash::Mix(hash, static_cast(key.rendering.stencil_format)); + for (const auto id: key.vertex_shader_ids) { + PipelineKeyHash::Mix(hash, id); + } + PipelineKeyHash::Mix(hash, key.ps_shader_id); + PipelineKeyHash::Mix(hash, key.vertex_input.binding_count); + for (uint32_t i = 0; i < key.vertex_input.binding_count; i++) { + PipelineKeyHash::Mix(hash, key.vertex_input.bindings[i].stride); + PipelineKeyHash::Mix(hash, key.vertex_input.bindings[i].instance); + } + PipelineKeyHash::Mix(hash, key.vertex_input.attribute_count); + for (uint32_t i = 0; i < key.vertex_input.attribute_count; i++) { + PipelineKeyHash::Mix(hash, key.vertex_input.attributes[i].offset); + PipelineKeyHash::Mix(hash, key.vertex_input.attributes[i].binding); + } + PipelineKeyHash::Mix(hash, XXH3_64bits(&key.static_params, sizeof(key.static_params))); + return hash; +} + struct PipelineCache::ProgramCache { struct ProgramKey { ShaderType stage = ShaderType::Unknown; @@ -206,12 +232,12 @@ struct PipelineCache::ProgramCache { PipelineKeyHash::Mix(hash, key.code_size); PipelineKeyHash::Mix(hash, key.static_state.size()); // Bucket same-shape static variants by source. ProgramKey equality performs the one - // exact state comparison needed on a stable hit without hashing up to 429 words first. + // exact state comparison needed on a stable hit without hashing the full state first. return hash; } }; - static constexpr std::size_t MaxStaticKeyWords = 13 + ShaderVertexInputInfo::RES_MAX * 13; + static constexpr std::size_t MaxStaticKeyWords = 32 + ShaderVertexInputInfo::RES_MAX * 6; Permutation CompilePermutation(const char* stage_name, const ShaderRecompiler::CompileOptions& options, diff --git a/src/graphics/host_gpu/renderer/pipeline/pipelineCache.h b/src/graphics/host_gpu/renderer/pipeline/pipelineCache.h index 8ecb80dcd..05ace5277 100644 --- a/src/graphics/host_gpu/renderer/pipeline/pipelineCache.h +++ b/src/graphics/host_gpu/renderer/pipeline/pipelineCache.h @@ -166,45 +166,10 @@ private: hash ^= value + static_cast(0x9e3779b97f4a7c15ull) + (hash << 6u) + (hash >> 2u); } - - static void MixStaticParams(std::size_t& hash, const PipelineStaticParameters& params) { - const auto* bytes = reinterpret_cast(¶ms); - for (std::size_t i = 0; i < sizeof(params); i++) { - Mix(hash, bytes[i]); - } - } - - static void MixRendering(std::size_t& hash, const PipelineRenderingState& rendering) { - Mix(hash, rendering.color_count); - for (uint32_t i = 0; i < rendering.color_count; i++) { - Mix(hash, static_cast(rendering.color_formats[i])); - } - Mix(hash, static_cast(rendering.depth_format)); - Mix(hash, static_cast(rendering.stencil_format)); - } }; struct GraphicsPipelineKeyHash { - std::size_t operator()(const GraphicsPipelineKey& key) const { - std::size_t hash = 0; - PipelineKeyHash::MixRendering(hash, key.rendering); - for (const auto id: key.vertex_shader_ids) { - PipelineKeyHash::Mix(hash, id); - } - PipelineKeyHash::Mix(hash, key.ps_shader_id); - PipelineKeyHash::Mix(hash, key.vertex_input.binding_count); - for (uint32_t i = 0; i < key.vertex_input.binding_count; i++) { - PipelineKeyHash::Mix(hash, key.vertex_input.bindings[i].stride); - PipelineKeyHash::Mix(hash, key.vertex_input.bindings[i].instance); - } - PipelineKeyHash::Mix(hash, key.vertex_input.attribute_count); - for (uint32_t i = 0; i < key.vertex_input.attribute_count; i++) { - PipelineKeyHash::Mix(hash, key.vertex_input.attributes[i].offset); - PipelineKeyHash::Mix(hash, key.vertex_input.attributes[i].binding); - } - PipelineKeyHash::MixStaticParams(hash, key.static_params); - return hash; - } + std::size_t operator()(const GraphicsPipelineKey& key) const; }; GraphicContext& m_graphics; diff --git a/src/graphics/shader/shader.cpp b/src/graphics/shader/shader.cpp index e443d35f8..5df85b04a 100644 --- a/src/graphics/shader/shader.cpp +++ b/src/graphics/shader/shader.cpp @@ -668,15 +668,8 @@ void BuildStageStaticKey(const ShaderVertexInputInfo& info, std::vector(destination.attr_id)); - key.push_back(resource.Stride()); - key.push_back(static_cast(resource.SwizzleEnabled())); - key.push_back(resource.DstSelX()); - key.push_back(resource.DstSelY()); - key.push_back(resource.DstSelZ()); - key.push_back(resource.DstSelW()); - key.push_back(resource.RawFormat()); - key.push_back(resource.OutOfBounds()); - key.push_back(static_cast(resource.AddTid())); + key.push_back(resource.fields[1] & 0xbfff0000u); // Stride and swizzle enable. + key.push_back(resource.fields[3] & 0x3087ffffu); // Channels, format, OOB, and add TID. } } diff --git a/tests/shaderCfgTests.cpp b/tests/shaderCfgTests.cpp index 57bc08409..baf134088 100644 --- a/tests/shaderCfgTests.cpp +++ b/tests/shaderCfgTests.cpp @@ -10633,6 +10633,24 @@ void TestNewShaderRecompilerClipDisabledPosition() { layout_b.resources[0].UpdateAddress48(4); Check(MakeStageStaticKey(layout_a) == MakeStageStaticKey(layout_b), "pipeline-only vertex layout fragmented the shader module cache key"); + + const auto descriptor_state = [](const ShaderBufferResource &resource) { + return std::array{ + resource.Stride(), resource.SwizzleEnabled(), resource.DstSelX(), + resource.DstSelY(), resource.DstSelZ(), resource.DstSelW(), + resource.RawFormat(), resource.OutOfBounds(), resource.AddTid()}; + }; + const auto key = MakeStageStaticKey(layout_a); + const auto state = descriptor_state(layout_a.resources[0]); + for (uint32_t word = 0; word < 4; word++) { + for (uint32_t bit = 0; bit < 32; bit++) { + auto changed = layout_a; + changed.resources[0].fields[word] ^= 1u << bit; + Check((MakeStageStaticKey(changed) == key) == + (descriptor_state(changed.resources[0]) == state), + "vertex key lost a descriptor field or included runtime-only bits"); + } + } } void TestNewShaderRecompilerAuxPositionExports() {