From 38d317660cc5aa5fb4825fa0fdfdd9effd6bb223 Mon Sep 17 00:00:00 2001 From: Philip Rebohle Date: Wed, 23 Oct 2024 14:07:49 +0200 Subject: [PATCH] [d3d11] Use existing MD5 hash to look up shader objects Skips the expensive SHA-1 pass. --- src/d3d11/d3d11_device.cpp | 139 +++++++++++++++++++------------------ src/d3d11/d3d11_device.h | 2 +- src/util/sha1/sha1_util.h | 4 ++ 3 files changed, 77 insertions(+), 68 deletions(-) diff --git a/src/d3d11/d3d11_device.cpp b/src/d3d11/d3d11_device.cpp index b2de92ca2a6..bfd0dcb0af1 100644 --- a/src/d3d11/d3d11_device.cpp +++ b/src/d3d11/d3d11_device.cpp @@ -742,13 +742,8 @@ namespace dxvk { moduleInfo.tess = nullptr; moduleInfo.xfb = nullptr; - Sha1Hash hash = Sha1Hash::compute( - pShaderBytecode, BytecodeLength); - - HRESULT hr = CreateShaderModule(&module, - DxvkShaderKey(VK_SHADER_STAGE_VERTEX_BIT, hash), - pShaderBytecode, BytecodeLength, pClassLinkage, - &moduleInfo); + HRESULT hr = CreateShaderModule(&module, VK_SHADER_STAGE_VERTEX_BIT, + pShaderBytecode, BytecodeLength, pClassLinkage, &moduleInfo); if (FAILED(hr)) return hr; @@ -774,13 +769,8 @@ namespace dxvk { moduleInfo.tess = nullptr; moduleInfo.xfb = nullptr; - Sha1Hash hash = Sha1Hash::compute( - pShaderBytecode, BytecodeLength); - - HRESULT hr = CreateShaderModule(&module, - DxvkShaderKey(VK_SHADER_STAGE_GEOMETRY_BIT, hash), - pShaderBytecode, BytecodeLength, pClassLinkage, - &moduleInfo); + HRESULT hr = CreateShaderModule(&module, VK_SHADER_STAGE_GEOMETRY_BIT, + pShaderBytecode, BytecodeLength, pClassLinkage, &moduleInfo); if (FAILED(hr)) return hr; @@ -848,37 +838,15 @@ namespace dxvk { if (RasterizedStream != D3D11_SO_NO_RASTERIZED_STREAM) Logger::err("D3D11: CreateGeometryShaderWithStreamOutput: Rasterized stream not supported"); - - // Compute hash from both the xfb info and the source - // code, because both influence the generated code - DxbcXfbInfo hashXfb = xfb; - - std::vector chunks = {{ - { pShaderBytecode, BytecodeLength }, - { &hashXfb, sizeof(hashXfb) }, - }}; - - for (uint32_t i = 0; i < hashXfb.entryCount; i++) { - const char* semantic = hashXfb.entries[i].semanticName; - - if (semantic) { - chunks.push_back({ semantic, std::strlen(semantic) }); - hashXfb.entries[i].semanticName = nullptr; - } - } - Sha1Hash hash = Sha1Hash::compute(chunks.size(), chunks.data()); - // Create the actual shader module DxbcModuleInfo moduleInfo; moduleInfo.options = m_dxbcOptions; moduleInfo.tess = nullptr; moduleInfo.xfb = &xfb; - HRESULT hr = CreateShaderModule(&module, - DxvkShaderKey(VK_SHADER_STAGE_GEOMETRY_BIT, hash), - pShaderBytecode, BytecodeLength, pClassLinkage, - &moduleInfo); + HRESULT hr = CreateShaderModule(&module, VK_SHADER_STAGE_GEOMETRY_BIT, + pShaderBytecode, BytecodeLength, pClassLinkage, &moduleInfo); if (FAILED(hr)) return E_INVALIDARG; @@ -904,14 +872,8 @@ namespace dxvk { moduleInfo.tess = nullptr; moduleInfo.xfb = nullptr; - Sha1Hash hash = Sha1Hash::compute( - pShaderBytecode, BytecodeLength); - - - HRESULT hr = CreateShaderModule(&module, - DxvkShaderKey(VK_SHADER_STAGE_FRAGMENT_BIT, hash), - pShaderBytecode, BytecodeLength, pClassLinkage, - &moduleInfo); + HRESULT hr = CreateShaderModule(&module, VK_SHADER_STAGE_FRAGMENT_BIT, + pShaderBytecode, BytecodeLength, pClassLinkage, &moduleInfo); if (FAILED(hr)) return hr; @@ -943,11 +905,7 @@ namespace dxvk { if (tessInfo.maxTessFactor >= 8.0f) moduleInfo.tess = &tessInfo; - Sha1Hash hash = Sha1Hash::compute( - pShaderBytecode, BytecodeLength); - - HRESULT hr = CreateShaderModule(&module, - DxvkShaderKey(VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT, hash), + HRESULT hr = CreateShaderModule(&module, VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT, pShaderBytecode, BytecodeLength, pClassLinkage, &moduleInfo); if (FAILED(hr)) @@ -974,11 +932,7 @@ namespace dxvk { moduleInfo.tess = nullptr; moduleInfo.xfb = nullptr; - Sha1Hash hash = Sha1Hash::compute( - pShaderBytecode, BytecodeLength); - - HRESULT hr = CreateShaderModule(&module, - DxvkShaderKey(VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, hash), + HRESULT hr = CreateShaderModule(&module, VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, pShaderBytecode, BytecodeLength, pClassLinkage, &moduleInfo); if (FAILED(hr)) @@ -1005,13 +959,8 @@ namespace dxvk { moduleInfo.tess = nullptr; moduleInfo.xfb = nullptr; - Sha1Hash hash = Sha1Hash::compute( - pShaderBytecode, BytecodeLength); - - HRESULT hr = CreateShaderModule(&module, - DxvkShaderKey(VK_SHADER_STAGE_COMPUTE_BIT, hash), - pShaderBytecode, BytecodeLength, pClassLinkage, - &moduleInfo); + HRESULT hr = CreateShaderModule(&module, VK_SHADER_STAGE_COMPUTE_BIT, + pShaderBytecode, BytecodeLength, pClassLinkage, &moduleInfo); if (FAILED(hr)) return hr; @@ -1952,11 +1901,65 @@ namespace dxvk { return enabled; } - - + + + DxvkShaderKey ComputeShaderKey( + VkShaderStageFlagBits ShaderStage, + const void* pShaderBytecode, + size_t BytecodeLength, + const DxbcModuleInfo* pModuleInfo) { + // DXBC shaders store an MD5 hash within their header, so just + // use that instead of running SHA-1 over the entire binary. + Sha1Digest digest = { }; + + uint32_t header = (uint32_t(ShaderStage) << 24) | uint32_t(BytecodeLength); + std::memcpy(&digest[0], &header, sizeof(header)); + + if (BytecodeLength >= digest.size()) + std::memcpy(&digest[4], reinterpret_cast(pShaderBytecode) + 4, digest.size() - 4u); + + // If transform feedback is enabled, hash that state too since it + // affects the generated shader code, and factor it into the key. + if (pModuleInfo && pModuleInfo->xfb) { + std::vector serialized; + + serialized.push_back(pModuleInfo->xfb->entryCount); + + for (uint32_t i = 0; i < pModuleInfo->xfb->entryCount; i++) { + if (pModuleInfo->xfb->entries[i].semanticName) { + for (uint32_t j = 0; pModuleInfo->xfb->entries[i].semanticName[j]; j++) + serialized.push_back(pModuleInfo->xfb->entries[i].semanticName[j]); + } + + serialized.push_back(pModuleInfo->xfb->entries[i].semanticIndex); + serialized.push_back(pModuleInfo->xfb->entries[i].componentIndex); + serialized.push_back(pModuleInfo->xfb->entries[i].componentCount); + serialized.push_back(pModuleInfo->xfb->entries[i].streamId); + serialized.push_back(pModuleInfo->xfb->entries[i].bufferId); + serialized.push_back(pModuleInfo->xfb->entries[i].offset); + serialized.push_back(pModuleInfo->xfb->entries[i].offset >> 8u); + } + + for (uint32_t i = 0; i < 4u; i++) { + serialized.push_back(pModuleInfo->xfb->strides[i]); + serialized.push_back(pModuleInfo->xfb->strides[i] >> 8u); + } + + serialized.push_back(pModuleInfo->xfb->rasterizedStream); + + Sha1Digest xfbDigest = Sha1Hash::compute(serialized.data(), serialized.size()).digest(); + + for (size_t i = 0; i < xfbDigest.size(); i++) + digest[i] ^= xfbDigest[i]; + } + + return DxvkShaderKey(ShaderStage, Sha1Hash(digest)); + } + + HRESULT D3D11Device::CreateShaderModule( D3D11CommonShader* pShaderModule, - DxvkShaderKey ShaderKey, + VkShaderStageFlagBits ShaderStage, const void* pShaderBytecode, size_t BytecodeLength, ID3D11ClassLinkage* pClassLinkage, @@ -1964,10 +1967,12 @@ namespace dxvk { if (pClassLinkage != nullptr) Logger::warn("D3D11Device::CreateShaderModule: Class linkage not supported"); + DxvkShaderKey shaderKey = ComputeShaderKey(ShaderStage, pShaderBytecode, BytecodeLength, pModuleInfo); + D3D11CommonShader commonShader; HRESULT hr = m_shaderModules.GetShaderModule(this, - &ShaderKey, pModuleInfo, pShaderBytecode, BytecodeLength, + &shaderKey, pModuleInfo, pShaderBytecode, BytecodeLength, &commonShader); if (FAILED(hr)) diff --git a/src/d3d11/d3d11_device.h b/src/d3d11/d3d11_device.h index 92db7e486f1..66ab6dfceec 100644 --- a/src/d3d11/d3d11_device.h +++ b/src/d3d11/d3d11_device.h @@ -484,7 +484,7 @@ namespace dxvk { HRESULT CreateShaderModule( D3D11CommonShader* pShaderModule, - DxvkShaderKey ShaderKey, + VkShaderStageFlagBits ShaderStage, const void* pShaderBytecode, size_t BytecodeLength, ID3D11ClassLinkage* pClassLinkage, diff --git a/src/util/sha1/sha1_util.h b/src/util/sha1/sha1_util.h index 9d83ab8c17e..d243551a472 100644 --- a/src/util/sha1/sha1_util.h +++ b/src/util/sha1/sha1_util.h @@ -29,6 +29,10 @@ namespace dxvk { | uint32_t(m_digest[4 * id + 2]) << 16 | uint32_t(m_digest[4 * id + 3]) << 24; } + + Sha1Digest digest() const { + return m_digest; + } bool operator == (const Sha1Hash& other) const { return !std::memcmp(