MaterialResource.h 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496
  1. // Copyright (C) 2009-2021, Panagiotis Christopoulos Charitos and contributors.
  2. // All rights reserved.
  3. // Code licensed under the BSD License.
  4. // http://www.anki3d.org/LICENSE
  5. #pragma once
  6. #include <AnKi/Resource/ResourceObject.h>
  7. #include <AnKi/Resource/RenderingKey.h>
  8. #include <AnKi/Resource/ShaderProgramResource.h>
  9. #include <AnKi/Resource/ImageResource.h>
  10. #include <AnKi/Math.h>
  11. #include <AnKi/Util/Enum.h>
  12. #include <AnKi/Shaders/Include/ModelTypes.h>
  13. namespace anki {
  14. // Forward
  15. class XmlElement;
  16. /// @addtogroup resource
  17. /// @{
  18. /// The ID of a buildin material variable.
  19. enum class BuiltinMaterialVariableId : U8
  20. {
  21. NONE = 0,
  22. MODEL_VIEW_PROJECTION_MATRIX,
  23. PREVIOUS_MODEL_VIEW_PROJECTION_MATRIX,
  24. MODEL_MATRIX,
  25. VIEW_MATRIX,
  26. PROJECTION_MATRIX,
  27. MODEL_VIEW_MATRIX,
  28. VIEW_PROJECTION_MATRIX,
  29. NORMAL_MATRIX,
  30. ROTATION_MATRIX,
  31. CAMERA_ROTATION_MATRIX,
  32. CAMERA_POSITION,
  33. GLOBAL_SAMPLER,
  34. COUNT,
  35. FIRST = 0,
  36. };
  37. ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(BuiltinMaterialVariableId)
  38. /// The ID of builtin mutators.
  39. enum class BuiltinMutatorId : U8
  40. {
  41. NONE = 0,
  42. INSTANCED,
  43. PASS,
  44. LOD,
  45. BONES,
  46. VELOCITY,
  47. COUNT,
  48. FIRST = 0
  49. };
  50. ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(BuiltinMutatorId)
  51. /// Holds the shader variables. It's a container for shader program variables that share the same name.
  52. class MaterialVariable
  53. {
  54. friend class MaterialVariant;
  55. friend class MaterialResource;
  56. public:
  57. MaterialVariable();
  58. MaterialVariable(const MaterialVariable&) = delete; // Non-copyable
  59. MaterialVariable(MaterialVariable&& b)
  60. {
  61. *this = std::move(b);
  62. }
  63. ~MaterialVariable();
  64. MaterialVariable& operator=(const MaterialVariable&) = delete; // Non-copyable
  65. MaterialVariable& operator=(MaterialVariable&& b)
  66. {
  67. m_name = std::move(b.m_name);
  68. m_index = b.m_index;
  69. m_indexInBinary = b.m_indexInBinary;
  70. m_indexInBinary2ndElement = b.m_indexInBinary2ndElement;
  71. m_opaqueBinding = b.m_opaqueBinding;
  72. m_constant = b.m_constant;
  73. m_instanced = b.m_instanced;
  74. m_numericValueIsSet = b.m_numericValueIsSet;
  75. m_dataType = b.m_dataType;
  76. m_builtin = b.m_builtin;
  77. m_Mat4 = b.m_Mat4;
  78. m_image = std::move(b.m_image);
  79. return *this;
  80. }
  81. /// Get the builtin info.
  82. BuiltinMaterialVariableId getBuiltin() const
  83. {
  84. return m_builtin;
  85. }
  86. CString getName() const
  87. {
  88. return m_name;
  89. }
  90. template<typename T>
  91. const T& getValue() const;
  92. Bool isTexture() const
  93. {
  94. return m_dataType >= ShaderVariableDataType::TEXTURE_FIRST
  95. && m_dataType <= ShaderVariableDataType::TEXTURE_LAST;
  96. }
  97. Bool isSampler() const
  98. {
  99. return m_dataType == ShaderVariableDataType::SAMPLER;
  100. }
  101. Bool inBlock() const
  102. {
  103. return !m_constant && !isTexture() && !isSampler();
  104. }
  105. Bool isConstant() const
  106. {
  107. return m_constant;
  108. }
  109. Bool isInstanced() const
  110. {
  111. return m_instanced;
  112. }
  113. Bool isBuildin() const
  114. {
  115. return m_builtin != BuiltinMaterialVariableId::NONE;
  116. }
  117. ShaderVariableDataType getDataType() const
  118. {
  119. ANKI_ASSERT(m_dataType != ShaderVariableDataType::NONE);
  120. return m_dataType;
  121. }
  122. /// Get the binding of a texture or a sampler type of material variable.
  123. U32 getOpaqueBinding() const
  124. {
  125. ANKI_ASSERT(m_opaqueBinding != MAX_U32 && (isTexture() || isSampler()));
  126. return m_opaqueBinding;
  127. }
  128. protected:
  129. String m_name;
  130. U32 m_index = MAX_U32;
  131. U32 m_indexInBinary = MAX_U32;
  132. U32 m_indexInBinary2ndElement = MAX_U32; ///< To calculate the stride.
  133. U32 m_opaqueBinding = MAX_U32; ///< Binding for textures and samplers.
  134. Bool m_constant = false;
  135. Bool m_instanced = false;
  136. Bool m_numericValueIsSet = false; ///< The unamed union bellow is set
  137. ShaderVariableDataType m_dataType = ShaderVariableDataType::NONE;
  138. BuiltinMaterialVariableId m_builtin = BuiltinMaterialVariableId::NONE;
  139. /// Values for non-builtins
  140. /// @{
  141. union
  142. {
  143. #define ANKI_SVDT_MACRO(capital, type, baseType, rowCount, columnCount) type ANKI_CONCATENATE(m_, type);
  144. #include <AnKi/Gr/ShaderVariableDataType.defs.h>
  145. #undef ANKI_SVDT_MACRO
  146. };
  147. ImageResourcePtr m_image;
  148. /// @}
  149. Bool valueSetByMaterial() const
  150. {
  151. return m_image.isCreated() || m_numericValueIsSet;
  152. }
  153. };
  154. // Specialize the MaterialVariable::getValue
  155. #define ANKI_SPECIALIZE_GET_VALUE(t_, var_, shaderType_) \
  156. template<> \
  157. inline const t_& MaterialVariable::getValue<t_>() const \
  158. { \
  159. ANKI_ASSERT(m_dataType == ShaderVariableDataType::shaderType_); \
  160. ANKI_ASSERT(m_builtin == BuiltinMaterialVariableId::NONE); \
  161. return var_; \
  162. }
  163. #define ANKI_SVDT_MACRO(capital, type, baseType, rowCount, columnCount) \
  164. ANKI_SPECIALIZE_GET_VALUE(type, ANKI_CONCATENATE(m_, type), capital)
  165. #include <AnKi/Gr/ShaderVariableDataType.defs.h>
  166. #undef ANKI_SVDT_MACRO
  167. #undef ANKI_SPECIALIZE_GET_VALUE
  168. template<>
  169. inline const ImageResourcePtr& MaterialVariable::getValue() const
  170. {
  171. ANKI_ASSERT(isTexture());
  172. ANKI_ASSERT(m_builtin == BuiltinMaterialVariableId::NONE);
  173. return m_image;
  174. }
  175. /// Material variant.
  176. class MaterialVariant
  177. {
  178. friend class MaterialResource;
  179. public:
  180. MaterialVariant() = default;
  181. MaterialVariant(const MaterialVariant&) = delete; // Non-copyable
  182. MaterialVariant& operator=(const MaterialVariant&) = delete; // Non-copyable
  183. /// Return true of the the variable is active.
  184. Bool isVariableActive(const MaterialVariable& var) const
  185. {
  186. return m_activeVars.get(var.m_index);
  187. }
  188. const ShaderProgramPtr& getShaderProgram() const
  189. {
  190. return m_prog;
  191. }
  192. U32 getPerDrawUniformBlockSize() const
  193. {
  194. return m_perDrawUboSize;
  195. }
  196. U32 getPerInstanceUniformBlockSize(U32 instanceCount) const
  197. {
  198. ANKI_ASSERT(instanceCount > 0 && instanceCount <= MAX_INSTANCE_COUNT);
  199. return m_perInstanceUboSizeSingleInstance * instanceCount;
  200. }
  201. ShaderVariableBlockInfo getBlockInfo(const MaterialVariable& var, U32 instanceCount) const
  202. {
  203. ANKI_ASSERT(isVariableActive(var));
  204. ANKI_ASSERT(var.inBlock());
  205. ANKI_ASSERT(m_blockInfos[var.m_index].m_offset >= 0);
  206. if(var.isInstanced())
  207. {
  208. ANKI_ASSERT(m_blockInfos[var.m_index].m_arraySize == I16(MAX_INSTANCE_COUNT));
  209. ANKI_ASSERT(instanceCount > 0 && instanceCount <= MAX_INSTANCE_COUNT);
  210. }
  211. else
  212. {
  213. ANKI_ASSERT(m_blockInfos[var.m_index].m_arraySize == 1);
  214. ANKI_ASSERT(instanceCount == 1);
  215. }
  216. ShaderVariableBlockInfo out = m_blockInfos[var.m_index];
  217. out.m_arraySize = I16(instanceCount);
  218. return out;
  219. }
  220. template<typename T>
  221. void writeShaderBlockMemory(const MaterialVariable& var, const T* elements, U32 elementCount, void* buffBegin,
  222. const void* buffEnd) const
  223. {
  224. ANKI_ASSERT(isVariableActive(var));
  225. ANKI_ASSERT(getShaderVariableTypeFromTypename<T>() == var.getDataType());
  226. const ShaderVariableBlockInfo blockInfo = getBlockInfo(var, elementCount);
  227. anki::writeShaderBlockMemory(var.getDataType(), blockInfo, elements, elementCount, buffBegin, buffEnd);
  228. }
  229. private:
  230. ShaderProgramPtr m_prog;
  231. DynamicArray<ShaderVariableBlockInfo> m_blockInfos;
  232. BitSet<128, U32> m_activeVars = {false};
  233. U32 m_perDrawUboSize = 0;
  234. U32 m_perInstanceUboSizeSingleInstance = 0;
  235. };
  236. /// Material resource.
  237. ///
  238. /// Material XML file format:
  239. /// @code
  240. /// <material [shadow="0 | 1"] [forwardShading="0 | 1"] shaderProgram="path">
  241. /// [<mutation>
  242. /// <mutator name="str" value="value"/>
  243. /// </mutation>]
  244. ///
  245. /// [<inputs>
  246. /// <input shaderVar="name to shaderProg var" value="values"/> (1)
  247. /// </inputs>]
  248. /// </material>
  249. ///
  250. /// [<rtMaterial>
  251. /// <rayType shaderProgram="path" type="shadows|gi|reflections|pathTracing">
  252. /// [<mutation>
  253. /// <mutator name="str" value="value"/>
  254. /// </mutation>]
  255. /// </rayType>
  256. ///
  257. /// [<inputs>
  258. /// <input name="name" value="value" />
  259. /// </inputs>]
  260. /// </rtMaterial>]
  261. /// @endcode
  262. ///
  263. /// (1): Only for non-builtins.
  264. class MaterialResource : public ResourceObject
  265. {
  266. public:
  267. MaterialResource(ResourceManager* manager);
  268. ~MaterialResource();
  269. /// Load a material file
  270. ANKI_USE_RESULT Error load(const ResourceFilename& filename, Bool async);
  271. U32 getLodCount() const
  272. {
  273. return m_lodCount;
  274. }
  275. Bool castsShadow() const
  276. {
  277. return m_shadow;
  278. }
  279. Bool hasTessellation() const
  280. {
  281. return !!(m_prog->getStages() & (ShaderTypeBit::TESSELLATION_CONTROL | ShaderTypeBit::TESSELLATION_EVALUATION));
  282. }
  283. Bool isForwardShading() const
  284. {
  285. return m_forwardShading;
  286. }
  287. Bool isInstanced() const
  288. {
  289. return m_builtinMutators[BuiltinMutatorId::INSTANCED] != nullptr;
  290. }
  291. ConstWeakArray<MaterialVariable> getVariables() const
  292. {
  293. return m_vars;
  294. }
  295. U32 getDescriptorSetIndex() const
  296. {
  297. ANKI_ASSERT(m_descriptorSetIdx != MAX_U8);
  298. return m_descriptorSetIdx;
  299. }
  300. U32 getBoneTransformsStorageBlockBinding() const
  301. {
  302. ANKI_ASSERT(supportsSkinning());
  303. return m_boneTrfsBinding;
  304. }
  305. U32 getPrevFrameBoneTransformsStorageBlockBinding() const
  306. {
  307. ANKI_ASSERT(supportsSkinning());
  308. return m_prevFrameBoneTrfsBinding;
  309. }
  310. Bool supportsSkinning() const
  311. {
  312. ANKI_ASSERT((m_boneTrfsBinding == MAX_U32 && m_prevFrameBoneTrfsBinding == MAX_U32)
  313. || (m_boneTrfsBinding != MAX_U32 && m_prevFrameBoneTrfsBinding != MAX_U32));
  314. return m_boneTrfsBinding != MAX_U32;
  315. }
  316. U32 getPerDrawUniformBlockBinding() const
  317. {
  318. ANKI_ASSERT(m_perDrawUboBinding != MAX_U32);
  319. return m_perDrawUboBinding;
  320. }
  321. U32 getPerInstanceUniformBlockBinding() const
  322. {
  323. ANKI_ASSERT(isInstanced() && m_perInstanceUboBinding != MAX_U32);
  324. return m_perInstanceUboBinding;
  325. }
  326. const MaterialVariant& getOrCreateVariant(const RenderingKey& key) const;
  327. U32 getShaderGroupHandleIndex(RayType type) const
  328. {
  329. ANKI_ASSERT(!!(m_rayTypes & RayTypeBit(1 << type)));
  330. ANKI_ASSERT(m_rtShaderGroupHandleIndices[type] < MAX_U32);
  331. return m_rtShaderGroupHandleIndices[type];
  332. }
  333. RayTypeBit getSupportedRayTracingTypes() const
  334. {
  335. return m_rayTypes;
  336. }
  337. const MaterialGpuDescriptor& getMaterialGpuDescriptor() const
  338. {
  339. return m_materialGpuDescriptor;
  340. }
  341. /// Get all texture views that the MaterialGpuDescriptor returned by getMaterialGpuDescriptor(), references. Used
  342. /// for lifetime management.
  343. ConstWeakArray<TextureViewPtr> getAllTextureViews() const
  344. {
  345. return ConstWeakArray<TextureViewPtr>((m_textureViewCount) ? &m_textureViews[0] : nullptr, m_textureViewCount);
  346. }
  347. private:
  348. class SubMutation
  349. {
  350. public:
  351. const ShaderProgramResourceMutator* m_mutator;
  352. MutatorValue m_value;
  353. };
  354. ShaderProgramResourcePtr m_prog;
  355. Array<const ShaderProgramResourceMutator*, U32(BuiltinMutatorId::COUNT)> m_builtinMutators = {};
  356. Bool m_shadow = true;
  357. Bool m_forwardShading = false;
  358. U8 m_lodCount = 1;
  359. U8 m_descriptorSetIdx = MAX_U8; ///< The material set.
  360. U32 m_perDrawUboIdx = MAX_U32; ///< The b_perDraw UBO inside the binary.
  361. U32 m_perInstanceUboIdx = MAX_U32; ///< The b_perInstance UBO inside the binary.
  362. U32 m_perDrawUboBinding = MAX_U32;
  363. U32 m_perInstanceUboBinding = MAX_U32;
  364. U32 m_boneTrfsBinding = MAX_U32;
  365. U32 m_prevFrameBoneTrfsBinding = MAX_U32;
  366. /// Matrix of variants.
  367. mutable Array5d<MaterialVariant, U(Pass::COUNT), MAX_LOD_COUNT, 2, 2, 2> m_variantMatrix;
  368. mutable RWMutex m_variantMatrixMtx;
  369. DynamicArray<MaterialVariable> m_vars;
  370. DynamicArray<SubMutation> m_nonBuiltinsMutation;
  371. Array<ShaderProgramResourcePtr, U(RayType::COUNT)> m_rtPrograms;
  372. Array<U32, U(RayType::COUNT)> m_rtShaderGroupHandleIndices = {};
  373. MaterialGpuDescriptor m_materialGpuDescriptor;
  374. Array<ImageResourcePtr, U(TextureChannelId::COUNT)> m_images; ///< Keep the resources alive.
  375. Array<TextureViewPtr, U(TextureChannelId::COUNT)> m_textureViews; ///< Cache the GPU objects.
  376. U8 m_textureViewCount = 0;
  377. RayTypeBit m_rayTypes = RayTypeBit::NONE;
  378. ANKI_USE_RESULT Error createVars();
  379. static ANKI_USE_RESULT Error parseVariable(CString fullVarName, Bool instanced, U32& idx, CString& name);
  380. /// Parse whatever is inside the <inputs> tag.
  381. ANKI_USE_RESULT Error parseInputs(XmlElement inputsEl, Bool async);
  382. ANKI_USE_RESULT Error parseMutators(XmlElement mutatorsEl);
  383. ANKI_USE_RESULT Error findBuiltinMutators();
  384. void initVariant(const ShaderProgramResourceVariant& progVariant, MaterialVariant& variant, Bool instanced) const;
  385. const MaterialVariable* tryFindVariableInternal(CString name) const
  386. {
  387. for(const MaterialVariable& v : m_vars)
  388. {
  389. if(v.m_name == name)
  390. {
  391. return &v;
  392. }
  393. }
  394. return nullptr;
  395. }
  396. const MaterialVariable* tryFindVariable(CString name) const
  397. {
  398. return tryFindVariableInternal(name);
  399. }
  400. MaterialVariable* tryFindVariable(CString name)
  401. {
  402. return const_cast<MaterialVariable*>(tryFindVariableInternal(name));
  403. }
  404. Error parseRtMaterial(XmlElement rootEl);
  405. };
  406. /// @}
  407. } // end namespace anki