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