Functions.cpp 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. // Copyright (C) 2009-2022, 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/Utils/Functions.h>
  6. namespace anki {
  7. template<typename T>
  8. static void writeShaderBlockMemorySanityChecks(const ShaderVariableBlockInfo& varBlkInfo,
  9. [[maybe_unused]] const void* elements,
  10. [[maybe_unused]] U32 elementsCount, [[maybe_unused]] void* buffBegin,
  11. [[maybe_unused]] const void* buffEnd)
  12. {
  13. // Check args
  14. ANKI_ASSERT(elements != nullptr);
  15. ANKI_ASSERT(elementsCount > 0);
  16. ANKI_ASSERT(buffBegin != nullptr);
  17. ANKI_ASSERT(buffEnd != nullptr);
  18. ANKI_ASSERT(buffBegin < buffEnd);
  19. // Check varBlkInfo
  20. ANKI_ASSERT(varBlkInfo.m_offset != -1);
  21. ANKI_ASSERT(varBlkInfo.m_arraySize > 0);
  22. if(varBlkInfo.m_arraySize > 1)
  23. {
  24. ANKI_ASSERT(varBlkInfo.m_arrayStride > 0);
  25. }
  26. // Check array size
  27. ANKI_ASSERT(I16(elementsCount) <= varBlkInfo.m_arraySize);
  28. }
  29. template<typename T>
  30. static void writeShaderBlockMemorySimple(const ShaderVariableBlockInfo& varBlkInfo, const void* elements,
  31. U32 elementsCount, void* buffBegin, const void* buffEnd)
  32. {
  33. writeShaderBlockMemorySanityChecks<T>(varBlkInfo, elements, elementsCount, buffBegin, buffEnd);
  34. U8* outBuff = static_cast<U8*>(buffBegin) + varBlkInfo.m_offset;
  35. const U8* inBuff = static_cast<const U8*>(elements);
  36. for(U i = 0; i < elementsCount; i++)
  37. {
  38. ANKI_ASSERT(outBuff + sizeof(T) <= static_cast<const U8*>(buffEnd));
  39. // Memcpy because Vec might have SIMD alignment but not the output buffer
  40. memcpy(outBuff, inBuff + i * sizeof(T), sizeof(T));
  41. outBuff += varBlkInfo.m_arrayStride;
  42. }
  43. }
  44. template<typename T, typename Vec>
  45. static void writeShaderBlockMemoryMatrix(const ShaderVariableBlockInfo& varBlkInfo, const void* elements,
  46. U32 elementsCount, void* buffBegin, const void* buffEnd)
  47. {
  48. writeShaderBlockMemorySanityChecks<T>(varBlkInfo, elements, elementsCount, buffBegin, buffEnd);
  49. ANKI_ASSERT(varBlkInfo.m_matrixStride > 0);
  50. ANKI_ASSERT(varBlkInfo.m_matrixStride >= static_cast<I16>(sizeof(Vec)));
  51. U8* buff = static_cast<U8*>(buffBegin) + varBlkInfo.m_offset;
  52. for(U i = 0; i < elementsCount; i++)
  53. {
  54. U8* subbuff = buff;
  55. const T& matrix = static_cast<const T*>(elements)[i];
  56. for(U j = 0; j < sizeof(T) / sizeof(Vec); j++)
  57. {
  58. ANKI_ASSERT((subbuff + sizeof(Vec)) <= static_cast<const U8*>(buffEnd));
  59. const Vec in = matrix.getRow(j);
  60. memcpy(subbuff, &in, sizeof(Vec)); // Memcpy because Vec might have SIMD alignment but not the output buffer
  61. subbuff += varBlkInfo.m_matrixStride;
  62. }
  63. buff += varBlkInfo.m_arrayStride;
  64. }
  65. }
  66. // This is some trickery to select calling between writeShaderBlockMemoryMatrix and writeShaderBlockMemorySimple
  67. namespace {
  68. template<typename T>
  69. class IsShaderVarDataTypeAMatrix
  70. {
  71. public:
  72. static constexpr Bool VALUE = false;
  73. };
  74. #define ANKI_SVDT_MACRO(capital, type, baseType, rowCount, columnCount, isIntagralType) \
  75. template<> \
  76. class IsShaderVarDataTypeAMatrix<type> \
  77. { \
  78. public: \
  79. static constexpr Bool VALUE = rowCount * columnCount > 4; \
  80. };
  81. #include <AnKi/Gr/ShaderVariableDataType.defs.h>
  82. #undef ANKI_SVDT_MACRO
  83. template<typename T, Bool isMatrix = IsShaderVarDataTypeAMatrix<T>::VALUE>
  84. class WriteShaderBlockMemory
  85. {
  86. public:
  87. void operator()(const ShaderVariableBlockInfo& varBlkInfo, const void* elements, U32 elementsCount, void* buffBegin,
  88. const void* buffEnd)
  89. {
  90. using RowVec = typename T::RowVec;
  91. writeShaderBlockMemoryMatrix<T, RowVec>(varBlkInfo, elements, elementsCount, buffBegin, buffEnd);
  92. }
  93. };
  94. template<typename T>
  95. class WriteShaderBlockMemory<T, false>
  96. {
  97. public:
  98. void operator()(const ShaderVariableBlockInfo& varBlkInfo, const void* elements, U32 elementsCount, void* buffBegin,
  99. const void* buffEnd)
  100. {
  101. writeShaderBlockMemorySimple<T>(varBlkInfo, elements, elementsCount, buffBegin, buffEnd);
  102. }
  103. };
  104. } // namespace
  105. void writeShaderBlockMemory(ShaderVariableDataType type, const ShaderVariableBlockInfo& varBlkInfo,
  106. const void* elements, U32 elementsCount, void* buffBegin, const void* buffEnd)
  107. {
  108. switch(type)
  109. {
  110. #define ANKI_SVDT_MACRO(capital, type, baseType, rowCount, columnCount, isIntagralType) \
  111. case ShaderVariableDataType::capital: \
  112. WriteShaderBlockMemory<type>()(varBlkInfo, elements, elementsCount, buffBegin, buffEnd); \
  113. break;
  114. #include <AnKi/Gr/ShaderVariableDataType.defs.h>
  115. #undef ANKI_SVDT_MACRO
  116. default:
  117. ANKI_ASSERT(0);
  118. }
  119. }
  120. } // end namespace anki