summaryrefslogtreecommitdiffstats
path: root/src/libs/dxvk-native-1.9.2a/src/d3d9/d3d9_shader.cpp
diff options
context:
space:
mode:
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.cpp192
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;
+ }
+ }
+ }
+
+}