Skip to content

Commit

Permalink
[d3d11] Use existing MD5 hash to look up shader objects
Browse files Browse the repository at this point in the history
Skips the expensive SHA-1 pass.
  • Loading branch information
doitsujin committed Oct 23, 2024
1 parent 565af8c commit 38d3176
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 68 deletions.
139 changes: 72 additions & 67 deletions src/d3d11/d3d11_device.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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<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;
Expand All @@ -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;
Expand Down Expand Up @@ -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))
Expand All @@ -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))
Expand All @@ -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;
Expand Down Expand Up @@ -1952,22 +1901,78 @@ 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<const char*>(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<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,
const DxbcModuleInfo* pModuleInfo) {
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))
Expand Down
2 changes: 1 addition & 1 deletion src/d3d11/d3d11_device.h
Original file line number Diff line number Diff line change
Expand Up @@ -484,7 +484,7 @@ namespace dxvk {

HRESULT CreateShaderModule(
D3D11CommonShader* pShaderModule,
DxvkShaderKey ShaderKey,
VkShaderStageFlagBits ShaderStage,
const void* pShaderBytecode,
size_t BytecodeLength,
ID3D11ClassLinkage* pClassLinkage,
Expand Down
4 changes: 4 additions & 0 deletions src/util/sha1/sha1_util.h
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down

0 comments on commit 38d3176

Please sign in to comment.