Cogs.Core
EffectsD3D11.cpp
1#include "EffectsD3D11.h"
2
3#include "GraphicsDeviceD3D11.h"
4
5#include "../Base/Utilities.h"
6
7#include "Foundation/Logging/Logger.h"
8
9#include <D3Dcompiler.h>
10
11#include <regex>
12#include <fstream>
13#include <sstream>
14
15namespace
16{
17 Cogs::Logging::Log logger = Cogs::Logging::getLogger("EffectsD3D11");
18
19
20 void dumpSource(const Cogs::ProcessedContent content, int firstLine = 1, int lastLine = std::numeric_limits<int>::max())
21 {
22 const char* start = content.content.data();
23 const char* curr = start;
24 int line = 1;
25
26 while ((*curr != '\0') && (line <= lastLine)) {
27 const char* p = curr;
28 while ((*p != '\0') && (*p != '\n') && (*p != '\r')) { p++; }
29
30 if (firstLine <= line) {
31 size_t source = 0;
32 while ((source < content.sourceStop.size()) && (content.sourceStop[source] < static_cast<size_t>(curr - start))) source++;
33
34 if (source < content.sourceStop.size()) {
35 LOG_DEBUG(logger, "%3d(%s): %s", line, content.sourceName[source].c_str(), std::string(curr, p - curr).c_str());
36 } else {
37 LOG_DEBUG(logger, "??: %3d: %s", line, std::string(curr, p - curr).c_str());
38 }
39 }
40
41 line = line + 1;
42
43 curr = p;
44 if (*curr != '\0') { curr++; };
45 if ((*curr != '\0') && (*curr != *p) && ((*curr == '\n') || (*curr == '\r'))) { curr++; }
46 }
47 }
48
49 void logCompilerOutput(Cogs::Logging::Category category, const Cogs::ProcessedContent& content, const char* output, Cogs::EffectFlags::EEffectFlags effectFlags)
50 {
51 const static std::regex outputPattern("^[^(]*\\((\\d+),(\\d+)\\-?(\\d*)\\): (\\S+) X(\\d+): (.+)$");
52
53 std::string compilerMessageLine;
54 std::string t(output);
55 std::stringstream stream(t);
56 std::smatch results;
57
58 while (stream.good()) {
59 std::getline(stream, compilerMessageLine);
60
61 if (std::regex_search(compilerMessageLine, results, outputPattern)) {
62 int line = std::stoi(results[1].str());
63 int col0 = std::stoi(results[2].str());
64 auto col1 = results[3].str().empty() ? col0 : std::stoi(results[3].str());
65 auto cat = results[4].str();
66 int code = std::stoi(results[5].str());
67 auto what = results[6].str();
68
70 dumpSource(content, 1, line);
71 }
72 else {
73 dumpSource(content, line - 3, line);
74 }
75 logger.log(category, Cogs::Logging::ErrorGroup::Unspecified, "HLSL (%d,%d-%d): %s X%d: %s", line, col0, col1, cat.c_str(), code, what.c_str());
76 }
77 else if (!compilerMessageLine.empty()) {
78 LOG_ERROR(logger, "Failed to parse HLSL compiler output.");
79 logger.log(category, Cogs::Logging::ErrorGroup::Unspecified, "%s", output);
80
82 dumpSource(content);
83 }
84 }
85 }
86 }
87
88 void dumpSource(const std::string & src, const std::vector<D3D_SHADER_MACRO> & macros, int firstLine = 1, int lastLine = std::numeric_limits<int>::max())
89 {
90#if 0
91 for (size_t i = 0; i < macros.size(); i++) {
92 LOG_DEBUG(logger, "PPM: %s: %s", macros[i].Name, macros[i].Definition);
93 }
94#else
95 (void)macros.size();
96#endif
97
98 const char* curr = src.data();
99 int line = 1;
100 while ((*curr != '\0') && (line <= lastLine)) {
101 const char* p = curr;
102 while ((*p != '\0') && (*p != '\n') && (*p != '\r')) { p++; }
103
104 if (firstLine <= line) {
105 LOG_DEBUG(logger, "%3d: %s", line, std::string(curr, p - curr).c_str());
106 }
107 line = line + 1;
108
109 curr = p;
110 if (*curr != '\0') { curr++; };
111 if ((*curr != '\0') && (*curr != *p) && ((*curr == '\n') || (*curr == '\r'))) { curr++; }
112 }
113 }
114
115 void logCompilerOutput(Cogs::Logging::Category category, const std::string& src, const std::vector<D3D_SHADER_MACRO> & macros, const char* output)
116 {
117 const static std::regex outputPattern("^[^(]*\\((\\d+),(\\d+)\\-?(\\d*)\\): (\\S+) X(\\d+): (.+)$");
118
119 std::string compilerMessageLine;
120 std::string t(output);
121 std::stringstream stream(t);
122 std::smatch results;
123
124 while (stream.good()) {
125 std::getline(stream, compilerMessageLine);
126
127 if (std::regex_search(compilerMessageLine, results, outputPattern)) {
128 int line = std::stoi(results[1].str());
129 int col0 = std::stoi(results[2].str());
130 auto col1 = results[3].str().empty() ? col0 : std::stoi(results[3].str());
131 auto cat = results[4].str();
132 int code = std::stoi(results[5].str());
133 auto what = results[6].str();
134
135 dumpSource(src, macros, line - 3, line);
136 logger.log(category, Cogs::Logging::ErrorGroup::Unspecified, "HLSL (%d,%d-%d): %s X%d: %s", line, col0, col1, cat.c_str(), code, what.c_str());
137 } else if (!compilerMessageLine.empty()) {
138 LOG_ERROR(logger, "Failed to parse HLSL compiler output.");
139 logger.log(category, Cogs::Logging::ErrorGroup::Unspecified, "%s", output);
140 }
141 }
142 }
143
144#ifdef COGSRENDERING_GFX_ANNOTATE
145 template<typename ShaderType>
146 void doAnnotate(Cogs::Shader & shader, const Cogs::StringView name)
147 {
148 if (shader.shader && !name.empty()) {
149 shader.shader.get<ShaderType>()->SetPrivateData(WKPDID_D3DDebugObjectName, static_cast<UINT>(name.length()), name.data());
150 }
151 }
152#endif
153}
154
155void Cogs::EffectsD3D11::setDevice(GraphicsDeviceD3D11 * graphicsDevice, const ResourcePointer<ID3D11Device> & device)
156{
157 this->graphicsDevice = graphicsDevice;
158 this->device = device;
159
160 EffectsCommon::initialize(graphicsDevice->getBuffers());
161}
162
164{
165#ifdef COGSRENDERING_GFX_ANNOTATE
166 auto nameStr = std::string(name);
167 doAnnotate<ID3D11VertexShader>(effects[handle].vertexShader, nameStr +"_VS");
168 doAnnotate<ID3D11GeometryShader>(effects[handle].geometryShader, nameStr + "_GS");
169 doAnnotate<ID3D11PixelShader>(effects[handle].pixelShader, nameStr + "_PS");
170 doAnnotate<ID3D11ComputeShader>(effects[handle].computeShader, nameStr + "_CS");
171#else
172 (void)handle;
173 (void)name;
174#endif
175}
176
178{
179#ifdef COGSRENDERING_GFX_ANNOTATE
180 doAnnotate<ID3D11VertexShader>(effects[handle].vertexShader, name);
181#else
182 (void)handle;
183 (void)name;
184#endif
185}
186
188{
189#ifdef COGSRENDERING_GFX_ANNOTATE
190 doAnnotate<ID3D11GeometryShader>(effects[handle].geometryShader, name);
191#else
192 (void)handle;
193 (void)name;
194#endif
195}
196
198{
199#ifdef COGSRENDERING_GFX_ANNOTATE
200 doAnnotate<ID3D11PixelShader>(effects[handle].pixelShader, name);
201#else
202 (void)handle;
203 (void)name;
204#endif
205}
206
208{
209#ifdef COGSRENDERING_GFX_ANNOTATE
210 doAnnotate<ID3D11ComputeShader>(effects[handle].computeShader, name);
211#else
212 (void)handle;
213 (void)name;
214#endif
215}
216
217
219{
220 this->effects.removeResource(handle);
221}
222
224{
225 return this->loadComputeEffect(fileName, PreprocessorDefinitions(), effectFlags);
226}
227
229{
230 HRESULT hr;
231
232 ProcessedContent csSourceProcessed;
233 Utilities::preprocessFile(handler, fileName, csSourceProcessed);
234
235 Effect effect;
237
238
239 std::vector<D3D_SHADER_MACRO> macros(defines.size() + 1);
240
241 for (size_t i = 0; i < defines.size(); ++i) {
242 D3D_SHADER_MACRO macro = { defines[i].first.c_str(), defines[i].second.c_str() };
243 macros[i] = macro;
244 }
245
246#ifdef _DEBUG
247 UINT flags = D3DCOMPILE_OPTIMIZATION_LEVEL0 | D3DCOMPILE_ENABLE_BACKWARDS_COMPATIBILITY | D3DCOMPILE_DEBUG | D3DCOMPILE_PACK_MATRIX_ROW_MAJOR;
248#else
249 UINT flags = D3DCOMPILE_OPTIMIZATION_LEVEL3 | D3DCOMPILE_ENABLE_BACKWARDS_COMPATIBILITY | D3DCOMPILE_PACK_MATRIX_ROW_MAJOR;
250#endif
251
252 const bool useShaderCache = (graphicsDevice->getSettings().flags & GraphicsDeviceFlags::EnableShaderCache) == GraphicsDeviceFlags::EnableShaderCache;
253 size_t shaderId = 0;
254 std::string cacheName;
256
257 if (useShaderCache) {
258 StringView sourceView(csSourceProcessed.content);
259
260 shaderId = Cogs::hash(flags);
261 shaderId = Cogs::hash(sourceView, shaderId);
262
263 for (const auto & macro : macros) {
264 if (macro.Definition) { // Avoid accessing last empty def.
265 shaderId = Cogs::hash(macro.Definition, shaderId);
266 shaderId = Cogs::hash(macro.Name, shaderId);
267 }
268 }
269
270 cacheName = std::to_string(shaderId) + "cs_5_0.shadercache";
271
272 if (handler->exists(IIOHandler::FileType::ShaderCache, cacheName)) {
273 static thread_local std::vector<uint8_t> shaderCache;
274 shaderCache.clear();
275 handler->openBinaryFile(IIOHandler::FileType::ShaderCache, cacheName, shaderCache);
276
277 uint32_t indices[1] = { 0 };
278 hr = D3DDecompressShaders(shaderCache.data(), shaderCache.size(), 1, 0, indices, 0, byteCode.internalPointer(), nullptr);
279 if (FAILED(hr)) {
280 LOG_ERROR(logger, "Failed to decompress shader cache item %s: %s", cacheName.c_str(), direct3D11ReturnCodeAsString(hr));
281 byteCode->Release();
282 }
283 else if ((graphicsDevice->getSettings().flags & GraphicsDeviceFlags::EnableTraceLogging) == GraphicsDeviceFlags::EnableTraceLogging) {
284 LOG_TRACE(logger, "Retrieved compute shader cache item %s", cacheName.c_str());
285 }
286 }
287 }
288
289 if (!byteCode) {
290 if (FAILED(hr = D3DCompile(csSourceProcessed.content.c_str(),
291 csSourceProcessed.content.size(),
292 (csSourceProcessed.origin.empty() ? nullptr : csSourceProcessed.origin.c_str()),
293 macros.data(),
294 nullptr,
295 "main", "cs_5_0", flags, 0,
296 byteCode.internalPointer(), errorBlob.internalPointer())))
297 {
298 LOG_ERROR(logger, "Failed to compile compute shader: %s", direct3D11ReturnCodeAsString(hr));
299 logCompilerOutput(Logging::Category::Error, csSourceProcessed, static_cast<const char*>(errorBlob->GetBufferPointer()), effectFlags);
301 } else if (errorBlob) {
302 logCompilerOutput(Logging::Category::Warning, csSourceProcessed, static_cast<const char*>(errorBlob->GetBufferPointer()), effectFlags);
303 LOG_WARNING(logger, static_cast<char*>(errorBlob->GetBufferPointer()));
304 }
305
306 if (useShaderCache && shaderId) {
307 D3D_SHADER_DATA shaderData;
308 shaderData.pBytecode = byteCode->GetBufferPointer();
309 shaderData.BytecodeLength = byteCode->GetBufferSize();
310
311 ResourcePointer<ID3DBlob> compressedShader;
312 hr = D3DCompressShaders(1, &shaderData, D3D_COMPRESS_SHADER_KEEP_ALL_PARTS, compressedShader.internalPointer());
313 if (FAILED(hr)) {
314 LOG_WARNING(logger, "Failed to compress shader cache item %s: %s", cacheName.c_str(), direct3D11ReturnCodeAsString(hr));
315 }
316 else {
317 if (!handler->writeBinaryFile(IIOHandler::FileType::ShaderCache,
318 cacheName,
319 compressedShader->GetBufferPointer(),
320 compressedShader->GetBufferSize()))
321 {
322 LOG_WARNING(logger, "Failed to store compute shader cache item %s", cacheName.c_str());
323 }
324 else if ((graphicsDevice->getSettings().flags & GraphicsDeviceFlags::EnableTraceLogging) == GraphicsDeviceFlags::EnableTraceLogging) {
325 LOG_TRACE(logger, "Stored compute shader cache item %s", cacheName.c_str());
326 }
327 }
328 }
329 }
330
331 if (FAILED(hr = device->CreateComputeShader(byteCode->GetBufferPointer(), byteCode->GetBufferSize(), nullptr, (ID3D11ComputeShader **)&effect.computeShader.shader))) {
332 LOG_ERROR(logger, "Failed to create compute shader: %s", direct3D11ReturnCodeAsString(hr));
334 } else {
335 effect.computeShader.byteCode = &*byteCode;
336 effect.computeShader.byteCode->AddRef();
337 }
338
339 reflectShader(effect.computeShader);
340
341#ifdef COGSRENDERING_GFX_ANNOTATE
342 doAnnotate<ID3D11ComputeShader>(effect.computeShader, tryToName(csSourceProcessed.origin));
343#endif
344 if ((graphicsDevice->getSettings().flags & GraphicsDeviceFlags::EnableTraceLogging) == GraphicsDeviceFlags::EnableTraceLogging) {
345 LOG_TRACE(logger, "Created compute shader %p", effect.computeShader.shader.get<void>());
346 }
347
348 return this->effects.addResource(std::move(effect));
349}
350
352{
353 this->effects.clear();
354}
355
356Cogs::EffectHandle Cogs::EffectsD3D11::load(const ProcessedContent & vsSource,
357 const ProcessedContent & hsSource,
358 const ProcessedContent & dsSource,
359 const ProcessedContent & gsSource,
360 const ProcessedContent & psSource,
361 const StringView & vsEntryPoint,
362 const StringView & hsEntryPoint,
363 const StringView & dsEntryPoint,
364 const StringView & gsEntryPoint,
365 const StringView & psEntryPoint,
366 const EffectDescription & desc)
367{
368 HRESULT hr;
370 std::vector<D3D_SHADER_MACRO> macros(desc.definitions.size() + 1);
371
372 for (size_t i = 0; i < desc.definitions.size(); ++i) {
373 D3D_SHADER_MACRO macro = { desc.definitions[i].first.c_str(), desc.definitions[i].second.c_str() };
374 macros[i] = macro;
375 }
376
377#ifdef _DEBUG
378 UINT flags = D3DCOMPILE_OPTIMIZATION_LEVEL0 | D3DCOMPILE_ENABLE_BACKWARDS_COMPATIBILITY | D3DCOMPILE_DEBUG | D3DCOMPILE_PACK_MATRIX_ROW_MAJOR;
379#else
380 UINT flags = D3DCOMPILE_OPTIMIZATION_LEVEL3 | D3DCOMPILE_ENABLE_BACKWARDS_COMPATIBILITY | D3DCOMPILE_PACK_MATRIX_ROW_MAJOR;
381#endif
382
383 const char * profiles[ShaderType::NumShaderTypes] = { "vs_5_0", "hs_5_0", "ds_5_0", "gs_5_0", "ps_5_0" };
384 const ProcessedContent * sources[ShaderType::NumShaderTypes] = { &vsSource, &hsSource, &dsSource, &gsSource, &psSource };
385 const StringView * entryPoints[ShaderType::NumShaderTypes] = {
386 &vsEntryPoint,
387 &hsEntryPoint,
388 &dsEntryPoint,
389 &gsEntryPoint,
390 &psEntryPoint
391 };
392 ResourcePointer<ID3DBlob> byteCode[ShaderType::NumShaderTypes];
393
394 const bool useShaderCache = (graphicsDevice->getSettings().flags & GraphicsDeviceFlags::EnableShaderCache) == GraphicsDeviceFlags::EnableShaderCache;
395 const bool dumpShaderContents = (graphicsDevice->getSettings().flags & GraphicsDeviceFlags::DumpShaderContents) == GraphicsDeviceFlags::DumpShaderContents;
396
397 size_t shaderIds[ShaderType::NumShaderTypes];
398
399 Effect effect;
400 for (int i = 0; i < ShaderType::NumShaderTypes; i++) {
401 if (sources[i]->content.empty()) {
402 continue;
403 }
404
405 size_t shaderId = 0;
406 std::string cacheName;
407
408 if (useShaderCache) {
409 StringView sourceView(sources[i]->content);
410
411 shaderId = Cogs::hash(*entryPoints[i]);
412 shaderId = Cogs::hash(sourceView, shaderId);
413 shaderId = Cogs::hash(flags, shaderId);
414
415 for (const auto & macro : macros) {
416 if (macro.Definition) { // Avoid accessing last empty def.
417 shaderId = Cogs::hash(macro.Definition, shaderId);
418 shaderId = Cogs::hash(macro.Name, shaderId);
419 }
420 }
421
422 shaderIds[i] = shaderId;
423
424 cacheName = std::to_string(shaderId) + profiles[i] + ".shadercache";
425
426 if (handler->exists(IIOHandler::FileType::ShaderCache, cacheName)) {
427 static thread_local std::vector<uint8_t> shaderCache;
428 shaderCache.clear();
429 handler->openBinaryFile(IIOHandler::FileType::ShaderCache, cacheName, shaderCache);
430
431 uint32_t indices[1] = { 0 };
432 assert(byteCode[i] == nullptr && "Leaking memory");
433 hr = D3DDecompressShaders(shaderCache.data(), shaderCache.size(), 1, 0, indices, 0, byteCode[i].internalPointer(), nullptr);
434 if (FAILED(hr)) {
435 LOG_ERROR(logger, "Failed to decompress shader cache item %s: %s", cacheName.c_str(), direct3D11ReturnCodeAsString(hr));
436 byteCode[i]->Release();
437 }
438 else if ((graphicsDevice->getSettings().flags & GraphicsDeviceFlags::EnableTraceLogging) == GraphicsDeviceFlags::EnableTraceLogging){
439 LOG_TRACE(logger, "Retrieved shader cache item %s", cacheName.c_str());
440 }
441 }
442 }
443
444 if (!byteCode[i]) {
445 if (dumpShaderContents && (desc.name.size() || shaderId)) {
446 auto dumpName = desc.name.empty() ? std::to_string(shaderId) + profiles[i] + ".hlsl" : std::string(desc.name) + "." + profiles[i] + ".hlsl";
447 handler->writeBinaryFile(IIOHandler::FileType::ShaderDump, dumpName, sources[i]->content.data(), sources[i]->content.size());
448 }
449
450 if (FAILED(hr = D3DCompile(sources[i]->content.c_str(),
451 sources[i]->content.size(),
452 nullptr,
453 macros.data(),
454 nullptr,
455 entryPoints[i]->data(),
456 profiles[i],
457 flags, 0, byteCode[i].internalPointer(), errorBlob.internalPointer())))
458 {
459 LOG_ERROR(logger, "Failed to compile %s shader: %s", profiles[i], direct3D11ReturnCodeAsString(hr));
460 logCompilerOutput(Logging::Category::Error, *sources[i], static_cast<const char*>(errorBlob->GetBufferPointer()), desc.flags);
462 } else if (errorBlob) {
463 logCompilerOutput(Logging::Category::Warning, *sources[i], static_cast<const char*>(errorBlob->GetBufferPointer()), desc.flags);
464 }
465 if ((graphicsDevice->getSettings().flags & GraphicsDeviceFlags::EnableTraceLogging) == GraphicsDeviceFlags::EnableTraceLogging) {
466 LOG_TRACE(logger, "Built %s shader %zu", profiles[i], shaderId);
467 }
468
469 if (useShaderCache && shaderId) {
470 D3D_SHADER_DATA shaderData;
471 shaderData.pBytecode = byteCode[i]->GetBufferPointer();
472 shaderData.BytecodeLength = byteCode[i]->GetBufferSize();
473
474 ResourcePointer<ID3DBlob> compressedShader;
475 hr = D3DCompressShaders(1, &shaderData, D3D_COMPRESS_SHADER_KEEP_ALL_PARTS, compressedShader.internalPointer());
476 if (FAILED(hr)) {
477 LOG_WARNING(logger, "Failed to compress shader cache item %s: %s", cacheName.c_str(), direct3D11ReturnCodeAsString(hr));
478 }
479 else {
480 if (!handler->writeBinaryFile(IIOHandler::FileType::ShaderCache,
481 cacheName,
482 compressedShader->GetBufferPointer(),
483 compressedShader->GetBufferSize()))
484 {
485
486 LOG_WARNING(logger, "Failed to store compute shader cache item %s", cacheName.c_str());
487 }
488 else if ((graphicsDevice->getSettings().flags & GraphicsDeviceFlags::EnableTraceLogging) == GraphicsDeviceFlags::EnableTraceLogging){
489 LOG_TRACE(logger, "Stored compute shader cache item %s", cacheName.c_str());
490 }
491 }
492 }
493 }
494
495 effect.shaders[i].byteCode = byteCode[i];
496
497 reflectShader(effect.shaders[i]);
498
499#ifdef COGSRENDERING_GFX_ANNOTATE
500 switch (i)
501 {
502 case ShaderType::VertexShader: doAnnotate<ID3D11VertexShader>(effect.shaders[i], tryToName(sources[i]->origin)); break;
503 case ShaderType::HullShader: doAnnotate<ID3D11HullShader>(effect.shaders[i], tryToName(sources[i]->origin)); break;
504 case ShaderType::DomainShader: doAnnotate<ID3D11DomainShader>(effect.shaders[i], tryToName(sources[i]->origin)); break;
505 case ShaderType::GeometryShader: doAnnotate<ID3D11GeometryShader>(effect.shaders[i], tryToName(sources[i]->origin)); break;
506 case ShaderType::PixelShader: doAnnotate<ID3D11PixelShader>(effect.shaders[i], tryToName(sources[i]->origin)); break;
507 case ShaderType::ComputeShader: doAnnotate<ID3D11ComputeShader>(effect.shaders[i], tryToName(sources[i]->origin)); break;
508 default:
509 break;
510 }
511#endif
512 }
513
514 if (dumpShaderContents) {
515 std::string meta;
516 meta.reserve(4096);
517
518 meta.append("{\n");
519
520 meta.append(" \"name\": ");
521
522 meta.append("\"");
523 meta.append(desc.name.empty() ? "N/A" : desc.name.data());
524 meta.append("\"\n");
525
526 if (!desc.definitions.empty()) {
527 meta.append(" \"definitions\": {\n");
528
529 for (auto & d : desc.definitions) {
530 meta.append(" \"");
531 meta.append(d.first);
532 meta.append("\": ");
533
534 meta.append("\"");
535 meta.append(d.second);
536 meta.append("\",\n");
537 }
538
539 meta.append(" },\n");
540 }
541
542 size_t effectId = 0;
543 for (int i = 0; i < ShaderType::NumShaderTypes; i++) {
544 if (sources[i]->content.empty()) {
545 continue;
546 }
547
548 effectId = Cogs::hash(shaderIds[i], effectId);
549
550 meta.append(" \"");
551 meta.append(profiles[i]);
552 meta.append("\": ");
553
554 auto dumpName = desc.name.empty() ? std::to_string(shaderIds[i]) + profiles[i] + ".dump.hlsl" : std::string(desc.name) + "." + profiles[i] + ".hlsl";
555 meta.append("\"");
556 meta.append(dumpName);
557 meta.append("\"\n");
558
559 if (sources[i]->sourceName.size()) {
560 meta.append(" \"");
561 meta.append(profiles[i]);
562 meta.append("_includes\": [\n");
563
564 for (auto & s : sources[i]->sourceName) {
565 if (s == "anonymous") continue;
566
567 meta.append(" \"");
568 meta.append(s);
569 meta.append("\"\n");
570 }
571
572 meta.append(" ],\n");
573 }
574 }
575
576 meta.append("}\n");
577
578 auto metaName = desc.name.empty() ? std::to_string(effectId) + ".json" : std::string(desc.name) + ".d3d11.json";
579 handler->writeBinaryFile(IIOHandler::FileType::ShaderDump, metaName, meta.data(), meta.size());
580 }
581
582 if (FAILED(hr = device->CreateVertexShader(byteCode[0]->GetBufferPointer(), byteCode[0]->GetBufferSize(), nullptr, (ID3D11VertexShader **)&effect.vertexShader.shader))) {
583 LOG_ERROR(logger, "Failed to create vertex shader: %s", direct3D11ReturnCodeAsString(hr));
585 }
586 else if ((graphicsDevice->getSettings().flags & GraphicsDeviceFlags::EnableTraceLogging) == GraphicsDeviceFlags::EnableTraceLogging){
587 LOG_TRACE(logger, "Created vertex shader %p", effect.vertexShader.shader.get<void>());
588 }
589
590 if (!hsSource.content.empty()) {
591 if (FAILED(hr = device->CreateHullShader(byteCode[1]->GetBufferPointer(), byteCode[1]->GetBufferSize(), nullptr, (ID3D11HullShader **)&effect.hullShader.shader))) {
592 LOG_ERROR(logger, "Failed to create hull shader: %s", direct3D11ReturnCodeAsString(hr));
594 }
595 else if ((graphicsDevice->getSettings().flags & GraphicsDeviceFlags::EnableTraceLogging) == GraphicsDeviceFlags::EnableTraceLogging){
596 LOG_TRACE(logger, "Created hull shader %p", effect.hullShader.shader.get<void>());
597 }
598 }
599
600 if (!dsSource.content.empty()) {
601 if (FAILED(hr = device->CreateDomainShader(byteCode[2]->GetBufferPointer(), byteCode[2]->GetBufferSize(), nullptr, (ID3D11DomainShader **)&effect.domainShader.shader))) {
602 LOG_ERROR(logger, "Failed to create domain shader: %s", direct3D11ReturnCodeAsString(hr));
604 }
605 else if ((graphicsDevice->getSettings().flags & GraphicsDeviceFlags::EnableTraceLogging) == GraphicsDeviceFlags::EnableTraceLogging){
606 LOG_TRACE(logger, "Created domain shader %p", effect.domainShader.shader.get<void>());
607 }
608 }
609
610 if (!gsSource.content.empty()) {
611 if (FAILED(hr = device->CreateGeometryShader(byteCode[3]->GetBufferPointer(), byteCode[3]->GetBufferSize(), nullptr, (ID3D11GeometryShader **)&effect.geometryShader.shader))) {
612 LOG_ERROR(logger, "Failed to create geometry shader: %s", direct3D11ReturnCodeAsString(hr));
614 }
615 else if ((graphicsDevice->getSettings().flags & GraphicsDeviceFlags::EnableTraceLogging) == GraphicsDeviceFlags::EnableTraceLogging){
616 LOG_TRACE(logger, "Created geometry shader %p", effect.geometryShader.shader.get<void>());
617 }
618 }
619
620 if (!psSource.content.empty()) {
621 if (FAILED(hr = device->CreatePixelShader(byteCode[4]->GetBufferPointer(), byteCode[4]->GetBufferSize(), nullptr, (ID3D11PixelShader **)&effect.pixelShader.shader))) {
622 LOG_ERROR(logger, "Failed to create pixel shader: %s", direct3D11ReturnCodeAsString(hr));
624 }
625 else if ((graphicsDevice->getSettings().flags & GraphicsDeviceFlags::EnableTraceLogging) == GraphicsDeviceFlags::EnableTraceLogging){
626 LOG_TRACE(logger, "Created pixel shader %p", effect.pixelShader.shader.get<void>());
627 }
628 }
629
630 auto handle = effects.addResource(std::move(effect));
631 if (desc.flags & EffectFlags::Pinned) effects.pin(handle);
632 return handle;
633}
634
635void Cogs::EffectsD3D11::reflectShader(Shader & shader)
636{
637 HRESULT hr;
638 auto code = shader.byteCode.get<ID3DBlob>();
639
641 hr = D3DReflect(code->GetBufferPointer(), code->GetBufferSize(), IID_ID3D11ShaderReflection, (void **) &reflector);
642 if (FAILED(hr)) {
643 LOG_ERROR(logger, "Failed to reflect on bytecode: %s", direct3D11ReturnCodeAsString(hr));
644 return;
645 }
646
647 D3D11_SHADER_DESC shaderDesc;
648 hr = reflector->GetDesc(&shaderDesc);
649 if (FAILED(hr)) {
650 LOG_ERROR(logger, "Failed to get shader description on bytecode: %s", direct3D11ReturnCodeAsString(hr));
651 return;
652 }
653
654 shader.reflection.constantBuffers.resize(shaderDesc.ConstantBuffers);
655
656 for (UINT i = 0; i < shaderDesc.ConstantBuffers; ++i) {
657 auto constantBufferReflect = reflector->GetConstantBufferByIndex(i);
658 auto & constantBuffer = shader.reflection.constantBuffers[i];
659 constantBuffer.slot = i;
660 constantBuffer.dirty = true;
661
662 D3D11_SHADER_BUFFER_DESC cbDesc;
663 hr = constantBufferReflect->GetDesc(&cbDesc);
664 assert(SUCCEEDED(hr));
665
666 shader.reflection.slots[StringId(cbDesc.Name)] = i;
667
668 constantBuffer.memoryBuffer.resize(cbDesc.Size);
669
670 constantBuffer.buffer = graphicsDevice->getBuffers()->loadBuffer(nullptr, cbDesc.Size, Usage::Dynamic, AccessMode::Write, BindFlags::ConstantBuffer);
671
672 constantBuffer.offsets.resize(cbDesc.Variables);
673 constantBuffer.sizes.resize(cbDesc.Variables);
674
675 for (UINT j = 0; j < cbDesc.Variables; ++j) {
676 auto * variable = constantBufferReflect->GetVariableByIndex(j);
677 assert(variable != nullptr);
678
679 D3D11_SHADER_VARIABLE_DESC vDesc;
680 hr = variable->GetDesc(&vDesc);
681 assert(SUCCEEDED(hr));
682
683 D3D11_SHADER_TYPE_DESC tDesc;
684 hr = variable->GetType()->GetDesc(&tDesc);
685 assert(SUCCEEDED(hr));
686
687 constantBuffer.variables[StringId(vDesc.Name)] = static_cast<uint16_t>(j);
688 constantBuffer.offsets[j] = vDesc.StartOffset;
689 constantBuffer.sizes[j] = vDesc.Size;
690 }
691 }
692
693 for (UINT i = 0; i < shaderDesc.BoundResources; ++i) {
694 D3D11_SHADER_INPUT_BIND_DESC iDesc;
695 hr = reflector->GetResourceBindingDesc(i, &iDesc);
696 assert(SUCCEEDED(hr));
697
698 if (iDesc.Type == D3D_SIT_TEXTURE || iDesc.Type == D3D_SIT_UAV_RWTYPED) {
699 shader.reflection.textures[StringId(iDesc.Name)] = iDesc.BindPoint;
700
701 if (iDesc.BindCount > 1) {
702 for (UINT b = 1; b < iDesc.BindCount; ++b) {
703 shader.reflection.textures[StringId(iDesc.Name + std::to_string(b))] = iDesc.BindPoint + b;
704 }
705 }
706 } else if (iDesc.Type == D3D_SIT_UAV_RWSTRUCTURED || iDesc.Type == D3D_SIT_UAV_RWBYTEADDRESS || iDesc.Type == D3D_SIT_UAV_RWSTRUCTURED_WITH_COUNTER) {
707 shader.reflection.bufferUAVs[StringId(iDesc.Name)] = iDesc.BindPoint;
708 } else if (iDesc.Type == D3D_SIT_STRUCTURED || iDesc.Type == D3D_SIT_BYTEADDRESS) {
709 shader.reflection.bufferSRVs[StringId(iDesc.Name)] = iDesc.BindPoint;
710 } else if (iDesc.Type == D3D_SIT_SAMPLER) {
711 shader.reflection.samplers[StringId(iDesc.Name)] = iDesc.BindPoint;
712 } else if (iDesc.Type != D3D_SIT_CBUFFER) {
713 LOG_WARNING(logger, "Unsupported binding type in shader.");
714 return;
715 }
716 }
717}
Log implementation class.
Definition: LogManager.h:139
void log(const Category category, uint32_t errorNumber, _Printf_format_string_ const char *fmt,...) const VALIDATE_ARGS(4)
Log a formatted message.
Definition: LogManager.h:156
Provides a weakly referenced view over the contents of a string.
Definition: StringView.h:24
constexpr const char * data() const noexcept
Get the sequence of characters referenced by the string view.
Definition: StringView.h:171
constexpr size_t length() const noexcept
Get the length of the string.
Definition: StringView.h:185
constexpr bool empty() const noexcept
Check if the string is empty.
Definition: StringView.h:122
constexpr Log getLogger(const char(&name)[LEN]) noexcept
Definition: LogManager.h:180
@ Unspecified
The default error number for legacy logger usage.
Definition: LogManager.h:49
Category
Logging categories used to filter log messages.
Definition: LogManager.h:31
constexpr size_t hash() noexcept
Simple getter function that returns the initial value for fnv1a hashing.
Definition: HashFunctions.h:62
@ DumpShaderContents
Dump shader contents for debugging.
@ EnableShaderCache
Enables using a shader cache to avoid recompiling previously seen shaders.
@ EnableTraceLogging
Enables trace logging.
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
EffectHandle loadComputeEffect(const StringView &fileName, EffectFlags::EEffectFlags effectFlags) override
Load the compute shader with the given file name and create an effect.
void annotateVS(EffectHandle handle, const StringView &name) override
Associate a name with an object for use in graphics debugging.
void annotateGS(EffectHandle handle, const StringView &name) override
Associate a name with an object for use in graphics debugging.
void annotatePS(EffectHandle handle, const StringView &name) override
Associate a name with an object for use in graphics debugging.
void releaseEffect(EffectHandle handle) override
Release the effect with the given handle, freeing all resources generated during program loading.
void releaseResources() override
Release all allocated effect resources.
void annotateCS(EffectHandle handle, const StringView &name) override
Associate a name with an object for use in graphics debugging.
void annotate(EffectHandle handle, const StringView &name) override
Associate a name with an object for use in graphics debugging.
static const Handle_t InvalidHandle
Represents an invalid handle.
Definition: Common.h:80
@ Dynamic
Buffer will be loaded and modified with some frequency.
Definition: Flags.h:30