// Copyright (C) 2009-2021, Panagiotis Christopoulos Charitos and contributors. // All rights reserved. // Code licensed under the BSD License. // http://www.anki3d.org/LICENSE #include namespace anki { template static void writeShaderBlockMemorySanityChecks(const ShaderVariableBlockInfo& varBlkInfo, const void* elements, U32 elementsCount, void* buffBegin, const void* buffEnd) { // Check args ANKI_ASSERT(elements != nullptr); ANKI_ASSERT(elementsCount > 0); ANKI_ASSERT(buffBegin != nullptr); ANKI_ASSERT(buffEnd != nullptr); ANKI_ASSERT(buffBegin < buffEnd); ANKI_ASSERT(isAligned(alignof(T), ptrToNumber(elements)) && "Breaking strict aliasing rules"); ANKI_ASSERT(isAligned(alignof(T), ptrToNumber(static_cast(buffBegin) + varBlkInfo.m_offset)) && "Breaking strict aliasing rules"); // Check varBlkInfo ANKI_ASSERT(varBlkInfo.m_offset != -1); ANKI_ASSERT(varBlkInfo.m_arraySize > 0); if(varBlkInfo.m_arraySize > 1) { ANKI_ASSERT(varBlkInfo.m_arrayStride > 0); } // Check array size ANKI_ASSERT(I16(elementsCount) <= varBlkInfo.m_arraySize); } template static void writeShaderBlockMemorySimple(const ShaderVariableBlockInfo& varBlkInfo, const void* elements, U32 elementsCount, void* buffBegin, const void* buffEnd) { writeShaderBlockMemorySanityChecks(varBlkInfo, elements, elementsCount, buffBegin, buffEnd); U8* buff = static_cast(buffBegin) + varBlkInfo.m_offset; for(U i = 0; i < elementsCount; i++) { ANKI_ASSERT(buff + sizeof(T) <= static_cast(buffEnd)); T* out = reinterpret_cast(buff); const T* in = reinterpret_cast(elements) + i; *out = *in; buff += varBlkInfo.m_arrayStride; } } template static void writeShaderBlockMemoryMatrix(const ShaderVariableBlockInfo& varBlkInfo, const void* elements, U32 elementsCount, void* buffBegin, const void* buffEnd) { writeShaderBlockMemorySanityChecks(varBlkInfo, elements, elementsCount, buffBegin, buffEnd); ANKI_ASSERT(varBlkInfo.m_matrixStride > 0); ANKI_ASSERT(varBlkInfo.m_matrixStride >= static_cast(sizeof(Vec))); U8* buff = static_cast(buffBegin) + varBlkInfo.m_offset; for(U i = 0; i < elementsCount; i++) { U8* subbuff = buff; const T& matrix = static_cast(elements)[i]; for(U j = 0; j < sizeof(T) / sizeof(Vec); j++) { ANKI_ASSERT((subbuff + sizeof(Vec)) <= static_cast(buffEnd)); Vec* out = reinterpret_cast(subbuff); *out = matrix.getRow(j); subbuff += varBlkInfo.m_matrixStride; } buff += varBlkInfo.m_arrayStride; } } // This is some trickery to select calling between writeShaderBlockMemoryMatrix and writeShaderBlockMemorySimple namespace { template class IsShaderVarDataTypeAMatrix { public: static constexpr Bool VALUE = false; }; #define ANKI_SVDT_MACRO(capital, type, baseType, rowCount, columnCount) \ template<> \ class IsShaderVarDataTypeAMatrix \ { \ public: \ static constexpr Bool VALUE = rowCount * columnCount > 4; \ }; #include #undef ANKI_SVDT_MACRO template::VALUE> class WriteShaderBlockMemory { public: void operator()(const ShaderVariableBlockInfo& varBlkInfo, const void* elements, U32 elementsCount, void* buffBegin, const void* buffEnd) { using RowVec = typename T::RowVec; writeShaderBlockMemoryMatrix(varBlkInfo, elements, elementsCount, buffBegin, buffEnd); } }; template class WriteShaderBlockMemory { public: void operator()(const ShaderVariableBlockInfo& varBlkInfo, const void* elements, U32 elementsCount, void* buffBegin, const void* buffEnd) { writeShaderBlockMemorySimple(varBlkInfo, elements, elementsCount, buffBegin, buffEnd); } }; } // namespace void writeShaderBlockMemory(ShaderVariableDataType type, const ShaderVariableBlockInfo& varBlkInfo, const void* elements, U32 elementsCount, void* buffBegin, const void* buffEnd) { switch(type) { #define ANKI_SVDT_MACRO(capital, type, baseType, rowCount, columnCount) \ case ShaderVariableDataType::capital: \ WriteShaderBlockMemory()(varBlkInfo, elements, elementsCount, buffBegin, buffEnd); \ break; #include #undef ANKI_SVDT_MACRO default: ANKI_ASSERT(0); } } const CString shaderVariableDataTypeToString(ShaderVariableDataType t) { switch(t) { case ShaderVariableDataType::NONE: return "NONE"; #define ANKI_SVDT_MACRO(capital, type, baseType, rowCount, columnCount) \ case ShaderVariableDataType::capital: \ return ANKI_STRINGIZE(type); #define ANKI_SVDT_MACRO_OPAQUE(capital, type) ANKI_SVDT_MACRO(capital, type, 0, 0, 0) #include #undef ANKI_SVDT_MACRO #undef ANKI_SVDT_MACRO_OPAQUE default: ANKI_ASSERT(0); } ANKI_ASSERT(0); return ""; } } // end namespace anki