DX12Shader.h 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332
  1. #pragma once
  2. #include "Array.h"
  3. #include "DX12Buffer.h"
  4. struct ID3D12Device5;
  5. struct ID3D12GraphicsCommandList;
  6. struct D3D12_INPUT_ELEMENT_DESC;
  7. struct D3D12_ROOT_PARAMETER1;
  8. struct D3D12_CONSTANT_BUFFER_VIEW_DESC;
  9. struct ID3D12StateObjectProperties;
  10. namespace Framework
  11. {
  12. class Texture;
  13. class DX12TLAS;
  14. enum DX12ShaderRegister
  15. {
  16. DX12_SHADER_REGISTER_B_CONST_BUFFER = 0,
  17. DX12_SHADER_REGISTER_T_SHADER_RESOURCE = 1,
  18. DX12_SHADER_REGISTER_U_UNORDERED_ACCESS = 2,
  19. // TODO: Do we need Sampler?
  20. };
  21. struct DX12ShaderRegisterUsage
  22. {
  23. DX12ShaderRegister registerType;
  24. int registerIndex;
  25. int spaceIndex;
  26. int descriptorHeapIndex;
  27. int bindingTableIndex;
  28. };
  29. class DX12ShaderHeap;
  30. class DX12ShaderSignature : public ReferenceCounter
  31. {
  32. private:
  33. ID3D12RootSignature* signature;
  34. Array<DX12ShaderRegisterUsage*> descriptorHeapBindings;
  35. Array<DX12ShaderRegisterUsage*> bindingTableBindings;
  36. bool changed;
  37. int shaderBindingTableParamCount;
  38. public:
  39. DLLEXPORT DX12ShaderSignature();
  40. DLLEXPORT ~DX12ShaderSignature();
  41. /**
  42. * for each datastructure with : register(...) in the shader code,
  43. * either this function or addRegisterUsageLinkedToDescriptorHeap must
  44. * be called to link the register usage to the shader binding table or
  45. * descriptor heap.
  46. *
  47. * \param registerType the register type e.g.
  48. * DX12_SHADER_REGISTER_B_CONST_BUFFER for : register(b0)
  49. * \param registerIndex the register index e.g. 1 for : register(b1)
  50. * \param spaceIndex the optional space index e.g. 3 for : register(b1,
  51. * space3)
  52. * \return pointer to the offset in the shader binding table where this
  53. * parameter needs to be placed. This pointer is only valid after the
  54. * call to createSignature() and should be used to fill the shader
  55. * binding table with the correct GPU addresses of the resources.
  56. */
  57. DLLEXPORT int* addRegisterUsageLinkedToShaderBindingTable(
  58. DX12ShaderRegister registerType,
  59. int registerIndex,
  60. int spaceIndex = 0);
  61. /**
  62. * for each datastructure with : register(...) in the shader code,
  63. * either this function or addRegisterUsageLinkedToDescriptorHeap must
  64. * be called to link the register usage to the shader binding table or
  65. * descriptor heap.
  66. * For optimal performance the registers that are linked to the
  67. * descriptor heaps should be consecutive and use consecutive descriptor
  68. * heap spaces. Example: register(b3), register(b4), register(b5) linked
  69. * to descriptor heap index 2, 3, 4.
  70. *
  71. * \param descriptorHeapIndex the index in the descriptor heap witch
  72. * contains the resource for this register usage
  73. * \param registerType the register type e.g.
  74. * DX12_SHADER_REGISTER_B_CONST_BUFFER for : register(b0)
  75. * \param registerIndex the register index e.g. 1 for : register(b1)
  76. * \param spaceIndex the optional space index e.g. 3 for : register(b1,
  77. * space3)
  78. */
  79. DLLEXPORT void addRegisterUsageLinkedToDescriptorHeap(
  80. int descriptorHeapIndex,
  81. DX12ShaderRegister registerType,
  82. int registerIndex,
  83. int spaceIndex = 0);
  84. /**
  85. * Creates the root signature.
  86. */
  87. DLLEXPORT void createSignature(ID3D12Device5* zDevice,
  88. PFN_D3D12_SERIALIZE_ROOT_SIGNATURE pfnD3D12SerializeRootSignature);
  89. DLLEXPORT ID3D12RootSignature* zSignature() const;
  90. DLLEXPORT const Array<DX12ShaderRegisterUsage*>&
  91. getDescriptorHeapBindings() const;
  92. DLLEXPORT int gerShaderBindingTableParamCount() const;
  93. };
  94. enum DX12ShaderFunctionType
  95. {
  96. DX12_SHADER_FUNCTION_TYPE_RAY_GEN,
  97. DX12_SHADER_FUNCTION_TYPE_INTERSECTION,
  98. DX12_SHADER_FUNCTION_TYPE_ANY_HIT,
  99. DX12_SHADER_FUNCTION_TYPE_CLOSEST_HIT,
  100. DX12_SHADER_FUNCTION_TYPE_MISS,
  101. DX12_SHADER_FUNCTION_TYPE_CALLABLE,
  102. };
  103. class DX12ShaderFunction : public ReferenceCounter
  104. {
  105. private:
  106. Text functionName;
  107. DX12ShaderSignature* signature;
  108. D3D12_EXPORT_DESC* exportDesc;
  109. DX12ShaderFunctionType functionType;
  110. public:
  111. DLLEXPORT DX12ShaderFunction(const Text& functionName,
  112. DX12ShaderSignature* signature,
  113. DX12ShaderFunctionType functionType);
  114. DLLEXPORT ~DX12ShaderFunction();
  115. DLLEXPORT const Text& getFunctionName() const;
  116. DLLEXPORT DX12ShaderSignature* zSignature() const;
  117. DLLEXPORT D3D12_EXPORT_DESC* zExportDesc() const;
  118. DLLEXPORT DX12ShaderFunctionType getFunctionType() const;
  119. };
  120. class DX12Shader : public ReferenceCounter
  121. {
  122. private:
  123. RCArray<DX12ShaderFunction> functions;
  124. const unsigned char* shaderBytes;
  125. int shaderBytesSize;
  126. D3D12_DXIL_LIBRARY_DESC* libraryDesc;
  127. public:
  128. DLLEXPORT DX12Shader(
  129. const unsigned char* shaderBytes, int shaderBytesSize);
  130. DLLEXPORT ~DX12Shader();
  131. DLLEXPORT void addFunction(DX12ShaderFunction* function);
  132. DLLEXPORT int getShaderBytesSize() const;
  133. DLLEXPORT const unsigned char* getShaderBytes() const;
  134. DLLEXPORT const RCArray<DX12ShaderFunction>& getFunctions() const;
  135. DLLEXPORT D3D12_DXIL_LIBRARY_DESC* zLibraryDesc() const;
  136. };
  137. class DX12ShaderHitGroup : public ReferenceCounter
  138. {
  139. private:
  140. Text name;
  141. DX12ShaderFunction* closestHitShaderFunction;
  142. DX12ShaderFunction* anyHitShaderFunction;
  143. DX12ShaderFunction* intersectionShaderFunction;
  144. int payloadSize;
  145. int attributeSize;
  146. D3D12_HIT_GROUP_DESC* hitGroupDesc;
  147. public:
  148. DLLEXPORT DX12ShaderHitGroup(const Text name);
  149. DLLEXPORT ~DX12ShaderHitGroup();
  150. DLLEXPORT void setClosestHitShaderFunction(
  151. DX12ShaderFunction* zClosestHitShaderFunction);
  152. DLLEXPORT void setAnyHitShaderFunction(
  153. DX12ShaderFunction* zAnyHitShaderFunction);
  154. DLLEXPORT void setIntersectionShaderFunction(
  155. DX12ShaderFunction* zIntersectionShaderFunction);
  156. DLLEXPORT void setPayloadSize(int payloadSize);
  157. DLLEXPORT void setAttributeSize(int attributeSize);
  158. DLLEXPORT const Text& getName() const;
  159. DLLEXPORT DX12ShaderFunction* zClosestHitShaderFunction() const;
  160. DLLEXPORT DX12ShaderFunction* zAnyHitShaderFunction() const;
  161. DLLEXPORT DX12ShaderFunction* zIntersectionShaderFunction() const;
  162. DLLEXPORT int getPayloadSize() const;
  163. DLLEXPORT int getAttributeSize() const;
  164. DLLEXPORT D3D12_HIT_GROUP_DESC* zHitGroupDesc() const;
  165. DLLEXPORT DX12ShaderSignature* zSignature() const;
  166. };
  167. class DX12ShaderBindingTable;
  168. class DX12GlobalDescriptorHeap;
  169. class DX12Pipeline : public ReferenceCounter
  170. {
  171. private:
  172. RCArray<DX12Shader> shaders;
  173. RCArray<DX12ShaderHitGroup> hitGroups;
  174. Array<const DX12ShaderFunction*> functionsWithoutHitGroups;
  175. ID3D12RootSignature* emptyGlobalRootSignature;
  176. ID3D12RootSignature* emptyLocalRootSignature;
  177. ID3D12StateObject* pipelineState;
  178. int maxRecursionDepth;
  179. public:
  180. DLLEXPORT DX12Pipeline();
  181. DLLEXPORT ~DX12Pipeline();
  182. DLLEXPORT void addShader(DX12Shader* shader);
  183. DLLEXPORT void addHitGroup(DX12ShaderHitGroup* hitGroup);
  184. DLLEXPORT void setMaxRecursionDepth(int maxRecursionDepth);
  185. DLLEXPORT void createPipelineState(ID3D12Device5* zDevice,
  186. PFN_D3D12_SERIALIZE_ROOT_SIGNATURE pfnD3D12SerializeRootSignature);
  187. DLLEXPORT ID3D12StateObject* zPipelineState() const;
  188. DLLEXPORT DX12ShaderBindingTable* createShaderBindingTable();
  189. DLLEXPORT DX12GlobalDescriptorHeap* createGlobalDescriptorHeap();
  190. DLLEXPORT const RCArray<DX12Shader>& getShaders() const;
  191. DLLEXPORT const Array<const DX12ShaderFunction*>&
  192. getFunctionsWithoutHitGroups() const;
  193. DLLEXPORT const RCArray<DX12ShaderHitGroup>& getHitGroups() const;
  194. }; // namespace Framework
  195. struct DX12ShaderRegisterInput
  196. {
  197. DX12ShaderRegister registerType;
  198. ReferenceCounter*
  199. inputResource; // Can be Texture*, DXBuffer*, or DX12TLAS*
  200. };
  201. class DX12GlobalDescriptorHeap : public ReferenceCounter
  202. {
  203. private:
  204. DX12Pipeline* pipeline;
  205. ID3D12DescriptorHeap* descriptorHeap;
  206. Array<DX12ShaderRegisterInput*> registerInputs;
  207. int lastDescriptorHeapSize;
  208. ID3D12Device5* zDevice;
  209. public:
  210. DX12GlobalDescriptorHeap(DX12Pipeline* pipeline);
  211. ~DX12GlobalDescriptorHeap();
  212. private:
  213. DLLEXPORT void addInput(
  214. DX12ShaderRegister type, ReferenceCounter* inputResource);
  215. public:
  216. DLLEXPORT void addTextureInput(
  217. DX12ShaderRegister type, Texture* zTexture);
  218. DLLEXPORT void updateTextureInput(
  219. int heapIndex, DX12ShaderRegister type, Texture* zTexture);
  220. DLLEXPORT void addBufferInput(
  221. DX12ShaderRegister type, DXBuffer* zBuffer);
  222. DLLEXPORT void addTLASInput(DX12ShaderRegister type, DX12TLAS* zTLAS);
  223. DLLEXPORT void updateDescriptorHeap(ID3D12Device5* zDevice);
  224. DLLEXPORT DX12Pipeline* zPipeline() const;
  225. DLLEXPORT ID3D12DescriptorHeap* zDescriptorHeap() const;
  226. };
  227. class DX12ShaderBindingTable : public ReferenceCounter
  228. {
  229. private:
  230. DX12Pipeline* pipeline;
  231. DX12Buffer* shaderBindingTableBuffer;
  232. DX12GlobalDescriptorHeap* globalDescriptorHeap;
  233. int rayGenRecordSize;
  234. int rayGenCount;
  235. int missRecordSize;
  236. int missCount;
  237. int callableRecordSize;
  238. int callableCount;
  239. int hitGroupRecordSize;
  240. int hitGroupCount;
  241. char* tableBuffer;
  242. int tableBufferSize;
  243. Array<char*> tempBuffers;
  244. int nextHitGroupOffset;
  245. ID3D12StateObjectProperties* stateObjectProperties;
  246. public:
  247. DLLEXPORT DX12ShaderBindingTable(DX12Pipeline* pipeline);
  248. DLLEXPORT ~DX12ShaderBindingTable();
  249. DLLEXPORT void setGlobalDescriptorHeap(
  250. DX12GlobalDescriptorHeap* zGlobalDescriptorHeap);
  251. DLLEXPORT void startUpdate();
  252. private:
  253. DLLEXPORT void set(int index, void* data, int size);
  254. public:
  255. /**
  256. * sets inputs for shader outside of any hit groups for the current
  257. * update of the shader binding table.
  258. *
  259. * \param zFunction the sample shader function for which the inputs are
  260. * set. The function must be part of the pipeline.
  261. * \param offsetPointer pointer for the offset in the shader binding
  262. * table witch was obtained by adding the register usage to the
  263. * segnature of the shader function by calling
  264. * DX12ShaderSignature::addRegisterUsageLinkedToShaderBindingTable.
  265. * \param gpuAddress the parameter to be placed in the shader binding
  266. * table for this input. This is usually the GPU address of a buffer or
  267. * texture.
  268. */
  269. DLLEXPORT void setShaderInput(DX12ShaderFunction* zFunction,
  270. int* offsetPointer,
  271. __int64 gpuAddress);
  272. /**
  273. * adds a hit group to the current update of the shader binding table.
  274. * each hit group mus be readded for each update of the shader binding
  275. * table.
  276. *
  277. * \param zHitGroup the hit group to be added. The hit group must be
  278. * part of the pipeline.
  279. * \return the index of the hit group in the shader binding table. This
  280. * index can be used to set the inputs for this hit group by calling
  281. * setHitGroupShaderInput.
  282. */
  283. DLLEXPORT int addHitGroup(DX12ShaderHitGroup* zHitGroup);
  284. /**
  285. * sets a specific input for a previously added hitgroup.
  286. *
  287. * \param hitGroupOffset the hit group offset returned by addHitGroup
  288. * for the hit group for which the input is set.
  289. * \param offsetPointer pointer for the offset in the shader binding
  290. * table witch was obtained by adding the register usage to the
  291. * segnature of the shader function by calling
  292. * DX12ShaderSignature::addRegisterUsageLinkedToShaderBindingTable.
  293. * \param gpuAddress the parameter to be placed in the shader binding
  294. * table for this input. This is usually the GPU address of a buffer or
  295. * texture.
  296. */
  297. DLLEXPORT void setHitGroupShaderInput(
  298. int hitGroupOffset, int* offsetPointer, __int64 gpuAddress);
  299. DLLEXPORT void endUpdate(
  300. ID3D12Device5* zDevice, DX12CommandQueue* zQueue);
  301. DLLEXPORT void fillDispatchRaysDesc(
  302. D3D12_DISPATCH_RAYS_DESC* dispatchRaysDesc);
  303. DLLEXPORT DX12Pipeline* zPipeline() const;
  304. };
  305. } // namespace Framework