/
d3d9_shader.cpp
150 lines (112 loc) · 5.02 KB
/
d3d9_shader.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
#include "d3d9_shader.h"
#include "d3d9_device.h"
#include "d3d9_util.h"
namespace dxvk {
D3D9CommonShader::D3D9CommonShader() {}
D3D9CommonShader::D3D9CommonShader(
D3D9DeviceEx* pDevice,
VkShaderStageFlagBits ShaderStage,
const Sha1Hash* pHash,
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);
DxvkShaderKey shaderKey = { ShaderStage, *pHash };
const std::string name = shaderKey.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 <<= 17;
m_usedRTs = pModule->usedRTs();
m_info = pModule->info();
m_meta = pModule->meta();
m_constants = pModule->constants();
m_shaders[0]->setShaderKey(shaderKey);
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, *pHash });
}
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)
pDevice->GetDXVKDevice()->registerShader(m_shaders[1]);
}
D3D9CommonShader D3D9ShaderModuleSet::GetShaderModule(
D3D9DeviceEx* pDevice,
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();
Sha1Hash hash = Sha1Hash::compute(
pShaderBytecode, info.bytecodeByteLength);
DxvkShaderKey lookupKey = DxvkShaderKey(ShaderStage, hash);
// Use the shader's unique key for the lookup
{ std::unique_lock<std::mutex> lock(m_mutex);
auto entry = m_modules.find(lookupKey);
if (entry != m_modules.end())
return entry->second;
}
// 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.
D3D9CommonShader commonShader(
pDevice, ShaderStage, &hash,
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<std::mutex> lock(m_mutex);
auto status = m_modules.insert({ lookupKey, commonShader });
if (!status.second)
return status.first->second;
}
return commonShader;
}
}