Cogs.Core
EffectsD3D12.cpp
1#include "EffectsD3D12.h"
2
3#include <D3Dcompiler.h>
4
5#include "../Base/Utilities.h"
6
7#include "GraphicsDeviceD3D12.h"
8
9namespace
10{
11 Cogs::Logging::Log logger = Cogs::Logging::getLogger("EffectsD3D12");
12
13 void dumpSource(const std::string & src, const std::vector<D3D_SHADER_MACRO> & macros, Cogs::EffectFlags::EEffectFlags effectFlags)
14 {
16 for (size_t i = 0; i < macros.size(); i++) {
17 LOG_DEBUG(logger, "PPM: %s: %s", macros[i].Name, macros[i].Definition);
18 }
19
20 const char* start = src.data();
21 const char* stop;
22 int line = 1;
23 do {
24 stop = start;
25 while ((*stop != '\0') && (*stop != '\n') && (*stop != '\r')) { stop++; }
26
27 LOG_DEBUG(logger, "%3d: %s", line++, std::string(start, stop - start).c_str());
28
29 while ((*stop != '\0') && (*stop != '\n')) { stop++; }
30 while ((*stop != '\0') && (*stop == '\r')) { stop++; }
31
32 start = stop + 1;
33 } while (*stop != '\0');
34 }
35 }
36
37}
38
40{
41 this->effects.removeResource(handle);
42}
43
44HRESULT Cogs::EffectsD3D12::compileShader(const std::string & source, const std::vector<D3D_SHADER_MACRO> & macros, const std::string & entryPoint, const std::string & profile, UINT flags, ID3DBlob ** byteCode, Cogs::EffectFlags::EEffectFlags effectFlags)
45{
47
48 if (FAILED(D3DCompile(source.c_str(), source.size(), nullptr, macros.data(), nullptr, entryPoint.c_str(), profile.c_str(), flags, 0, byteCode, errorBlob.internalPointer()))) {
49 dumpSource(source, macros, effectFlags);
50
51 LOG_ERROR(logger, "%s", errorBlob->GetBufferPointer());
52
53 return E_FAIL;
54 } else if (errorBlob) {
55 dumpSource(source, macros, effectFlags);
56
57 LOG_WARNING(logger, "%s", errorBlob->GetBufferPointer());
58 }
59
60 return S_OK;
61}
62
63void Cogs::EffectsD3D12::setDevice(const ResourcePointer<ID3D12Device>& device, GraphicsDeviceD3D12 * graphicsDevice)
64{
65 this->device = device;
66 this->persistentEffects = 0;
67 this->graphicsDevice = graphicsDevice;
68
69 EffectsCommon::initialize(graphicsDevice->getBuffers());
70}
71
73{
74 return this->loadComputeEffect(fileName, PreprocessorDefinitions(), effectFlags);
75}
76
78{
79 ProcessedContent csSource;
80 Utilities::readFile(handler, fileName, csSource);
81
82 EffectD3D12 effect;
84
85 std::vector<D3D_SHADER_MACRO> macros(defines.size() + 1);
86
87 for (size_t i = 0; i < defines.size(); ++i) {
88 D3D_SHADER_MACRO macro = { defines[i].first.c_str(), defines[i].second.c_str() };
89 macros[i] = macro;
90 }
91
92#ifdef _DEBUG
93 UINT flags = D3DCOMPILE_OPTIMIZATION_LEVEL0 | D3DCOMPILE_ENABLE_BACKWARDS_COMPATIBILITY | D3DCOMPILE_DEBUG | D3DCOMPILE_PACK_MATRIX_ROW_MAJOR;
94#else
95 UINT flags = D3DCOMPILE_OPTIMIZATION_LEVEL3 | D3DCOMPILE_ENABLE_BACKWARDS_COMPATIBILITY | D3DCOMPILE_PACK_MATRIX_ROW_MAJOR;
96#endif
97
98 if (FAILED(D3DCompile(csSource.content.c_str(), csSource.content.size(), nullptr, macros.data(), nullptr, "main", "cs_5_0", flags, 0, effect.computeShader.byteCode.internalPointer(), errorBlob.internalPointer()))) {
99 LOG_ERROR(logger, "%s", errorBlob->GetBufferPointer());
101 } else if (errorBlob) {
102 LOG_WARNING(logger, "%s", errorBlob->GetBufferPointer());
103 }
104
105 reflectShader(effect.computeShader);
106
107 return effects.addResource(effect);
108}
109
110Cogs::EffectHandle Cogs::EffectsD3D12::load(const ProcessedContent & vsSource,
111 const ProcessedContent & hsSource,
112 const ProcessedContent & dsSource,
113 const ProcessedContent & gsSource,
114 const ProcessedContent & psSource,
115 const StringView & vsEntryPoint,
116 const StringView & hsEntryPoint,
117 const StringView & dsEntryPoint,
118 const StringView & gsEntryPoint,
119 const StringView & psEntryPoint,
120 const EffectDescription & desc)
121{
123 std::vector<D3D_SHADER_MACRO> macros(desc.definitions.size() + 1);
124
125 for (size_t i = 0; i < desc.definitions.size(); ++i) {
126 D3D_SHADER_MACRO macro = { desc.definitions[i].first.c_str(), desc.definitions[i].second.c_str() };
127 macros[i] = macro;
128 }
129
130#ifdef _DEBUG
131 UINT flags = D3DCOMPILE_OPTIMIZATION_LEVEL0 | D3DCOMPILE_ENABLE_BACKWARDS_COMPATIBILITY | D3DCOMPILE_DEBUG | D3DCOMPILE_PACK_MATRIX_ROW_MAJOR;
132#else
133 UINT flags = D3DCOMPILE_OPTIMIZATION_LEVEL3 | D3DCOMPILE_ENABLE_BACKWARDS_COMPATIBILITY | D3DCOMPILE_PACK_MATRIX_ROW_MAJOR;
134#endif
135
136 const char * profiles[ShaderType::NumShaderTypes] = { "vs_5_0", "hs_5_0", "ds_5_0", "gs_5_0", "ps_5_0" };
137 const ProcessedContent * sources[ShaderType::NumShaderTypes] = { &vsSource, &hsSource, &dsSource, &gsSource, &psSource };
138 const StringView * entryPoints[ShaderType::NumShaderTypes] = { &vsEntryPoint, &hsEntryPoint, &dsEntryPoint, &gsEntryPoint, &psEntryPoint };
139 ResourcePointer<ID3DBlob> byteCode[ShaderType::NumShaderTypes];
140
141 EffectD3D12 effect;
142 for (int i = 0; i < ShaderType::NumShaderTypes; i++) {
143 if (sources[i]->content.empty()) {
144 continue;
145 }
146
147 if (FAILED(D3DCompile(sources[i]->content.c_str(),
148 sources[i]->content.size(),
149 nullptr,
150 macros.data(),
151 nullptr,
152 entryPoints[i]->data(),
153 profiles[i],
154 flags, 0, byteCode[i].internalPointer(), errorBlob.internalPointer())))
155 {
156 //logCompilerOutput(Rendering::Logging::Category::Error, *sources[i], static_cast<const char*>(errorBlob->GetBufferPointer()));
158 } else if (errorBlob) {
159 //logCompilerOutput(Rendering::Logging::Category::Warning, *sources[i], static_cast<const char*>(errorBlob->GetBufferPointer()));
160 }
161
162 effect.shaders[i].byteCode = &*byteCode[i];
163 effect.shaders[i].byteCode->AddRef();
164
165 reflectShader(effect.shaders[i]);
166 }
167
168 effect.buildSignature();
169
170 effect.rootSignature = createSignature(effect.signature);
171
172 auto handle = this->effects.addResource(effect);
173 if (desc.flags & EffectFlags::Pinned) this->effects.pin(handle);
174 return handle;
175}
176
178{
179 this->effects.clear();
180}
181
182void Cogs::EffectsD3D12::reflectShader(Shader & shader)
183{
184 auto code = shader.byteCode.get<ID3DBlob>();
185
186 ID3D12ShaderReflection * reflector = nullptr;
187 D3DReflect(code->GetBufferPointer(), code->GetBufferSize(), IID_ID3D12ShaderReflection, (void **) &reflector);
188
189 D3D12_SHADER_DESC shaderDesc;
190 reflector->GetDesc(&shaderDesc);
191
192 shader.reflection.constantBuffers.resize(shaderDesc.ConstantBuffers);
193
194 for (UINT i = 0; i < shaderDesc.ConstantBuffers; ++i) {
195 auto constantBufferReflect = reflector->GetConstantBufferByIndex(i);
196 auto & constantBuffer = shader.reflection.constantBuffers[i];
197 constantBuffer.slot = i;
198 constantBuffer.dirty = true;
199
200 D3D12_SHADER_BUFFER_DESC cbDesc;
201 constantBufferReflect->GetDesc(&cbDesc);
202
203 shader.reflection.slots[StringId(cbDesc.Name)] = i;
204
205 constantBuffer.memoryBuffer.resize(cbDesc.Size);
206
207 constantBuffer.buffer = graphicsDevice->buffers.loadBuffer(nullptr, cbDesc.Size, Usage::Default, AccessMode::Write, BindFlags::ConstantBuffer);
208
209 constantBuffer.offsets.resize(cbDesc.Variables);
210 constantBuffer.sizes.resize(cbDesc.Variables);
211
212 for (UINT j = 0; j < cbDesc.Variables; ++j) {
213 auto variable = constantBufferReflect->GetVariableByIndex(j);
214
215 D3D12_SHADER_VARIABLE_DESC vDesc;
216 variable->GetDesc(&vDesc);
217
218 D3D12_SHADER_TYPE_DESC tDesc;
219 variable->GetType()->GetDesc(&tDesc);
220
221 constantBuffer.variables[StringId(vDesc.Name)] = static_cast<uint16_t>(j);
222 constantBuffer.offsets[j] = vDesc.StartOffset;
223 constantBuffer.sizes[j] = vDesc.Size;
224 }
225 }
226
227 for (UINT i = 0; i < shaderDesc.BoundResources; ++i) {
228 D3D12_SHADER_INPUT_BIND_DESC iDesc;
229 reflector->GetResourceBindingDesc(i, &iDesc);
230
231 if (iDesc.Type == D3D_SIT_TEXTURE || iDesc.Type == D3D_SIT_UAV_RWTYPED) {
232 shader.reflection.textures[StringId(iDesc.Name)] = iDesc.BindPoint;
233 shader.reflection.srvSlots = std::max(shader.reflection.srvSlots, iDesc.BindPoint + 1);
234 } else if (iDesc.Type == D3D_SIT_SAMPLER) {
235 shader.reflection.samplers[StringId(iDesc.Name)] = iDesc.BindPoint;
236 } else if (iDesc.Type == D3D_SIT_UAV_RWSTRUCTURED || iDesc.Type == D3D_SIT_UAV_RWBYTEADDRESS || iDesc.Type == D3D_SIT_UAV_RWSTRUCTURED_WITH_COUNTER) {
237 shader.reflection.bufferUAVs[StringId(iDesc.Name)] = iDesc.BindPoint;
238 } else if (iDesc.Type == D3D_SIT_STRUCTURED || iDesc.Type == D3D_SIT_BYTEADDRESS) {
239 shader.reflection.bufferSRVs[StringId(iDesc.Name)] = iDesc.BindPoint;
240 shader.reflection.srvSlots = std::max(shader.reflection.srvSlots, iDesc.BindPoint + 1);
241 }
242 }
243}
244
245Cogs::ResourcePointer<ID3D12RootSignature> Cogs::EffectsD3D12::createSignature(EffectSignature & signature)
246{
247 const D3D12_DESCRIPTOR_RANGE_TYPE rangeTypes[] = {
248 D3D12_DESCRIPTOR_RANGE_TYPE_CBV,
249 D3D12_DESCRIPTOR_RANGE_TYPE_SRV,
250 D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER,
251 D3D12_DESCRIPTOR_RANGE_TYPE_UAV,
252 };
253
254 const D3D12_SHADER_VISIBILITY shaderVisibilities[] = {
255 D3D12_SHADER_VISIBILITY_VERTEX,
256 D3D12_SHADER_VISIBILITY_HULL,
257 D3D12_SHADER_VISIBILITY_DOMAIN,
258 D3D12_SHADER_VISIBILITY_GEOMETRY,
259 D3D12_SHADER_VISIBILITY_PIXEL
260 };
261
262 std::vector<CD3DX12_DESCRIPTOR_RANGE> ranges(size_t(SlotType::NumSlotTypes) * size_t(ShaderType::NumShaderTypes));
263 std::vector<CD3DX12_ROOT_PARAMETER> slotRootParameter;
264
265 for (uint32_t i = 0; i < SlotType::NumSlotTypes; ++i) {
266 for (uint32_t j = 0; j < ShaderType::NumShaderTypes; ++j) {
267 auto & rangeDesc = ranges[i * ShaderType::NumShaderTypes + j];
268
269 auto & slots = signature.slots[i].values[j];
270
271 if (slots) {
272 rangeDesc.Init(rangeTypes[i], slots, 0);
273
274 slotRootParameter.emplace_back();
275
276 auto & parameter = slotRootParameter.back();
277 parameter.InitAsDescriptorTable(1, &rangeDesc, shaderVisibilities[j]);
278 }
279 }
280 }
281
282 const D3D12_ROOT_SIGNATURE_FLAGS rootSignatureFlags = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT;
283
284 CD3DX12_ROOT_SIGNATURE_DESC descRootSignature;
285 descRootSignature.Init(static_cast<UINT>(slotRootParameter.size()), slotRootParameter.data(), 0, nullptr, rootSignatureFlags);
286
287 ResourcePointer<ID3D12RootSignature> rootSignature;
288 ResourcePointer<ID3DBlob> pOutBlob;
289 ResourcePointer<ID3DBlob> pErrorBlob;
290 if (FAILED(D3D12SerializeRootSignature(&descRootSignature, D3D_ROOT_SIGNATURE_VERSION_1, pOutBlob.internalPointer(), pErrorBlob.internalPointer()))) {
291 LOG_ERROR(logger, "Could not serialize root signature: %s", pErrorBlob->GetBufferPointer());
292
293 return nullptr;
294 }
295
296 if (FAILED(device->CreateRootSignature(0, pOutBlob->GetBufferPointer(), pOutBlob->GetBufferSize(), IID_PPV_ARGS(rootSignature.internalPointer())))) {
297 LOG_ERROR(logger, "Could not create root signature.");
298
299 return nullptr;
300 }
301
302 return rootSignature;
303}
Log implementation class.
Definition: LogManager.h:139
Provides a weakly referenced view over the contents of a string.
Definition: StringView.h:24
constexpr Log getLogger(const char(&name)[LEN]) noexcept
Definition: LogManager.h:180
std::vector< PreprocessorDefinition > PreprocessorDefinitions
A set of preprocessor definitions.
Definition: IEffects.h:13
@ Write
The buffer can be mapped and written to by the CPU after creation.
Definition: Flags.h:50
@ ConstantBuffer
The buffer can be bound as input to effects as a constant buffer.
Definition: Flags.h:72
Contains an effect description used to load a single effect.
Definition: IEffects.h:55
EEffectFlags
Effect source flags.
Definition: IEffects.h:20
@ LogShaderSource
Log the contents of the shader on error.
Definition: IEffects.h:34
@ Pinned
Effect can only be released explicitly, not using releaseResources().
Definition: IEffects.h:30
void releaseResources()
Release all allocated effect resources.
void releaseEffect(EffectHandle handle)
Release the effect with the given handle, freeing all resources generated during program loading.
EffectHandle loadComputeEffect(const StringView &fileName, EffectFlags::EEffectFlags effectFlags) override
Load the compute shader with the given file name and create an effect.
static const Handle_t InvalidHandle
Represents an invalid handle.
Definition: Common.h:80
@ Default
Default usage.
Definition: Flags.h:26