1
0
mirror of https://github.com/doitsujin/dxvk.git synced 2025-01-19 05:52:11 +01:00

[d3d11] Use existing MD5 hash to look up shader objects

Skips the expensive SHA-1 pass.
This commit is contained in:
Philip Rebohle 2024-10-23 14:07:49 +02:00 committed by Philip Rebohle
parent ae9024492b
commit 800f71c4f5
3 changed files with 85 additions and 68 deletions

View File

@ -791,13 +791,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;
@ -823,13 +818,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;
@ -897,37 +887,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<Sha1Data> 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;
@ -953,14 +921,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;
@ -992,11 +954,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))
@ -1023,11 +981,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))
@ -1054,13 +1008,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;
@ -2008,11 +1957,67 @@ namespace dxvk {
return enabled;
}
DxvkShaderKey D3D11Device::ComputeShaderKey(
VkShaderStageFlagBits ShaderStage,
const void* pShaderBytecode,
size_t BytecodeLength,
const DxbcModuleInfo* pModuleInfo) {
constexpr static uint32_t Md5Size = 16;
// DXBC shaders store an MD5 hash within their header, so just
// use that instead of running SHA-1 over the entire binary.
Sha1Digest digest = { };
if (BytecodeLength >= Md5Size + 4u)
std::memcpy(&digest[0], reinterpret_cast<const char*>(pShaderBytecode) + 4, Md5Size);
uint32_t metadata = uint32_t(ShaderStage) | (uint32_t(BytecodeLength) << 8u);
std::memcpy(&digest[Md5Size], &metadata, sizeof(metadata));
// 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<unsigned char> 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,
@ -2020,10 +2025,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))

View File

@ -511,9 +511,15 @@ namespace dxvk {
D3D_FEATURE_LEVEL m_maxFeatureLevel;
D3D11DeviceFeatures m_deviceFeatures;
DxvkShaderKey ComputeShaderKey(
VkShaderStageFlagBits ShaderStage,
const void* pShaderBytecode,
size_t BytecodeLength,
const DxbcModuleInfo* pModuleInfo);
HRESULT CreateShaderModule(
D3D11CommonShader* pShaderModule,
DxvkShaderKey ShaderKey,
VkShaderStageFlagBits ShaderStage,
const void* pShaderBytecode,
size_t BytecodeLength,
ID3D11ClassLinkage* pClassLinkage,

View File

@ -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(