Functions.cpp 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. // Copyright (C) 2009-2023, Panagiotis Christopoulos Charitos and contributors.
  2. // All rights reserved.
  3. // Code licensed under the BSD License.
  4. // http://www.anki3d.org/LICENSE
  5. #include <AnKi/Gr/BackendCommon/Functions.h>
  6. namespace anki {
  7. template<typename T>
  8. static void writeShaderBlockMemorySanityChecks(const ShaderVariableBlockInfo& varBlkInfo, [[maybe_unused]] const void* elements,
  9. [[maybe_unused]] U32 elementsCount, [[maybe_unused]] void* buffBegin,
  10. [[maybe_unused]] const void* buffEnd)
  11. {
  12. // Check args
  13. ANKI_ASSERT(elements != nullptr);
  14. ANKI_ASSERT(elementsCount > 0);
  15. ANKI_ASSERT(buffBegin != nullptr);
  16. ANKI_ASSERT(buffEnd != nullptr);
  17. ANKI_ASSERT(buffBegin < buffEnd);
  18. // Check varBlkInfo
  19. ANKI_ASSERT(varBlkInfo.m_offset != -1);
  20. ANKI_ASSERT(varBlkInfo.m_arraySize > 0);
  21. if(varBlkInfo.m_arraySize > 1)
  22. {
  23. ANKI_ASSERT(varBlkInfo.m_arrayStride > 0);
  24. }
  25. // Check array size
  26. ANKI_ASSERT(I16(elementsCount) <= varBlkInfo.m_arraySize);
  27. }
  28. template<typename T>
  29. static void writeShaderBlockMemorySimple(const ShaderVariableBlockInfo& varBlkInfo, const void* elements, U32 elementsCount, void* buffBegin,
  30. const void* buffEnd)
  31. {
  32. writeShaderBlockMemorySanityChecks<T>(varBlkInfo, elements, elementsCount, buffBegin, buffEnd);
  33. U8* outBuff = static_cast<U8*>(buffBegin) + varBlkInfo.m_offset;
  34. const U8* inBuff = static_cast<const U8*>(elements);
  35. for(U i = 0; i < elementsCount; i++)
  36. {
  37. ANKI_ASSERT(outBuff + sizeof(T) <= static_cast<const U8*>(buffEnd));
  38. // Memcpy because Vec might have SIMD alignment but not the output buffer
  39. memcpy(outBuff, inBuff + i * sizeof(T), sizeof(T));
  40. outBuff += varBlkInfo.m_arrayStride;
  41. }
  42. }
  43. template<typename T, typename Vec>
  44. static void writeShaderBlockMemoryMatrix(const ShaderVariableBlockInfo& varBlkInfo, const void* elements, U32 elementsCount, void* buffBegin,
  45. const void* buffEnd)
  46. {
  47. writeShaderBlockMemorySanityChecks<T>(varBlkInfo, elements, elementsCount, buffBegin, buffEnd);
  48. ANKI_ASSERT(varBlkInfo.m_matrixStride > 0);
  49. ANKI_ASSERT(varBlkInfo.m_matrixStride >= static_cast<I16>(sizeof(Vec)));
  50. U8* buff = static_cast<U8*>(buffBegin) + varBlkInfo.m_offset;
  51. for(U i = 0; i < elementsCount; i++)
  52. {
  53. U8* subbuff = buff;
  54. const T& matrix = static_cast<const T*>(elements)[i];
  55. for(U j = 0; j < sizeof(T) / sizeof(Vec); j++)
  56. {
  57. ANKI_ASSERT((subbuff + sizeof(Vec)) <= static_cast<const U8*>(buffEnd));
  58. const Vec in = matrix.getRow(j);
  59. memcpy(subbuff, &in, sizeof(Vec)); // Memcpy because Vec might have SIMD alignment but not the output buffer
  60. subbuff += varBlkInfo.m_matrixStride;
  61. }
  62. buff += varBlkInfo.m_arrayStride;
  63. }
  64. }
  65. // This is some trickery to select calling between writeShaderBlockMemoryMatrix and writeShaderBlockMemorySimple
  66. namespace {
  67. template<typename T>
  68. class IsShaderVarDataTypeAMatrix
  69. {
  70. public:
  71. static constexpr Bool kValue = false;
  72. };
  73. #define ANKI_SVDT_MACRO(type, baseType, rowCount, columnCount, isIntagralType) \
  74. template<> \
  75. class IsShaderVarDataTypeAMatrix<type> \
  76. { \
  77. public: \
  78. static constexpr Bool kValue = rowCount * columnCount > 4; \
  79. };
  80. #include <AnKi/Gr/ShaderVariableDataType.def.h>
  81. #undef ANKI_SVDT_MACRO
  82. template<typename T, Bool isMatrix = IsShaderVarDataTypeAMatrix<T>::kValue>
  83. class WriteShaderBlockMemory
  84. {
  85. public:
  86. void operator()(const ShaderVariableBlockInfo& varBlkInfo, const void* elements, U32 elementsCount, void* buffBegin, const void* buffEnd)
  87. {
  88. using RowVec = typename T::RowVec;
  89. writeShaderBlockMemoryMatrix<T, RowVec>(varBlkInfo, elements, elementsCount, buffBegin, buffEnd);
  90. }
  91. };
  92. template<typename T>
  93. class WriteShaderBlockMemory<T, false>
  94. {
  95. public:
  96. void operator()(const ShaderVariableBlockInfo& varBlkInfo, const void* elements, U32 elementsCount, void* buffBegin, const void* buffEnd)
  97. {
  98. writeShaderBlockMemorySimple<T>(varBlkInfo, elements, elementsCount, buffBegin, buffEnd);
  99. }
  100. };
  101. } // namespace
  102. void writeShaderBlockMemory(ShaderVariableDataType type, const ShaderVariableBlockInfo& varBlkInfo, const void* elements, U32 elementsCount,
  103. void* buffBegin, const void* buffEnd)
  104. {
  105. switch(type)
  106. {
  107. #define ANKI_SVDT_MACRO(type, baseType, rowCount, columnCount, isIntagralType) \
  108. case ShaderVariableDataType::k##type: \
  109. WriteShaderBlockMemory<type>()(varBlkInfo, elements, elementsCount, buffBegin, buffEnd); \
  110. break;
  111. #include <AnKi/Gr/ShaderVariableDataType.def.h>
  112. #undef ANKI_SVDT_MACRO
  113. default:
  114. ANKI_ASSERT(0);
  115. }
  116. }
  117. Error linkShaderReflection(const ShaderReflection& a, const ShaderReflection& b, ShaderReflection& c_)
  118. {
  119. ShaderReflection c;
  120. c.m_descriptorSetMask = a.m_descriptorSetMask | b.m_descriptorSetMask;
  121. for(U32 set = 0; set < kMaxDescriptorSets; ++set)
  122. {
  123. if(!c.m_descriptorSetMask.get(set))
  124. {
  125. continue;
  126. }
  127. for(U32 binding = 0; binding < kMaxBindingsPerDescriptorSet; ++binding)
  128. {
  129. const Bool bindingExists = a.m_descriptorArraySizes[set][binding] > 0 || b.m_descriptorArraySizes[set][binding] > 0;
  130. if(!bindingExists)
  131. {
  132. continue;
  133. }
  134. const Bool sizeCorrect = a.m_descriptorArraySizes[set][binding] == 0 || b.m_descriptorArraySizes[set][binding] == 0
  135. || a.m_descriptorArraySizes[set][binding] == b.m_descriptorArraySizes[set][binding];
  136. if(!sizeCorrect)
  137. {
  138. ANKI_GR_LOGE("Can't link shader reflection because of different array size. Set %u binding %u", set, binding);
  139. return Error::kFunctionFailed;
  140. }
  141. const Bool typeCorrect = a.m_descriptorTypes[set][binding] == DescriptorType::kCount
  142. || b.m_descriptorTypes[set][binding] == DescriptorType::kCount
  143. || a.m_descriptorTypes[set][binding] == b.m_descriptorTypes[set][binding];
  144. if(!typeCorrect)
  145. {
  146. ANKI_GR_LOGE("Can't link shader reflection because of different array size. Set %u binding %u", set, binding);
  147. return Error::kFunctionFailed;
  148. }
  149. const Bool flagsCorrect = a.m_descriptorFlags[set][binding] == DescriptorFlag::kNone
  150. || b.m_descriptorFlags[set][binding] == DescriptorFlag::kNone
  151. || a.m_descriptorFlags[set][binding] == b.m_descriptorFlags[set][binding];
  152. if(!flagsCorrect)
  153. {
  154. ANKI_GR_LOGE("Can't link shader reflection because of different discriptor flags. Set %u binding %u", set, binding);
  155. return Error::kFunctionFailed;
  156. }
  157. c.m_descriptorArraySizes[set][binding] = max(a.m_descriptorArraySizes[set][binding], b.m_descriptorArraySizes[set][binding]);
  158. c.m_descriptorTypes[set][binding] = min(a.m_descriptorTypes[set][binding], b.m_descriptorTypes[set][binding]);
  159. c.m_descriptorFlags[set][binding] = max(a.m_descriptorFlags[set][binding], b.m_descriptorFlags[set][binding]);
  160. }
  161. }
  162. c.m_vertexAttributeLocations = (a.m_vertexAttributeMask.getAnySet()) ? a.m_vertexAttributeLocations : b.m_vertexAttributeLocations;
  163. c.m_vertexAttributeMask = a.m_vertexAttributeMask | b.m_vertexAttributeMask;
  164. c.m_colorAttachmentWritemask = a.m_colorAttachmentWritemask | b.m_colorAttachmentWritemask;
  165. const Bool pushConstantsCorrect = a.m_pushConstantsSize == 0 || b.m_pushConstantsSize == 0 || a.m_pushConstantsSize == b.m_pushConstantsSize;
  166. if(!pushConstantsCorrect)
  167. {
  168. ANKI_GR_LOGE("Can't link shader reflection because of different push constants size");
  169. return Error::kFunctionFailed;
  170. }
  171. c.m_pushConstantsSize = max(a.m_pushConstantsSize, b.m_pushConstantsSize);
  172. c.m_discards = a.m_discards || b.m_discards;
  173. c_ = c;
  174. return Error::kNone;
  175. }
  176. } // end namespace anki