xref: /aosp_15_r20/external/angle/src/libANGLE/renderer/metal/renderermtl_utils.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
1 //
2 // Copyright 2023 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 // renderermtl_utils:
7 //   Helper methods pertaining to the Metal back-end.
8 //
9 
10 #include "libANGLE/renderer/metal/renderermtl_utils.h"
11 #include "libANGLE/renderer/renderer_utils.h"
12 
13 namespace rx
14 {
15 
16 namespace
17 {
18 
19 template <int cols, int rows, bool IsColumnMajor>
GetFlattenedIndex(int col,int row)20 inline int GetFlattenedIndex(int col, int row)
21 {
22     if (IsColumnMajor)
23     {
24         return col * rows + row;
25     }
26     else
27     {
28         return row * cols + col;
29     }
30 }
31 
32 template <typename T,
33           bool IsSrcColumnMajor,
34           int colsSrc,
35           int rowsSrc,
36           bool IsDstColumnMajor,
37           int colsDst,
38           int rowsDst>
ExpandMatrix(T * target,const GLfloat * value)39 void ExpandMatrix(T *target, const GLfloat *value)
40 {
41     static_assert(colsSrc <= colsDst && rowsSrc <= rowsDst, "Can only expand!");
42 
43     constexpr int kDstFlatSize = colsDst * rowsDst;
44     T staging[kDstFlatSize]    = {0};
45 
46     for (int r = 0; r < rowsSrc; r++)
47     {
48         for (int c = 0; c < colsSrc; c++)
49         {
50             int srcIndex = GetFlattenedIndex<colsSrc, rowsSrc, IsSrcColumnMajor>(c, r);
51             int dstIndex = GetFlattenedIndex<colsDst, rowsDst, IsDstColumnMajor>(c, r);
52 
53             staging[dstIndex] = static_cast<T>(value[srcIndex]);
54         }
55     }
56 
57     memcpy(target, staging, kDstFlatSize * sizeof(T));
58 }
59 
60 template <bool IsSrcColumMajor,
61           int colsSrc,
62           int rowsSrc,
63           bool IsDstColumnMajor,
64           int colsDst,
65           int rowsDst>
SetFloatUniformMatrix(unsigned int arrayElementOffset,unsigned int elementCount,GLsizei countIn,const GLfloat * value,uint8_t * targetData)66 void SetFloatUniformMatrix(unsigned int arrayElementOffset,
67                            unsigned int elementCount,
68                            GLsizei countIn,
69                            const GLfloat *value,
70                            uint8_t *targetData)
71 {
72     unsigned int count =
73         std::min(elementCount - arrayElementOffset, static_cast<unsigned int>(countIn));
74 
75     const unsigned int targetMatrixStride = colsDst * rowsDst;
76     GLfloat *target                       = reinterpret_cast<GLfloat *>(
77         targetData + arrayElementOffset * sizeof(GLfloat) * targetMatrixStride);
78 
79     for (unsigned int i = 0; i < count; i++)
80     {
81         ExpandMatrix<GLfloat, IsSrcColumMajor, colsSrc, rowsSrc, IsDstColumnMajor, colsDst,
82                      rowsDst>(target, value);
83 
84         target += targetMatrixStride;
85         value += colsSrc * rowsSrc;
86     }
87 }
88 
SetFloatUniformMatrixFast(unsigned int arrayElementOffset,unsigned int elementCount,GLsizei countIn,size_t matrixSize,const GLfloat * value,uint8_t * targetData)89 void SetFloatUniformMatrixFast(unsigned int arrayElementOffset,
90                                unsigned int elementCount,
91                                GLsizei countIn,
92                                size_t matrixSize,
93                                const GLfloat *value,
94                                uint8_t *targetData)
95 {
96     const unsigned int count =
97         std::min(elementCount - arrayElementOffset, static_cast<unsigned int>(countIn));
98 
99     const uint8_t *valueData = reinterpret_cast<const uint8_t *>(value);
100     targetData               = targetData + arrayElementOffset * matrixSize;
101 
102     memcpy(targetData, valueData, matrixSize * count);
103 }
104 
105 }  // anonymous namespace
106 
107 namespace mtl
108 {
109 
110 #define ANGLE_INSTANTIATE_SET_UNIFORM_MATRIX_FUNC(api, cols, rows) \
111     template void SetFloatUniformMatrix##api<cols, rows>::Run(     \
112         unsigned int, unsigned int, GLsizei, GLboolean, const GLfloat *, uint8_t *)
113 
114 ANGLE_INSTANTIATE_SET_UNIFORM_MATRIX_FUNC(Metal, 2, 2);
115 ANGLE_INSTANTIATE_SET_UNIFORM_MATRIX_FUNC(Metal, 3, 3);
116 ANGLE_INSTANTIATE_SET_UNIFORM_MATRIX_FUNC(Metal, 2, 3);
117 ANGLE_INSTANTIATE_SET_UNIFORM_MATRIX_FUNC(Metal, 3, 2);
118 ANGLE_INSTANTIATE_SET_UNIFORM_MATRIX_FUNC(Metal, 2, 4);
119 ANGLE_INSTANTIATE_SET_UNIFORM_MATRIX_FUNC(Metal, 3, 4);
120 ANGLE_INSTANTIATE_SET_UNIFORM_MATRIX_FUNC(Metal, 4, 3);
121 
122 #undef ANGLE_INSTANTIATE_SET_UNIFORM_MATRIX_FUNC
123 
124 #define ANGLE_SPECIALIZATION_COLS_SET_UNIFORM_MATRIX_FUNC(api, cols, rows) \
125     template void SetFloatUniformMatrix##api<cols, rows>::Run(             \
126         unsigned int, unsigned int, GLsizei, GLboolean, const GLfloat *, uint8_t *)
127 
128 template <int cols>
129 struct SetFloatUniformMatrixMetal<cols, 4>
130 {
131     static void Run(unsigned int arrayElementOffset,
132                     unsigned int elementCount,
133                     GLsizei countIn,
134                     GLboolean transpose,
135                     const GLfloat *value,
136                     uint8_t *targetData);
137 };
138 
139 template <int cols>
140 struct SetFloatUniformMatrixMetal<cols, 2>
141 {
142     static void Run(unsigned int arrayElementOffset,
143                     unsigned int elementCount,
144                     GLsizei countIn,
145                     GLboolean transpose,
146                     const GLfloat *value,
147                     uint8_t *targetData);
148 };
149 
150 ANGLE_SPECIALIZATION_COLS_SET_UNIFORM_MATRIX_FUNC(Metal, 2, 4);
151 ANGLE_SPECIALIZATION_COLS_SET_UNIFORM_MATRIX_FUNC(Metal, 3, 4);
152 ANGLE_SPECIALIZATION_COLS_SET_UNIFORM_MATRIX_FUNC(Metal, 4, 4);
153 
154 ANGLE_SPECIALIZATION_COLS_SET_UNIFORM_MATRIX_FUNC(Metal, 2, 2);
155 ANGLE_SPECIALIZATION_COLS_SET_UNIFORM_MATRIX_FUNC(Metal, 3, 2);
156 ANGLE_SPECIALIZATION_COLS_SET_UNIFORM_MATRIX_FUNC(Metal, 4, 2);
157 
158 #undef ANGLE_SPECIALIZATION_COLS_SET_UNIFORM_MATRIX_FUNC
159 
160 template <int cols>
Run(unsigned int arrayElementOffset,unsigned int elementCount,GLsizei countIn,GLboolean transpose,const GLfloat * value,uint8_t * targetData)161 void SetFloatUniformMatrixMetal<cols, 4>::Run(unsigned int arrayElementOffset,
162                                               unsigned int elementCount,
163                                               GLsizei countIn,
164                                               GLboolean transpose,
165                                               const GLfloat *value,
166                                               uint8_t *targetData)
167 {
168     const bool isSrcColumnMajor = !transpose;
169     if (isSrcColumnMajor)
170     {
171         // Both src and dst matrixs have the same layout,
172         // a single memcpy updates all the matrices
173         constexpr size_t srcMatrixSize = sizeof(GLfloat) * cols * 4;
174         SetFloatUniformMatrixFast(arrayElementOffset, elementCount, countIn, srcMatrixSize, value,
175                                   targetData);
176     }
177     else
178     {
179         // fallback to general cases
180         SetFloatUniformMatrix<false, cols, 4, true, cols, 4>(arrayElementOffset, elementCount,
181                                                              countIn, value, targetData);
182     }
183 }
184 
185 template <int cols>
Run(unsigned int arrayElementOffset,unsigned int elementCount,GLsizei countIn,GLboolean transpose,const GLfloat * value,uint8_t * targetData)186 void SetFloatUniformMatrixMetal<cols, 2>::Run(unsigned int arrayElementOffset,
187                                               unsigned int elementCount,
188                                               GLsizei countIn,
189                                               GLboolean transpose,
190                                               const GLfloat *value,
191                                               uint8_t *targetData)
192 {
193     const bool isSrcColumnMajor = !transpose;
194     if (isSrcColumnMajor)
195     {
196         // Both src and dst matrixs have the same layout,
197         // a single memcpy updates all the matrices
198         constexpr size_t srcMatrixSize = sizeof(GLfloat) * cols * 2;
199         SetFloatUniformMatrixFast(arrayElementOffset, elementCount, countIn, srcMatrixSize, value,
200                                   targetData);
201     }
202     else
203     {
204         // fallback to general cases
205         SetFloatUniformMatrix<false, cols, 2, true, cols, 2>(arrayElementOffset, elementCount,
206                                                              countIn, value, targetData);
207     }
208 }
209 
210 template <int cols, int rows>
Run(unsigned int arrayElementOffset,unsigned int elementCount,GLsizei countIn,GLboolean transpose,const GLfloat * value,uint8_t * targetData)211 void SetFloatUniformMatrixMetal<cols, rows>::Run(unsigned int arrayElementOffset,
212                                                  unsigned int elementCount,
213                                                  GLsizei countIn,
214                                                  GLboolean transpose,
215                                                  const GLfloat *value,
216                                                  uint8_t *targetData)
217 {
218     const bool isSrcColumnMajor = !transpose;
219     constexpr size_t numRows    = rows == 3 ? 4 : rows;
220     // Metal expects matrix uniforms to be column-major, and each column is padded to 4 rows.
221     if (isSrcColumnMajor)
222     {
223         SetFloatUniformMatrix<true, cols, rows, true, cols, numRows>(
224             arrayElementOffset, elementCount, countIn, value, targetData);
225     }
226     else
227     {
228         SetFloatUniformMatrix<false, cols, rows, true, cols, numRows>(
229             arrayElementOffset, elementCount, countIn, value, targetData);
230     }
231 }
232 
233 template void GetMatrixUniformMetal<GLint>(GLenum, GLint *, const GLint *, bool);
234 template void GetMatrixUniformMetal<GLuint>(GLenum, GLuint *, const GLuint *, bool);
235 
GetMatrixUniformMetal(GLenum type,GLfloat * dataOut,const GLfloat * source,bool transpose)236 void GetMatrixUniformMetal(GLenum type, GLfloat *dataOut, const GLfloat *source, bool transpose)
237 {
238     int columns    = gl::VariableColumnCount(type);
239     int rows       = gl::VariableRowCount(type);
240     int rowsPerCol = rows == 3 ? 4 : rows;
241     for (GLint col = 0; col < columns; ++col)
242     {
243         for (GLint row = 0; row < rows; ++row)
244         {
245             GLfloat *outptr = dataOut + ((col * rows) + row);
246             const GLfloat *inptr =
247                 transpose ? source + ((row * columns) + col) : source + ((col * rowsPerCol) + row);
248             *outptr = *inptr;
249         }
250     }
251 }
252 
253 template <typename NonFloatT>
GetMatrixUniformMetal(GLenum type,NonFloatT * dataOut,const NonFloatT * source,bool transpose)254 void GetMatrixUniformMetal(GLenum type, NonFloatT *dataOut, const NonFloatT *source, bool transpose)
255 {
256     UNREACHABLE();
257 }
258 
259 }  // namespace mtl
260 }  // namespace rx
261