GteHLSLShaderFactory.cpp
Go to the documentation of this file.
1 // David Eberly, Geometric Tools, Redmond WA 98052
2 // Copyright (c) 1998-2017
3 // Distributed under the Boost Software License, Version 1.0.
4 // http://www.boost.org/LICENSE_1_0.txt
5 // http://www.geometrictools.com/License/Boost/LICENSE_1_0.txt
6 // File Version: 3.0.1 (2016/09/12)
7 
8 #include <GTEnginePCH.h>
9 #include <LowLevel/GteWrapper.h>
11 using namespace gte;
12 
13 
15  std::string const& entry, std::string const& target,
16  ProgramDefines const& defines, unsigned int compileFlags)
17 {
18  std::ifstream input(filename);
19  if (!input)
20  {
21  WriteLog("Cannot open file " + filename);
22  return HLSLShader();
23  }
24 
25  std::string source = "";
26  while (!input.eof())
27  {
28  std::string line;
29  getline(input, line);
30  source += line + "\n";
31  }
32  input.close();
33 
34  return CompileAndReflect(filename, source, entry, target, defines, compileFlags);
35 }
36 
38  std::string const& source, std::string const& entry, std::string const& target,
39  ProgramDefines const& defines, unsigned int compileFlags)
40 {
41  return CompileAndReflect(name, source, entry, target, defines, compileFlags);
42 }
43 
45  std::string const& name,
46  std::string const& entry,
47  std::string const& target,
48  size_t numBytes,
49  unsigned char const* bytecode)
50 {
51  ID3DBlob* compiledCode = nullptr;
52  HRESULT hr = D3DCreateBlob(numBytes, &compiledCode);
53  if (FAILED(hr))
54  {
55  WriteLog("CreateFromBytecode failed to create blob.");
56  return HLSLShader();
57  }
58 
59  Memcpy(compiledCode->GetBufferPointer(), bytecode, numBytes);
60 
62  if (!ReflectShader(name, entry, target, compiledCode, shader))
63  {
64  // Errors are recorded to a logfile by ReflectShader.
65  shader = HLSLShader();
66  }
67  compiledCode->Release();
68  return shader;
69 }
70 
72  std::string const& source, std::string const& entry,
73  std::string const& target, ProgramDefines const& defines,
74  unsigned int compileFlags)
75 {
76  std::string type = target.substr(0, 3);
77  if (type == "vs_" || type == "gs_" || type == "ps_" || type == "cs_")
78  {
79  ID3DBlob* compiledCode = CompileShader(name, source, entry, target,
80  compileFlags, defines);
81  if (!compiledCode)
82  {
83  // Errors are recorded to a logfile by CompileShader.
84  return HLSLShader();
85  }
86 
88  if (!ReflectShader(name, entry, target, compiledCode, shader))
89  {
90  // Errors are recorded to a logfile by ReflectShader.
91  shader = HLSLShader();
92  }
93  compiledCode->Release();
94  return shader;
95  }
96  else
97  {
98  WriteLog("Invalid target " + target);
99  return HLSLShader();
100  }
101 }
102 
104  std::string const& source, std::string const& entry,
105  std::string const& target, unsigned int compileFlags,
106  ProgramDefines const& defines)
107 {
108  ID3DInclude* include = D3D_COMPILE_STANDARD_FILE_INCLUDE;
109  ID3DBlob* compiledCode = nullptr;
110  ID3DBlob* errors = nullptr;
111 
112  // Repackage the 'defines' for D3DCompile. Prepend a definition based
113  // on the engine's current matrix-vector multiplication convention.
114  auto const& definitions = defines.Get();
115  std::vector<D3D_SHADER_MACRO> localDefinitions(definitions.size() + 2);
116  std::string umvName = "GTE_USE_MAT_VEC";
117  std::string umvValue;
118 #if defined(GTE_USE_MAT_VEC)
119  umvValue = "1";
120 #else
121  umvValue = "0";
122 #endif
123  localDefinitions.front().Name = umvName.c_str();
124  localDefinitions.front().Definition = umvValue.c_str();
125  for (size_t i = 0; i < definitions.size(); ++i)
126  {
127  localDefinitions[i + 1].Name = definitions[i].first.c_str();
128  localDefinitions[i + 1].Definition = definitions[i].second.c_str();
129  }
130  localDefinitions.back().Name = nullptr;
131  localDefinitions.back().Definition = nullptr;
132 
133  if (!(compileFlags & D3DCOMPILE_PACK_MATRIX_ROW_MAJOR)
134  && !(compileFlags & D3DCOMPILE_PACK_MATRIX_COLUMN_MAJOR))
135  {
136  // The matrix storage was not explicitly set. Use the storage
137  // consistent with the CPU storage.
138 #if defined(GTE_USE_ROW_MAJOR)
139  compileFlags |= D3DCOMPILE_PACK_MATRIX_ROW_MAJOR;
140 #else
141  compileFlags |= D3DCOMPILE_PACK_MATRIX_COLUMN_MAJOR;
142 #endif
143  }
144 
145  HRESULT hr = D3DCompile(source.c_str(), source.length(), name.c_str(),
146  localDefinitions.data(), include, entry.c_str(), target.c_str(),
147  compileFlags, 0, &compiledCode, &errors);
148 
149  if (SUCCEEDED(hr))
150  {
151  if (errors)
152  {
153  // The message is a 'warning' from the HLSL compiler.
154  char const* message =
155  static_cast<char const*>(errors->GetBufferPointer());
156 
157  // Write the warning to the output window when the program is
158  // executing through the Microsoft Visual Studio IDE.
159  size_t const length = strlen(message);
160  std::wstring output = L"";
161  for (size_t i = 0; i < length; ++i)
162  {
163  output += static_cast<wchar_t>(message[i]);
164  }
165  output += L'\n';
166  OutputDebugString(output.c_str());
167 
168  WriteLog("D3DCompile warning: " + std::string(message));
169  }
170  }
171  else // FAILED(hr)
172  {
173  if (errors)
174  {
175  // The message is an 'error' from the HLSL compiler.
176  char const* message =
177  static_cast<char const*>(errors->GetBufferPointer());
178  size_t const length = strlen(message);
179 
180  // Write the error to the output window when the program is
181  // executing through the Microsoft Visual Studio IDE.
182  std::wstring output = L"";
183  for (size_t i = 0; i < length; ++i)
184  {
185  output += static_cast<wchar_t>(message[i]);
186  }
187  output += L'\n';
188  OutputDebugString(output.c_str());
189 
190  WriteLog("D3DCompile error: " + std::string(message));
191  }
192  else
193  {
194  // Unknown reason for error.
195  WriteLog("D3DCompile error, hr = " + std::to_string(hr));
196  }
197  }
198 
199  if (errors)
200  {
201  errors->Release();
202  }
203 
204  return compiledCode;
205 }
206 
208  std::string const& entry, std::string const& target,
209  ID3DBlob* compiledCode, HLSLShader& shader)
210 {
211  void const* buffer = compiledCode->GetBufferPointer();
212  size_t numBytes = compiledCode->GetBufferSize();
213  ID3DShaderReflection* reflector = nullptr;
214  HRESULT hr = D3DReflect(buffer, numBytes, IID_ID3DShaderReflection, (void**)&reflector);
215  if (FAILED(hr))
216  {
217  WriteLog("D3DReflect error, hr = " + std::to_string(hr));
218  return false;
219  }
220 
221  bool success =
222  GetDescription(reflector, shader) &&
223  GetInputs(reflector, shader) &&
224  GetOutputs(reflector, shader) &&
225  GetCBuffers(reflector, shader) &&
226  GetBoundResources(reflector, shader);
227 
228  if (success)
229  {
230  shader.SetName(std::string(name));
231  shader.SetEntry(std::string(entry));
232  shader.SetTarget(std::string(target));
233  shader.SetCompiledCode(numBytes, buffer);
234 
235  if (shader.GetDescription().shaderType == D3D11_SHVER_COMPUTE_SHADER)
236  {
237  // The return value of GetThreadGroupSize is numX*numY*numZ, so
238  // it is safe to ignore.
239  UINT numX, numY, numZ;
240  reflector->GetThreadGroupSize(&numX, &numY, &numZ);
241  shader.SetNumThreads(numX, numY, numZ);
242  }
243  }
244 
245  reflector->Release();
246  return success;
247 }
248 
250 {
251  D3D_SHADER_DESC desc;
252  HRESULT hr = reflector->GetDesc(&desc);
253  if (FAILED(hr))
254  {
255  WriteLog("reflector->GetDesc error, hr = " + std::to_string(hr));
256  return false;
257  }
258  shader.SetDescription(desc);
259  return true;
260 }
261 
263 {
264  UINT const numInputs = shader.GetDescription().numInputParameters;
265  for (UINT i = 0; i < numInputs; ++i)
266  {
268  HRESULT hr = reflector->GetInputParameterDesc(i, &spDesc);
269  if (FAILED(hr))
270  {
271  WriteLog("reflector->GetInputParameterDesc error, hr = " +
272  std::to_string(hr));
273  return false;
274  }
275  shader.InsertInput(HLSLParameter(spDesc));
276  }
277  return true;
278 }
279 
281 {
282  UINT const numOutputs = shader.GetDescription().numOutputParameters;
283  for (UINT i = 0; i < numOutputs; ++i)
284  {
286  HRESULT hr = reflector->GetOutputParameterDesc(i, &spDesc);
287  if (FAILED(hr))
288  {
289  WriteLog("reflector->GetOutputParameterDesc error, hr = " +
290  std::to_string(hr));
291  return false;
292  }
293  shader.InsertOutput(HLSLParameter(spDesc));
294  }
295  return true;
296 }
297 
299 {
300  UINT const numCBuffers = shader.GetDescription().numConstantBuffers;
301  for (UINT i = 0; i < numCBuffers; ++i)
302  {
303  ID3DShaderReflectionConstantBuffer* cbuffer = reflector->GetConstantBufferByIndex(i);
304 
305  D3D_SHADER_BUFFER_DESC cbDesc;
306  HRESULT hr = cbuffer->GetDesc(&cbDesc);
307  if (FAILED(hr))
308  {
309  WriteLog("reflector->GetConstantBufferByIndex error, hr = " +
310  std::to_string(hr));
311  return false;
312  }
313 
315  hr = reflector->GetResourceBindingDescByName(cbDesc.Name, &resDesc);
316  if (FAILED(hr))
317  {
318  WriteLog("reflector->GetResourceBindingDescByName error, hr = " +
319  std::to_string(hr));
320  return false;
321  }
322 
323  if (cbDesc.Type == D3D_CT_CBUFFER)
324  {
325  std::vector<HLSLBaseBuffer::Member> members;
326  if (!GetVariables(cbuffer, cbDesc.Variables, members))
327  {
328  return false;
329  }
330 
331  if (resDesc.BindCount == 1)
332  {
333  shader.Insert(HLSLConstantBuffer(resDesc, cbDesc.Size, members));
334  }
335  else
336  {
337  for (UINT j = 0; j < resDesc.BindCount; ++j)
338  {
339  shader.Insert(HLSLConstantBuffer(resDesc, j, cbDesc.Size, members));
340  }
341  }
342  }
343  else if (cbDesc.Type == D3D_CT_TBUFFER)
344  {
345  std::vector<HLSLBaseBuffer::Member> members;
346  if (!GetVariables(cbuffer, cbDesc.Variables, members))
347  {
348  return false;
349  }
350 
351  if (resDesc.BindCount == 1)
352  {
353  shader.Insert(HLSLTextureBuffer(resDesc, cbDesc.Size, members));
354  }
355  else
356  {
357  for (UINT j = 0; j < resDesc.BindCount; ++j)
358  {
359  shader.Insert(HLSLTextureBuffer(resDesc, j,
360  cbDesc.Size, members));
361  }
362  }
363  }
364  else if (cbDesc.Type == D3D_CT_RESOURCE_BIND_INFO)
365  {
366  std::vector<HLSLBaseBuffer::Member> members;
367  if (!GetVariables(cbuffer, cbDesc.Variables, members))
368  {
369  return false;
370  }
371 
372  if (resDesc.BindCount == 1)
373  {
374  shader.Insert(HLSLResourceBindInfo(resDesc, cbDesc.Size, members));
375  }
376  else
377  {
378  for (UINT j = 0; j < resDesc.BindCount; ++j)
379  {
380  shader.Insert(HLSLResourceBindInfo(resDesc, j, cbDesc.Size, members));
381  }
382  }
383  }
384  else // cbDesc.Type == D3D_CT_INTERFACE_POINTERS
385  {
386  WriteLog("Interface pointers are not yet supported in GTEngine.");
387  return false;
388  }
389  }
390  return true;
391 }
392 
394 {
395  // TODO: It appears that D3DCompile never produces a resource with a bind
396  // count larger than 1. For example, "Texture2D texture[2];" comes
397  // through with names "texture[0]" and "texture[1]", each having a bind
398  // count of 1 (with consecutive bind points). So it appears that passing
399  // a bind count in D3D interfaces that is larger than 1 is something a
400  // programmer can do only if he manually combines the texture resources
401  // into his own data structure. If the statement about D3DCompiler is
402  // true, we do not need the loops with upper bound resDesc.BindCount.
403 
404  UINT const numResources = shader.GetDescription().numBoundResources;
405  for (UINT i = 0; i < numResources; ++i)
406  {
408  HRESULT hr = reflector->GetResourceBindingDesc(i, &resDesc);
409  if (FAILED(hr))
410  {
411  WriteLog("reflector->GetResourceBindingDesc error, hr = " + std::to_string(hr));
412  return false;
413  }
414 
415  if (resDesc.Type == D3D_SIT_CBUFFER // cbuffer
416  || resDesc.Type == D3D_SIT_TBUFFER) // tbuffer
417  {
418  // These were processed in the previous loop.
419  }
420  else if (
421  resDesc.Type == D3D_SIT_TEXTURE // Texture*
422  || resDesc.Type == D3D_SIT_UAV_RWTYPED) // RWTexture*
423  {
424  if (IsTextureArray(resDesc.Dimension))
425  {
426  if (resDesc.BindCount == 1)
427  {
428  shader.Insert(HLSLTextureArray(resDesc));
429  }
430  else
431  {
432  for (UINT j = 0; j < resDesc.BindCount; ++j)
433  {
434  shader.Insert(HLSLTextureArray(resDesc, j));
435  }
436  }
437  }
438  else
439  {
440  if (resDesc.BindCount == 1)
441  {
442  shader.Insert(HLSLTexture(resDesc));
443  }
444  else
445  {
446  for (UINT j = 0; j < resDesc.BindCount; ++j)
447  {
448  shader.Insert(HLSLTexture(resDesc, j));
449  }
450  }
451  }
452  }
453  else if (resDesc.Type == D3D_SIT_SAMPLER) // SamplerState
454  {
455  if (resDesc.BindCount == 1)
456  {
457  shader.Insert(HLSLSamplerState(resDesc));
458  }
459  else
460  {
461  for (UINT j = 0; j < resDesc.BindCount; ++j)
462  {
463  shader.Insert(HLSLSamplerState(resDesc, j));
464  }
465  }
466  }
467  else if (
468  resDesc.Type == D3D_SIT_BYTEADDRESS // ByteAddressBuffer
469  || resDesc.Type == D3D_SIT_UAV_RWBYTEADDRESS) // RWByteAddressBuffer
470  {
471  if (resDesc.BindCount == 1)
472  {
473  shader.Insert(HLSLByteAddressBuffer(resDesc));
474  }
475  else
476  {
477  for (UINT j = 0; j < resDesc.BindCount; ++j)
478  {
479  shader.Insert(HLSLByteAddressBuffer(resDesc, j));
480  }
481  }
482  }
483  else
484  {
485  // D3D_SIT_STRUCTURED: StructuredBuffer
486  // D3D_SIT_UAV_RWSTRUCTURED: RWStructuredBuffer
487  // D3D_SIT_UAV_APPEND_STRUCTURED: AppendStructuredBuffer
488  // D3D_SIT_UAV_CONSUME_STRUCTURED: ConsumeStructuredBuffer
489  // D3D_SIT_UAV_RWSTRUCTURED_WITH_COUNTER: RWStructuredBuffer
490 
491  if (resDesc.BindCount == 1)
492  {
493  shader.Insert(HLSLStructuredBuffer(resDesc));
494  }
495  else
496  {
497  for (UINT j = 0; j < resDesc.BindCount; ++j)
498  {
499  shader.Insert(HLSLStructuredBuffer(resDesc, j));
500  }
501  }
502  }
503  }
504 
505  return true;
506 }
507 
510  unsigned int numVariables,
511  std::vector<HLSLBaseBuffer::Member>& members)
512 {
513  for (UINT i = 0; i < numVariables; ++i)
514  {
515  ID3DShaderReflectionVariable* var = cbuffer->GetVariableByIndex(i);
516  ID3DShaderReflectionType* varType = var->GetType();
517 
518  D3D_SHADER_VARIABLE_DESC varDesc;
519  HRESULT hr = var->GetDesc(&varDesc);
520  if (FAILED(hr))
521  {
522  WriteLog("var->GetDesc error, hr = " + std::to_string(hr));
523  return false;
524  }
525 
526  D3D_SHADER_TYPE_DESC varTypeDesc;
527  hr = varType->GetDesc(&varTypeDesc);
528  if (FAILED(hr))
529  {
530  WriteLog("varType->GetDesc error, hr = " + std::to_string(hr));
531  return false;
532  }
533 
534  // Get the top-level information about the shader variable.
535  HLSLShaderVariable svar;
536  svar.SetDescription(varDesc);
537 
538  // Get the type of the variable. If this is a struct type, the
539  // call recurses to build the type tree implied by the struct.
540  HLSLShaderType stype;
541  stype.SetName(svar.GetName());
542  stype.SetDescription(varTypeDesc);
543  if (!GetTypes(varType, varTypeDesc.Members, stype))
544  {
545  return false;
546  }
547 
548  members.push_back(std::make_pair(svar, stype));
549  }
550  return true;
551 }
552 
554  unsigned int numMembers, HLSLShaderType& stype)
555 {
556  for (UINT i = 0; i < numMembers; ++i)
557  {
558  ID3DShaderReflectionType* memType = rtype->GetMemberTypeByIndex(i);
559  char const* memTypeName = rtype->GetMemberTypeName(i);
560  std::string memName(memTypeName ? memTypeName : "");
561  D3D_SHADER_TYPE_DESC memTypeDesc;
562  HRESULT hr = memType->GetDesc(&memTypeDesc);
563  if (FAILED(hr))
564  {
565  WriteLog("memType->GetDesc error, hr = " + std::to_string(hr));
566  return false;
567  }
568  HLSLShaderType& child = stype.GetChild(i);
569  child.SetName(memName);
570  child.SetDescription(memTypeDesc);
571  GetTypes(memType, memTypeDesc.Members, child);
572  }
573  return true;
574 }
575 
576 bool HLSLShaderFactory::IsTextureArray(D3D_SRV_DIMENSION dim)
577 {
578  return dim == D3D_SRV_DIMENSION_TEXTURE1DARRAY
579  || dim == D3D_SRV_DIMENSION_TEXTURE2DARRAY
580  || dim == D3D_SRV_DIMENSION_TEXTURE2DMSARRAY
581  || dim == D3D_SRV_DIMENSION_TEXTURECUBE
582  || dim == D3D_SRV_DIMENSION_TEXTURECUBEARRAY;
583 }
584 
586 {
587  std::ofstream logfile("hlslshaderfactory.log");
588  if (logfile)
589  {
590  logfile << message.c_str() << std::endl;
591  logfile.close();
592  }
593 }
594 
static bool IsTextureArray(D3D_SRV_DIMENSION dim)
void SetDescription(D3D_SHADER_TYPE_DESC const &desc)
D3D_SHADER_VERSION_TYPE shaderType
Definition: GteHLSLShader.h:79
void SetTarget(std::string const &target)
void InsertOutput(HLSLParameter const &parameter)
static bool ReflectShader(std::string const &name, std::string const &entry, std::string const &target, ID3DBlob *compiledCode, HLSLShader &shader)
#define D3D_SHADER_TYPE_DESC
static bool GetInputs(ID3DShaderReflection *reflector, HLSLShader &shader)
std::vector< std::pair< std::string, std::string > > const & Get() const
static HLSLShader CreateFromBytecode(std::string const &name, std::string const &entry, std::string const &target, size_t numBytes, unsigned char const *bytecode)
void SetEntry(std::string const &entry)
#define D3D_SIGNATURE_PARAMETER_DESC
#define ID3DShaderReflectionType
HLSLShaderType & GetChild(unsigned int i)
GLuint const GLchar * name
Definition: glcorearb.h:781
#define D3D_SHADER_VARIABLE_DESC
void SetDescription(D3D_SHADER_DESC const &desc)
GLenum target
Definition: glcorearb.h:1662
static bool GetVariables(ID3DShaderReflectionConstantBuffer *cbuffer, unsigned int numVariables, std::vector< HLSLBaseBuffer::Member > &members)
#define D3D_SHADER_BUFFER_DESC
void SetCompiledCode(size_t numBytes, void const *buffer)
void InsertInput(HLSLParameter const &parameter)
static HLSLShader CreateFromFile(std::string const &filename, std::string const &entry, std::string const &target, ProgramDefines const &defines, unsigned int compileFlags)
GLsizei GLsizei GLchar * source
Definition: glcorearb.h:798
static bool GetOutputs(ID3DShaderReflection *reflector, HLSLShader &shader)
GLsizei const GLchar *const * string
Definition: glcorearb.h:809
void SetNumThreads(unsigned int numXThreads, unsigned int numYThreads, unsigned int numZThreads)
#define D3D_SHADER_INPUT_BIND_DESC
#define IID_ID3DShaderReflection
void SetName(std::string const &name)
static ID3DBlob * CompileShader(std::string const &name, std::string const &source, std::string const &entry, std::string const &target, unsigned int compileFlags, ProgramDefines const &defines)
GLuint GLsizei const GLchar * message
Definition: glcorearb.h:2538
Description const & GetDescription() const
void SetDescription(D3D_SHADER_VARIABLE_DESC const &desc)
std::string const & GetName() const
#define ID3DShaderReflectionConstantBuffer
GLuint GLsizei GLsizei * length
Definition: glcorearb.h:790
GLuint shader
Definition: glcorearb.h:780
#define ID3DShaderReflectionVariable
static HLSLShader CompileAndReflect(std::string const &name, std::string const &source, std::string const &entry, std::string const &target, ProgramDefines const &defines, unsigned int compileFlags)
GLenum GLenum GLenum input
Definition: glext.h:9913
void Memcpy(void *target, void const *source, size_t count)
Definition: GteWrapper.cpp:16
static bool GetCBuffers(ID3DShaderReflection *reflector, HLSLShader &shader)
static bool GetTypes(ID3DShaderReflectionType *rtype, unsigned int numMembers, HLSLShaderType &stype)
void Insert(HLSLConstantBuffer const &cbuffer)
typedef UINT(WINAPI *PFNWGLGETGPUIDSAMDPROC)(UINT maxCount
static bool GetBoundResources(ID3DShaderReflection *reflector, HLSLShader &shader)
GLuint buffer
Definition: glcorearb.h:655
static HLSLShader CreateFromString(std::string const &name, std::string const &source, std::string const &entry, std::string const &target, ProgramDefines const &defines, unsigned int compileFlags)
static void WriteLog(std::string const &message)
#define D3D_SHADER_DESC
void SetName(std::string const &name)
#define ID3DShaderReflection
GLint GLint GLsizei GLint GLenum GLenum type
Definition: glcorearb.h:103
static bool GetDescription(ID3DShaderReflection *reflector, HLSLShader &shader)


geometric_tools_engine
Author(s): Yijiang Huang
autogenerated on Thu Jul 18 2019 04:00:00