1
0
mirror of https://github.com/doitsujin/dxvk.git synced 2024-12-14 09:23:53 +01:00
dxvk/src/d3d9/d3d9_shader.cpp

152 lines
5.1 KiB
C++

#include "d3d9_shader.h"
#include "d3d9_caps.h"
#include "d3d9_device.h"
#include "d3d9_util.h"
namespace dxvk {
D3D9CommonShader::D3D9CommonShader() {}
D3D9CommonShader::D3D9CommonShader(
D3D9DeviceEx* pDevice,
VkShaderStageFlagBits ShaderStage,
const DxvkShaderKey& Key,
const DxsoModuleInfo* pDxsoModuleInfo,
const void* pShaderBytecode,
const DxsoAnalysisInfo& AnalysisInfo,
DxsoModule* pModule) {
const uint32_t bytecodeLength = AnalysisInfo.bytecodeByteLength;
m_bytecode.resize(bytecodeLength);
std::memcpy(m_bytecode.data(), pShaderBytecode, bytecodeLength);
const std::string name = Key.toString();
Logger::debug(str::format("Compiling shader ", name));
// If requested by the user, dump both the raw DXBC
// shader and the compiled SPIR-V module to a file.
const std::string dumpPath = env::getEnvVar("DXVK_SHADER_DUMP_PATH");
if (dumpPath.size() != 0) {
DxsoReader reader(
reinterpret_cast<const char*>(pShaderBytecode));
reader.store(std::ofstream(str::tows(str::format(dumpPath, "/", name, ".dxso").c_str()).c_str(),
std::ios_base::binary | std::ios_base::trunc), bytecodeLength);
char comment[2048];
Com<ID3DBlob> blob;
HRESULT hr = DisassembleShader(
pShaderBytecode,
TRUE,
comment,
&blob);
if (SUCCEEDED(hr)) {
std::ofstream disassembledOut(str::tows(str::format(dumpPath, "/", name, ".dxso.dis").c_str()).c_str(), std::ios_base::binary | std::ios_base::trunc);
disassembledOut.write(
reinterpret_cast<const char*>(blob->GetBufferPointer()),
blob->GetBufferSize());
}
}
// Decide whether we need to create a pass-through
// geometry shader for vertex shader stream output
const D3D9ConstantLayout& constantLayout = ShaderStage == VK_SHADER_STAGE_VERTEX_BIT
? pDevice->GetVertexConstantLayout()
: pDevice->GetPixelConstantLayout();
m_shaders = pModule->compile(*pDxsoModuleInfo, name, AnalysisInfo, constantLayout);
m_isgn = pModule->isgn();
m_usedSamplers = pModule->usedSamplers();
// Shift up these sampler bits so we can just
// do an or per-draw in the device.
// We shift by 17 because 16 ps samplers + 1 dmap (tess)
if (ShaderStage == VK_SHADER_STAGE_VERTEX_BIT)
m_usedSamplers <<= caps::MaxTexturesPS + 1;
m_usedRTs = pModule->usedRTs();
m_info = pModule->info();
m_meta = pModule->meta();
m_constants = pModule->constants();
m_maxDefinedConst = pModule->maxDefinedConstant();
m_shaders[0]->setShaderKey(Key);
if (m_shaders[1] != nullptr) {
// Lets lie about the shader key type for the state cache.
m_shaders[1]->setShaderKey({ VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT, Key.sha1() });
}
if (dumpPath.size() != 0) {
std::ofstream dumpStream(
str::tows(str::format(dumpPath, "/", name, ".spv").c_str()).c_str(),
std::ios_base::binary | std::ios_base::trunc);
m_shaders[0]->dump(dumpStream);
}
pDevice->GetDXVKDevice()->registerShader(m_shaders[0]);
if (m_shaders[1] != nullptr && m_shaders[1] != m_shaders[0])
pDevice->GetDXVKDevice()->registerShader(m_shaders[1]);
}
void D3D9ShaderModuleSet::GetShaderModule(
D3D9DeviceEx* pDevice,
D3D9CommonShader* pShaderModule,
VkShaderStageFlagBits ShaderStage,
const DxsoModuleInfo* pDxbcModuleInfo,
const void* pShaderBytecode) {
DxsoReader reader(
reinterpret_cast<const char*>(pShaderBytecode));
DxsoModule module(reader);
if (module.info().majorVersion() > pDxbcModuleInfo->options.shaderModel)
throw DxvkError("GetShaderModule: Out of range of supported shader model");
if (module.info().shaderStage() != ShaderStage)
throw DxvkError("GetShaderModule: Bytecode does not match shader stage");
DxsoAnalysisInfo info = module.analyze();
DxvkShaderKey lookupKey = DxvkShaderKey(
ShaderStage,
Sha1Hash::compute(pShaderBytecode, info.bytecodeByteLength));
// Use the shader's unique key for the lookup
{ std::unique_lock<dxvk::mutex> lock(m_mutex);
auto entry = m_modules.find(lookupKey);
if (entry != m_modules.end()) {
*pShaderModule = entry->second;
return;
}
}
// This shader has not been compiled yet, so we have to create a
// new module. This takes a while, so we won't lock the structure.
*pShaderModule = D3D9CommonShader(
pDevice, ShaderStage, lookupKey,
pDxbcModuleInfo, pShaderBytecode,
info, &module);
// Insert the new module into the lookup table. If another thread
// has compiled the same shader in the meantime, we should return
// that object instead and discard the newly created module.
{ std::unique_lock<dxvk::mutex> lock(m_mutex);
auto status = m_modules.insert({ lookupKey, *pShaderModule });
if (!status.second) {
*pShaderModule = status.first->second;
return;
}
}
}
}