// // Copyright 2023 The ANGLE Project Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // // renderermtl_utils: // Helper methods pertaining to the Metal back-end. // #include "libANGLE/renderer/metal/renderermtl_utils.h" #include "libANGLE/renderer/renderer_utils.h" namespace rx { namespace { template inline int GetFlattenedIndex(int col, int row) { if (IsColumnMajor) { return col * rows + row; } else { return row * cols + col; } } template void ExpandMatrix(T *target, const GLfloat *value) { static_assert(colsSrc <= colsDst && rowsSrc <= rowsDst, "Can only expand!"); constexpr int kDstFlatSize = colsDst * rowsDst; T staging[kDstFlatSize] = {0}; for (int r = 0; r < rowsSrc; r++) { for (int c = 0; c < colsSrc; c++) { int srcIndex = GetFlattenedIndex(c, r); int dstIndex = GetFlattenedIndex(c, r); staging[dstIndex] = static_cast(value[srcIndex]); } } memcpy(target, staging, kDstFlatSize * sizeof(T)); } template void SetFloatUniformMatrix(unsigned int arrayElementOffset, unsigned int elementCount, GLsizei countIn, const GLfloat *value, uint8_t *targetData) { unsigned int count = std::min(elementCount - arrayElementOffset, static_cast(countIn)); const unsigned int targetMatrixStride = colsDst * rowsDst; GLfloat *target = reinterpret_cast( targetData + arrayElementOffset * sizeof(GLfloat) * targetMatrixStride); for (unsigned int i = 0; i < count; i++) { ExpandMatrix(target, value); target += targetMatrixStride; value += colsSrc * rowsSrc; } } void SetFloatUniformMatrixFast(unsigned int arrayElementOffset, unsigned int elementCount, GLsizei countIn, size_t matrixSize, const GLfloat *value, uint8_t *targetData) { const unsigned int count = std::min(elementCount - arrayElementOffset, static_cast(countIn)); const uint8_t *valueData = reinterpret_cast(value); targetData = targetData + arrayElementOffset * matrixSize; memcpy(targetData, valueData, matrixSize * count); } } // anonymous namespace namespace mtl { #define ANGLE_INSTANTIATE_SET_UNIFORM_MATRIX_FUNC(api, cols, rows) \ template void SetFloatUniformMatrix##api::Run( \ unsigned int, unsigned int, GLsizei, GLboolean, const GLfloat *, uint8_t *) ANGLE_INSTANTIATE_SET_UNIFORM_MATRIX_FUNC(Metal, 2, 2); ANGLE_INSTANTIATE_SET_UNIFORM_MATRIX_FUNC(Metal, 3, 3); ANGLE_INSTANTIATE_SET_UNIFORM_MATRIX_FUNC(Metal, 2, 3); ANGLE_INSTANTIATE_SET_UNIFORM_MATRIX_FUNC(Metal, 3, 2); ANGLE_INSTANTIATE_SET_UNIFORM_MATRIX_FUNC(Metal, 2, 4); ANGLE_INSTANTIATE_SET_UNIFORM_MATRIX_FUNC(Metal, 3, 4); ANGLE_INSTANTIATE_SET_UNIFORM_MATRIX_FUNC(Metal, 4, 3); #undef ANGLE_INSTANTIATE_SET_UNIFORM_MATRIX_FUNC #define ANGLE_SPECIALIZATION_COLS_SET_UNIFORM_MATRIX_FUNC(api, cols, rows) \ template void SetFloatUniformMatrix##api::Run( \ unsigned int, unsigned int, GLsizei, GLboolean, const GLfloat *, uint8_t *) template struct SetFloatUniformMatrixMetal { static void Run(unsigned int arrayElementOffset, unsigned int elementCount, GLsizei countIn, GLboolean transpose, const GLfloat *value, uint8_t *targetData); }; template struct SetFloatUniformMatrixMetal { static void Run(unsigned int arrayElementOffset, unsigned int elementCount, GLsizei countIn, GLboolean transpose, const GLfloat *value, uint8_t *targetData); }; ANGLE_SPECIALIZATION_COLS_SET_UNIFORM_MATRIX_FUNC(Metal, 2, 4); ANGLE_SPECIALIZATION_COLS_SET_UNIFORM_MATRIX_FUNC(Metal, 3, 4); ANGLE_SPECIALIZATION_COLS_SET_UNIFORM_MATRIX_FUNC(Metal, 4, 4); ANGLE_SPECIALIZATION_COLS_SET_UNIFORM_MATRIX_FUNC(Metal, 2, 2); ANGLE_SPECIALIZATION_COLS_SET_UNIFORM_MATRIX_FUNC(Metal, 3, 2); ANGLE_SPECIALIZATION_COLS_SET_UNIFORM_MATRIX_FUNC(Metal, 4, 2); #undef ANGLE_SPECIALIZATION_COLS_SET_UNIFORM_MATRIX_FUNC template void SetFloatUniformMatrixMetal::Run(unsigned int arrayElementOffset, unsigned int elementCount, GLsizei countIn, GLboolean transpose, const GLfloat *value, uint8_t *targetData) { const bool isSrcColumnMajor = !transpose; if (isSrcColumnMajor) { // Both src and dst matrixs have the same layout, // a single memcpy updates all the matrices constexpr size_t srcMatrixSize = sizeof(GLfloat) * cols * 4; SetFloatUniformMatrixFast(arrayElementOffset, elementCount, countIn, srcMatrixSize, value, targetData); } else { // fallback to general cases SetFloatUniformMatrix(arrayElementOffset, elementCount, countIn, value, targetData); } } template void SetFloatUniformMatrixMetal::Run(unsigned int arrayElementOffset, unsigned int elementCount, GLsizei countIn, GLboolean transpose, const GLfloat *value, uint8_t *targetData) { const bool isSrcColumnMajor = !transpose; if (isSrcColumnMajor) { // Both src and dst matrixs have the same layout, // a single memcpy updates all the matrices constexpr size_t srcMatrixSize = sizeof(GLfloat) * cols * 2; SetFloatUniformMatrixFast(arrayElementOffset, elementCount, countIn, srcMatrixSize, value, targetData); } else { // fallback to general cases SetFloatUniformMatrix(arrayElementOffset, elementCount, countIn, value, targetData); } } template void SetFloatUniformMatrixMetal::Run(unsigned int arrayElementOffset, unsigned int elementCount, GLsizei countIn, GLboolean transpose, const GLfloat *value, uint8_t *targetData) { const bool isSrcColumnMajor = !transpose; constexpr size_t numRows = rows == 3 ? 4 : rows; // Metal expects matrix uniforms to be column-major, and each column is padded to 4 rows. if (isSrcColumnMajor) { SetFloatUniformMatrix( arrayElementOffset, elementCount, countIn, value, targetData); } else { SetFloatUniformMatrix( arrayElementOffset, elementCount, countIn, value, targetData); } } template void GetMatrixUniformMetal(GLenum, GLint *, const GLint *, bool); template void GetMatrixUniformMetal(GLenum, GLuint *, const GLuint *, bool); void GetMatrixUniformMetal(GLenum type, GLfloat *dataOut, const GLfloat *source, bool transpose) { int columns = gl::VariableColumnCount(type); int rows = gl::VariableRowCount(type); int rowsPerCol = rows == 3 ? 4 : rows; for (GLint col = 0; col < columns; ++col) { for (GLint row = 0; row < rows; ++row) { GLfloat *outptr = dataOut + ((col * rows) + row); const GLfloat *inptr = transpose ? source + ((row * columns) + col) : source + ((col * rowsPerCol) + row); *outptr = *inptr; } } } template void GetMatrixUniformMetal(GLenum type, NonFloatT *dataOut, const NonFloatT *source, bool transpose) { UNREACHABLE(); } } // namespace mtl } // namespace rx