diff options
Diffstat (limited to 'src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_shader.cpp')
-rw-r--r-- | src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_shader.cpp | 192 |
1 files changed, 192 insertions, 0 deletions
diff --git a/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_shader.cpp b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_shader.cpp new file mode 100644 index 00000000..8c717db0 --- /dev/null +++ b/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_shader.cpp @@ -0,0 +1,192 @@ +#include "d3d9_shader.h" + +#include "d3d9_device.h" +#include "d3d9_util.h" + +namespace dxvk { + +#ifndef DXVK_NATIVE + typedef HRESULT (STDMETHODCALLTYPE *D3DXDisassembleShader) ( + const void* pShader, + BOOL EnableColorCode, + char* pComments, + ID3DBlob** ppDisassembly); // ppDisassembly is actually a D3DXBUFFER, but it has the exact same vtable as a ID3DBlob at the start. + + D3DXDisassembleShader g_pfnDisassembleShader = nullptr; + + HRESULT DisassembleShader( + const void* pShader, + BOOL EnableColorCode, + char* pComments, + ID3DBlob** ppDisassembly) { + if (g_pfnDisassembleShader == nullptr) { + HMODULE d3d9x = LoadLibraryA("d3dx9.dll"); + + if (d3d9x == nullptr) + d3d9x = LoadLibraryA("d3dx9_43.dll"); + + g_pfnDisassembleShader = + reinterpret_cast<D3DXDisassembleShader>(GetProcAddress(d3d9x, "D3DXDisassembleShader")); + } + + if (g_pfnDisassembleShader == nullptr) + return D3DERR_INVALIDCALL; + + return g_pfnDisassembleShader( + pShader, + EnableColorCode, + pComments, + ppDisassembly); + } +#endif + + + 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)); + + const std::string dumpPath = env::getEnvVar("DXVK_SHADER_DUMP_PATH"); +#ifndef DXVK_NATIVE + // If requested by the user, dump both the raw DXBC + // shader and the compiled SPIR-V module to a file. + 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()); + } + } +#endif + + // 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 <<= 17; + + m_usedRTs = pModule->usedRTs(); + + m_info = pModule->info(); + m_meta = pModule->meta(); + m_constants = pModule->constants(); + + 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) { +#ifdef _WIN32 + std::ofstream dumpStream( + str::tows(str::format(dumpPath, "/", name, ".spv").c_str()).c_str(), + std::ios_base::binary | std::ios_base::trunc); +#else + std::ofstream dumpStream( + str::format(dumpPath, "/", name, ".spv").c_str(), + std::ios_base::binary | std::ios_base::trunc); +#endif + + m_shaders[0]->dump(dumpStream); + } + + pDevice->GetDXVKDevice()->registerShader(m_shaders[0]); + + if (m_shaders[1] != nullptr) + 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; + } + } + } + +} |