1cb93a386Sopenharmony_ci/*
2cb93a386Sopenharmony_ci * Copyright 2021 Google LLC
3cb93a386Sopenharmony_ci *
4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be
5cb93a386Sopenharmony_ci * found in the LICENSE file.
6cb93a386Sopenharmony_ci */
7cb93a386Sopenharmony_ci
8cb93a386Sopenharmony_ci#include "experimental/graphite/src/UniformManager.h"
9cb93a386Sopenharmony_ci#include "include/core/SkMatrix.h"
10cb93a386Sopenharmony_ci#include "include/private/SkHalf.h"
11cb93a386Sopenharmony_ci#include "include/private/SkTemplates.h"
12cb93a386Sopenharmony_ci
13cb93a386Sopenharmony_ci// ensure that these types are the sizes the uniform data is expecting
14cb93a386Sopenharmony_cistatic_assert(sizeof(int32_t) == 4);
15cb93a386Sopenharmony_cistatic_assert(sizeof(float) == 4);
16cb93a386Sopenharmony_cistatic_assert(sizeof(int16_t) == 2);
17cb93a386Sopenharmony_cistatic_assert(sizeof(SkHalf) == 2);
18cb93a386Sopenharmony_ci
19cb93a386Sopenharmony_cinamespace skgpu {
20cb93a386Sopenharmony_ci
21cb93a386Sopenharmony_ci//////////////////////////////////////////////////////////////////////////////
22cb93a386Sopenharmony_ci
23cb93a386Sopenharmony_ciUniformManager::UniformManager(Layout layout) : fLayout(layout) {}
24cb93a386Sopenharmony_ci
25cb93a386Sopenharmony_citemplate<typename BaseType>
26cb93a386Sopenharmony_cistatic constexpr size_t tight_vec_size(int vecLength) {
27cb93a386Sopenharmony_ci    return sizeof(BaseType) * vecLength;
28cb93a386Sopenharmony_ci}
29cb93a386Sopenharmony_ci
30cb93a386Sopenharmony_ci/**
31cb93a386Sopenharmony_ci * From Section 7.6.2.2 "Standard Uniform Block Layout":
32cb93a386Sopenharmony_ci *  1. If the member is a scalar consuming N basic machine units, the base alignment is N.
33cb93a386Sopenharmony_ci *  2. If the member is a two- or four-component vector with components consuming N basic machine
34cb93a386Sopenharmony_ci *     units, the base alignment is 2N or 4N, respectively.
35cb93a386Sopenharmony_ci *  3. If the member is a three-component vector with components consuming N
36cb93a386Sopenharmony_ci *     basic machine units, the base alignment is 4N.
37cb93a386Sopenharmony_ci *  4. If the member is an array of scalars or vectors, the base alignment and array
38cb93a386Sopenharmony_ci *     stride are set to match the base alignment of a single array element, according
39cb93a386Sopenharmony_ci *     to rules (1), (2), and (3), and rounded up to the base alignment of a vec4. The
40cb93a386Sopenharmony_ci *     array may have padding at the end; the base offset of the member following
41cb93a386Sopenharmony_ci *     the array is rounded up to the next multiple of the base alignment.
42cb93a386Sopenharmony_ci *  5. If the member is a column-major matrix with C columns and R rows, the
43cb93a386Sopenharmony_ci *     matrix is stored identically to an array of C column vectors with R components each,
44cb93a386Sopenharmony_ci *     according to rule (4).
45cb93a386Sopenharmony_ci *  6. If the member is an array of S column-major matrices with C columns and
46cb93a386Sopenharmony_ci *     R rows, the matrix is stored identically to a row of S × C column vectors
47cb93a386Sopenharmony_ci *     with R components each, according to rule (4).
48cb93a386Sopenharmony_ci *  7. If the member is a row-major matrix with C columns and R rows, the matrix
49cb93a386Sopenharmony_ci *     is stored identically to an array of R row vectors with C components each,
50cb93a386Sopenharmony_ci *     according to rule (4).
51cb93a386Sopenharmony_ci *  8. If the member is an array of S row-major matrices with C columns and R
52cb93a386Sopenharmony_ci *     rows, the matrix is stored identically to a row of S × R row vectors with C
53cb93a386Sopenharmony_ci *    components each, according to rule (4).
54cb93a386Sopenharmony_ci *  9. If the member is a structure, the base alignment of the structure is N, where
55cb93a386Sopenharmony_ci *     N is the largest base alignment value of any of its members, and rounded
56cb93a386Sopenharmony_ci *     up to the base alignment of a vec4. The individual members of this substructure are then
57cb93a386Sopenharmony_ci *     assigned offsets by applying this set of rules recursively,
58cb93a386Sopenharmony_ci *     where the base offset of the first member of the sub-structure is equal to the
59cb93a386Sopenharmony_ci *     aligned offset of the structure. The structure may have padding at the end;
60cb93a386Sopenharmony_ci *     the base offset of the member following the sub-structure is rounded up to
61cb93a386Sopenharmony_ci *     the next multiple of the base alignment of the structure.
62cb93a386Sopenharmony_ci * 10. If the member is an array of S structures, the S elements of the array are laid
63cb93a386Sopenharmony_ci *     out in order, according to rule (9).
64cb93a386Sopenharmony_ci */
65cb93a386Sopenharmony_citemplate<typename BaseType, int RowsOrVecLength = 1, int Cols = 1>
66cb93a386Sopenharmony_cistruct Rules140 {
67cb93a386Sopenharmony_ci    /**
68cb93a386Sopenharmony_ci     * For an array of scalars or vectors this returns the stride between array elements. For
69cb93a386Sopenharmony_ci     * matrices or arrays of matrices this returns the stride between columns of the matrix. Note
70cb93a386Sopenharmony_ci     * that for single (non-array) scalars or vectors we don't require a stride.
71cb93a386Sopenharmony_ci     */
72cb93a386Sopenharmony_ci    static constexpr size_t Stride(int count) {
73cb93a386Sopenharmony_ci        SkASSERT(count >= 1 || count == Uniform::kNonArray);
74cb93a386Sopenharmony_ci        static_assert(RowsOrVecLength >= 1 && RowsOrVecLength <= 4);
75cb93a386Sopenharmony_ci        static_assert(Cols >= 1 && Cols <= 4);
76cb93a386Sopenharmony_ci        if (Cols != 1) {
77cb93a386Sopenharmony_ci            // This is a matrix or array of matrices. We return the stride between columns.
78cb93a386Sopenharmony_ci            SkASSERT(RowsOrVecLength > 1);
79cb93a386Sopenharmony_ci            return Rules140<BaseType, RowsOrVecLength>::Stride(1);
80cb93a386Sopenharmony_ci        }
81cb93a386Sopenharmony_ci        if (count == 0) {
82cb93a386Sopenharmony_ci            // Stride doesn't matter for a non-array.
83cb93a386Sopenharmony_ci            return RowsOrVecLength * sizeof(BaseType);
84cb93a386Sopenharmony_ci        }
85cb93a386Sopenharmony_ci
86cb93a386Sopenharmony_ci        // Rule 4.
87cb93a386Sopenharmony_ci
88cb93a386Sopenharmony_ci        // Alignment of vec4 by Rule 2.
89cb93a386Sopenharmony_ci        constexpr size_t kVec4Alignment = tight_vec_size<float>(4);
90cb93a386Sopenharmony_ci        // Get alignment of a single vector of BaseType by Rule 1, 2, or 3
91cb93a386Sopenharmony_ci        int n = RowsOrVecLength == 3 ? 4 : RowsOrVecLength;
92cb93a386Sopenharmony_ci        size_t kElementAlignment = tight_vec_size<BaseType>(n);
93cb93a386Sopenharmony_ci        // Round kElementAlignment up to multiple of kVec4Alignment.
94cb93a386Sopenharmony_ci        size_t m = (kElementAlignment + kVec4Alignment - 1) / kVec4Alignment;
95cb93a386Sopenharmony_ci        return m * kVec4Alignment;
96cb93a386Sopenharmony_ci    }
97cb93a386Sopenharmony_ci};
98cb93a386Sopenharmony_ci
99cb93a386Sopenharmony_ci/**
100cb93a386Sopenharmony_ci * When using the std430 storage layout, shader storage blocks will be laid out in buffer storage
101cb93a386Sopenharmony_ci * identically to uniform and shader storage blocks using the std140 layout, except that the base
102cb93a386Sopenharmony_ci * alignment and stride of arrays of scalars and vectors in rule 4 and of structures in rule 9 are
103cb93a386Sopenharmony_ci * not rounded up a multiple of the base alignment of a vec4.
104cb93a386Sopenharmony_ci */
105cb93a386Sopenharmony_citemplate<typename BaseType, int RowsOrVecLength = 1, int Cols = 1>
106cb93a386Sopenharmony_cistruct Rules430 {
107cb93a386Sopenharmony_ci    static constexpr size_t Stride(int count) {
108cb93a386Sopenharmony_ci        SkASSERT(count >= 1 || count == Uniform::kNonArray);
109cb93a386Sopenharmony_ci        static_assert(RowsOrVecLength >= 1 && RowsOrVecLength <= 4);
110cb93a386Sopenharmony_ci        static_assert(Cols >= 1 && Cols <= 4);
111cb93a386Sopenharmony_ci
112cb93a386Sopenharmony_ci        if (Cols != 1) {
113cb93a386Sopenharmony_ci            // This is a matrix or array of matrices. We return the stride between columns.
114cb93a386Sopenharmony_ci            SkASSERT(RowsOrVecLength > 1);
115cb93a386Sopenharmony_ci            return Rules430<BaseType, RowsOrVecLength>::Stride(1);
116cb93a386Sopenharmony_ci        }
117cb93a386Sopenharmony_ci        if (count == 0) {
118cb93a386Sopenharmony_ci            // Stride doesn't matter for a non-array.
119cb93a386Sopenharmony_ci            return RowsOrVecLength * sizeof(BaseType);
120cb93a386Sopenharmony_ci        }
121cb93a386Sopenharmony_ci        // Rule 4 without the round up to a multiple of align-of vec4.
122cb93a386Sopenharmony_ci        return tight_vec_size<BaseType>(RowsOrVecLength == 3 ? 4 : RowsOrVecLength);
123cb93a386Sopenharmony_ci    }
124cb93a386Sopenharmony_ci};
125cb93a386Sopenharmony_ci
126cb93a386Sopenharmony_ci// The strides used here were derived from the rules we've imposed on ourselves in
127cb93a386Sopenharmony_ci// GrMtlPipelineStateDataManger. Everything is tight except 3-component which have the stride of
128cb93a386Sopenharmony_ci// their 4-component equivalents.
129cb93a386Sopenharmony_citemplate<typename BaseType, int RowsOrVecLength = 1, int Cols = 1>
130cb93a386Sopenharmony_cistruct RulesMetal {
131cb93a386Sopenharmony_ci    static constexpr size_t Stride(int count) {
132cb93a386Sopenharmony_ci        SkASSERT(count >= 1 || count == Uniform::kNonArray);
133cb93a386Sopenharmony_ci        static_assert(RowsOrVecLength >= 1 && RowsOrVecLength <= 4);
134cb93a386Sopenharmony_ci        static_assert(Cols >= 1 && Cols <= 4);
135cb93a386Sopenharmony_ci        if (Cols != 1) {
136cb93a386Sopenharmony_ci            // This is a matrix or array of matrices. We return the stride between columns.
137cb93a386Sopenharmony_ci            SkASSERT(RowsOrVecLength > 1);
138cb93a386Sopenharmony_ci            return RulesMetal<BaseType, RowsOrVecLength>::Stride(1);
139cb93a386Sopenharmony_ci        }
140cb93a386Sopenharmony_ci        if (count == 0) {
141cb93a386Sopenharmony_ci            // Stride doesn't matter for a non-array.
142cb93a386Sopenharmony_ci            return RowsOrVecLength * sizeof(BaseType);
143cb93a386Sopenharmony_ci        }
144cb93a386Sopenharmony_ci        return tight_vec_size<BaseType>(RowsOrVecLength == 3 ? 4 : RowsOrVecLength);
145cb93a386Sopenharmony_ci    }
146cb93a386Sopenharmony_ci};
147cb93a386Sopenharmony_ci
148cb93a386Sopenharmony_citemplate<template<typename BaseType, int RowsOrVecLength, int Cols> class Rules>
149cb93a386Sopenharmony_ciclass Writer {
150cb93a386Sopenharmony_ciprivate:
151cb93a386Sopenharmony_ci    template <typename MemType, typename UniformType>
152cb93a386Sopenharmony_ci    static void CopyUniforms(void* dst, const void* src, int numUniforms) {
153cb93a386Sopenharmony_ci        if constexpr (std::is_same<MemType, UniformType>::value) {
154cb93a386Sopenharmony_ci            // Matching types--use memcpy.
155cb93a386Sopenharmony_ci            std::memcpy(dst, src, numUniforms * sizeof(MemType));
156cb93a386Sopenharmony_ci            return;
157cb93a386Sopenharmony_ci        }
158cb93a386Sopenharmony_ci
159cb93a386Sopenharmony_ci        if constexpr (std::is_same<MemType, float>::value &&
160cb93a386Sopenharmony_ci                      std::is_same<UniformType, SkHalf>::value) {
161cb93a386Sopenharmony_ci            // Convert floats to half.
162cb93a386Sopenharmony_ci            const float* floatBits = static_cast<const float*>(src);
163cb93a386Sopenharmony_ci            SkHalf* halfBits = static_cast<SkHalf*>(dst);
164cb93a386Sopenharmony_ci            while (numUniforms-- > 0) {
165cb93a386Sopenharmony_ci                *halfBits++ = SkFloatToHalf(*floatBits++);
166cb93a386Sopenharmony_ci            }
167cb93a386Sopenharmony_ci            return;
168cb93a386Sopenharmony_ci        }
169cb93a386Sopenharmony_ci
170cb93a386Sopenharmony_ci        SK_ABORT("implement conversion from MemType to UniformType");
171cb93a386Sopenharmony_ci    }
172cb93a386Sopenharmony_ci
173cb93a386Sopenharmony_ci    template <typename MemType, typename UniformType, int RowsOrVecLength = 1, int Cols = 1>
174cb93a386Sopenharmony_ci    static uint32_t Write(void *dst, int n, const MemType src[]) {
175cb93a386Sopenharmony_ci        size_t stride = Rules<UniformType, RowsOrVecLength, Cols>::Stride(n);
176cb93a386Sopenharmony_ci        n = (n == Uniform::kNonArray) ? 1 : n;
177cb93a386Sopenharmony_ci        n *= Cols;
178cb93a386Sopenharmony_ci
179cb93a386Sopenharmony_ci        if (dst) {
180cb93a386Sopenharmony_ci            if (stride == RowsOrVecLength * sizeof(UniformType)) {
181cb93a386Sopenharmony_ci                CopyUniforms<MemType, UniformType>(dst, src, n * RowsOrVecLength);
182cb93a386Sopenharmony_ci            } else {
183cb93a386Sopenharmony_ci                for (int i = 0; i < n; ++i) {
184cb93a386Sopenharmony_ci                    CopyUniforms<MemType, UniformType>(dst, src, RowsOrVecLength);
185cb93a386Sopenharmony_ci                    src += RowsOrVecLength;
186cb93a386Sopenharmony_ci                    dst = SkTAddOffset<void>(dst, stride);
187cb93a386Sopenharmony_ci                }
188cb93a386Sopenharmony_ci            }
189cb93a386Sopenharmony_ci        }
190cb93a386Sopenharmony_ci
191cb93a386Sopenharmony_ci        return n * stride;
192cb93a386Sopenharmony_ci    }
193cb93a386Sopenharmony_ci
194cb93a386Sopenharmony_ci    template <typename UniformType>
195cb93a386Sopenharmony_ci    static uint32_t WriteSkMatrices(void *dst, int n, const SkMatrix m[]) {
196cb93a386Sopenharmony_ci        // Stride() will give us the stride of each column, so mul by 3 to get matrix stride.
197cb93a386Sopenharmony_ci        size_t stride = 3 * Rules<UniformType, 3, 3>::Stride(1);
198cb93a386Sopenharmony_ci        n = std::max(n, 1);
199cb93a386Sopenharmony_ci
200cb93a386Sopenharmony_ci        if (dst) {
201cb93a386Sopenharmony_ci            size_t offset = 0;
202cb93a386Sopenharmony_ci            for (int i = 0; i < n; ++i) {
203cb93a386Sopenharmony_ci                float mt[] = {
204cb93a386Sopenharmony_ci                        m[i].get(SkMatrix::kMScaleX),
205cb93a386Sopenharmony_ci                        m[i].get(SkMatrix::kMSkewY),
206cb93a386Sopenharmony_ci                        m[i].get(SkMatrix::kMPersp0),
207cb93a386Sopenharmony_ci                        m[i].get(SkMatrix::kMSkewX),
208cb93a386Sopenharmony_ci                        m[i].get(SkMatrix::kMScaleY),
209cb93a386Sopenharmony_ci                        m[i].get(SkMatrix::kMPersp1),
210cb93a386Sopenharmony_ci                        m[i].get(SkMatrix::kMTransX),
211cb93a386Sopenharmony_ci                        m[i].get(SkMatrix::kMTransY),
212cb93a386Sopenharmony_ci                        m[i].get(SkMatrix::kMPersp2),
213cb93a386Sopenharmony_ci                };
214cb93a386Sopenharmony_ci                Write<float, UniformType, 3, 3>(SkTAddOffset<void>(dst, offset), 1, mt);
215cb93a386Sopenharmony_ci                offset += stride;
216cb93a386Sopenharmony_ci            }
217cb93a386Sopenharmony_ci        }
218cb93a386Sopenharmony_ci        return n * stride;
219cb93a386Sopenharmony_ci    }
220cb93a386Sopenharmony_ci
221cb93a386Sopenharmony_cipublic:
222cb93a386Sopenharmony_ci    static uint32_t WriteUniform(SLType type,
223cb93a386Sopenharmony_ci                                 CType ctype,
224cb93a386Sopenharmony_ci                                 void *dest,
225cb93a386Sopenharmony_ci                                 int n,
226cb93a386Sopenharmony_ci                                 const void *src) {
227cb93a386Sopenharmony_ci        SkASSERT(n >= 1 || n == Uniform::kNonArray);
228cb93a386Sopenharmony_ci        switch (type) {
229cb93a386Sopenharmony_ci            case SLType::kInt:
230cb93a386Sopenharmony_ci                return Write<int32_t, int32_t>(dest, n, static_cast<const int32_t *>(src));
231cb93a386Sopenharmony_ci
232cb93a386Sopenharmony_ci            case SLType::kInt2:
233cb93a386Sopenharmony_ci                return Write<int32_t, int32_t, 2>(dest, n, static_cast<const int32_t *>(src));
234cb93a386Sopenharmony_ci
235cb93a386Sopenharmony_ci            case SLType::kInt3:
236cb93a386Sopenharmony_ci                return Write<int32_t, int32_t, 3>(dest, n, static_cast<const int32_t *>(src));
237cb93a386Sopenharmony_ci
238cb93a386Sopenharmony_ci            case SLType::kInt4:
239cb93a386Sopenharmony_ci                return Write<int32_t, int32_t, 4>(dest, n, static_cast<const int32_t *>(src));
240cb93a386Sopenharmony_ci
241cb93a386Sopenharmony_ci            case SLType::kHalf:
242cb93a386Sopenharmony_ci                return Write<float, SkHalf>(dest, n, static_cast<const float *>(src));
243cb93a386Sopenharmony_ci
244cb93a386Sopenharmony_ci            case SLType::kFloat:
245cb93a386Sopenharmony_ci                return Write<float, float>(dest, n, static_cast<const float *>(src));
246cb93a386Sopenharmony_ci
247cb93a386Sopenharmony_ci            case SLType::kHalf2:
248cb93a386Sopenharmony_ci                return Write<float, SkHalf, 2>(dest, n, static_cast<const float *>(src));
249cb93a386Sopenharmony_ci
250cb93a386Sopenharmony_ci            case SLType::kFloat2:
251cb93a386Sopenharmony_ci                return Write<float, float, 2>(dest, n, static_cast<const float *>(src));
252cb93a386Sopenharmony_ci
253cb93a386Sopenharmony_ci            case SLType::kHalf3:
254cb93a386Sopenharmony_ci                return Write<float, SkHalf, 3>(dest, n, static_cast<const float *>(src));
255cb93a386Sopenharmony_ci
256cb93a386Sopenharmony_ci            case SLType::kFloat3:
257cb93a386Sopenharmony_ci                return Write<float, float, 3>(dest, n, static_cast<const float *>(src));
258cb93a386Sopenharmony_ci
259cb93a386Sopenharmony_ci            case SLType::kHalf4:
260cb93a386Sopenharmony_ci                return Write<float, SkHalf, 4>(dest, n, static_cast<const float *>(src));
261cb93a386Sopenharmony_ci
262cb93a386Sopenharmony_ci            case SLType::kFloat4:
263cb93a386Sopenharmony_ci                return Write<float, float, 4>(dest, n, static_cast<const float *>(src));
264cb93a386Sopenharmony_ci
265cb93a386Sopenharmony_ci            case SLType::kHalf2x2:
266cb93a386Sopenharmony_ci                return Write<float, SkHalf, 2, 2>(dest, n, static_cast<const float *>(src));
267cb93a386Sopenharmony_ci
268cb93a386Sopenharmony_ci            case SLType::kFloat2x2:
269cb93a386Sopenharmony_ci                return Write<float, float, 2, 2>(dest, n, static_cast<const float *>(src));
270cb93a386Sopenharmony_ci
271cb93a386Sopenharmony_ci            case SLType::kHalf3x3:
272cb93a386Sopenharmony_ci                switch (ctype) {
273cb93a386Sopenharmony_ci                    case CType::kDefault:
274cb93a386Sopenharmony_ci                        return Write<float, SkHalf, 3, 3>(dest, n, static_cast<const float *>(src));
275cb93a386Sopenharmony_ci                    case CType::kSkMatrix:
276cb93a386Sopenharmony_ci                        return WriteSkMatrices<SkHalf>(dest, n, static_cast<const SkMatrix *>(src));
277cb93a386Sopenharmony_ci                }
278cb93a386Sopenharmony_ci                SkUNREACHABLE;
279cb93a386Sopenharmony_ci
280cb93a386Sopenharmony_ci            case SLType::kFloat3x3:
281cb93a386Sopenharmony_ci                switch (ctype) {
282cb93a386Sopenharmony_ci                    case CType::kDefault:
283cb93a386Sopenharmony_ci                        return Write<float, float, 3, 3>(dest, n, static_cast<const float *>(src));
284cb93a386Sopenharmony_ci                    case CType::kSkMatrix:
285cb93a386Sopenharmony_ci                        return WriteSkMatrices<float>(dest, n, static_cast<const SkMatrix *>(src));
286cb93a386Sopenharmony_ci                }
287cb93a386Sopenharmony_ci                SkUNREACHABLE;
288cb93a386Sopenharmony_ci
289cb93a386Sopenharmony_ci            case SLType::kHalf4x4:
290cb93a386Sopenharmony_ci                return Write<float, SkHalf, 4, 4>(dest, n, static_cast<const float *>(src));
291cb93a386Sopenharmony_ci
292cb93a386Sopenharmony_ci            case SLType::kFloat4x4:
293cb93a386Sopenharmony_ci                return Write<float, float, 4, 4>(dest, n, static_cast<const float *>(src));
294cb93a386Sopenharmony_ci
295cb93a386Sopenharmony_ci            default:
296cb93a386Sopenharmony_ci                SK_ABORT("Unexpected uniform type");
297cb93a386Sopenharmony_ci        }
298cb93a386Sopenharmony_ci    }
299cb93a386Sopenharmony_ci};
300cb93a386Sopenharmony_ci
301cb93a386Sopenharmony_ci#ifdef SK_DEBUG
302cb93a386Sopenharmony_ci// To determine whether a current offset is aligned, we can just 'and' the lowest bits with the
303cb93a386Sopenharmony_ci// alignment mask. A value of 0 means aligned, any other value is how many bytes past alignment we
304cb93a386Sopenharmony_ci// are. This works since all alignments are powers of 2. The mask is always (alignment - 1).
305cb93a386Sopenharmony_cistatic uint32_t sltype_to_alignment_mask(SLType type) {
306cb93a386Sopenharmony_ci    switch (type) {
307cb93a386Sopenharmony_ci        case SLType::kInt:
308cb93a386Sopenharmony_ci        case SLType::kUInt:
309cb93a386Sopenharmony_ci        case SLType::kFloat:
310cb93a386Sopenharmony_ci            return 0x3;
311cb93a386Sopenharmony_ci        case SLType::kInt2:
312cb93a386Sopenharmony_ci        case SLType::kUInt2:
313cb93a386Sopenharmony_ci        case SLType::kFloat2:
314cb93a386Sopenharmony_ci            return 0x7;
315cb93a386Sopenharmony_ci        case SLType::kInt3:
316cb93a386Sopenharmony_ci        case SLType::kUInt3:
317cb93a386Sopenharmony_ci        case SLType::kFloat3:
318cb93a386Sopenharmony_ci        case SLType::kInt4:
319cb93a386Sopenharmony_ci        case SLType::kUInt4:
320cb93a386Sopenharmony_ci        case SLType::kFloat4:
321cb93a386Sopenharmony_ci            return 0xF;
322cb93a386Sopenharmony_ci
323cb93a386Sopenharmony_ci        case SLType::kFloat2x2:
324cb93a386Sopenharmony_ci            return 0x7;
325cb93a386Sopenharmony_ci        case SLType::kFloat3x3:
326cb93a386Sopenharmony_ci            return 0xF;
327cb93a386Sopenharmony_ci        case SLType::kFloat4x4:
328cb93a386Sopenharmony_ci            return 0xF;
329cb93a386Sopenharmony_ci
330cb93a386Sopenharmony_ci        case SLType::kShort:
331cb93a386Sopenharmony_ci        case SLType::kUShort:
332cb93a386Sopenharmony_ci        case SLType::kHalf:
333cb93a386Sopenharmony_ci            return 0x1;
334cb93a386Sopenharmony_ci        case SLType::kShort2:
335cb93a386Sopenharmony_ci        case SLType::kUShort2:
336cb93a386Sopenharmony_ci        case SLType::kHalf2:
337cb93a386Sopenharmony_ci            return 0x3;
338cb93a386Sopenharmony_ci        case SLType::kShort3:
339cb93a386Sopenharmony_ci        case SLType::kShort4:
340cb93a386Sopenharmony_ci        case SLType::kUShort3:
341cb93a386Sopenharmony_ci        case SLType::kUShort4:
342cb93a386Sopenharmony_ci        case SLType::kHalf3:
343cb93a386Sopenharmony_ci        case SLType::kHalf4:
344cb93a386Sopenharmony_ci            return 0x7;
345cb93a386Sopenharmony_ci
346cb93a386Sopenharmony_ci        case SLType::kHalf2x2:
347cb93a386Sopenharmony_ci            return 0x3;
348cb93a386Sopenharmony_ci        case SLType::kHalf3x3:
349cb93a386Sopenharmony_ci            return 0x7;
350cb93a386Sopenharmony_ci        case SLType::kHalf4x4:
351cb93a386Sopenharmony_ci            return 0x7;
352cb93a386Sopenharmony_ci
353cb93a386Sopenharmony_ci        // This query is only valid for certain types.
354cb93a386Sopenharmony_ci        case SLType::kVoid:
355cb93a386Sopenharmony_ci        case SLType::kBool:
356cb93a386Sopenharmony_ci        case SLType::kBool2:
357cb93a386Sopenharmony_ci        case SLType::kBool3:
358cb93a386Sopenharmony_ci        case SLType::kBool4:
359cb93a386Sopenharmony_ci        case SLType::kTexture2DSampler:
360cb93a386Sopenharmony_ci        case SLType::kTextureExternalSampler:
361cb93a386Sopenharmony_ci        case SLType::kTexture2DRectSampler:
362cb93a386Sopenharmony_ci        case SLType::kSampler:
363cb93a386Sopenharmony_ci        case SLType::kTexture2D:
364cb93a386Sopenharmony_ci        case SLType::kInput:
365cb93a386Sopenharmony_ci            break;
366cb93a386Sopenharmony_ci    }
367cb93a386Sopenharmony_ci    SK_ABORT("Unexpected type");
368cb93a386Sopenharmony_ci}
369cb93a386Sopenharmony_ci
370cb93a386Sopenharmony_ci/** Returns the size in bytes taken up in Metal buffers for GrSLTypes. */
371cb93a386Sopenharmony_ciinline uint32_t sltype_to_mtl_size(SLType type) {
372cb93a386Sopenharmony_ci    switch (type) {
373cb93a386Sopenharmony_ci        case SLType::kInt:
374cb93a386Sopenharmony_ci        case SLType::kUInt:
375cb93a386Sopenharmony_ci        case SLType::kFloat:
376cb93a386Sopenharmony_ci            return 4;
377cb93a386Sopenharmony_ci        case SLType::kInt2:
378cb93a386Sopenharmony_ci        case SLType::kUInt2:
379cb93a386Sopenharmony_ci        case SLType::kFloat2:
380cb93a386Sopenharmony_ci            return 8;
381cb93a386Sopenharmony_ci        case SLType::kInt3:
382cb93a386Sopenharmony_ci        case SLType::kUInt3:
383cb93a386Sopenharmony_ci        case SLType::kFloat3:
384cb93a386Sopenharmony_ci        case SLType::kInt4:
385cb93a386Sopenharmony_ci        case SLType::kUInt4:
386cb93a386Sopenharmony_ci        case SLType::kFloat4:
387cb93a386Sopenharmony_ci            return 16;
388cb93a386Sopenharmony_ci
389cb93a386Sopenharmony_ci        case SLType::kFloat2x2:
390cb93a386Sopenharmony_ci            return 16;
391cb93a386Sopenharmony_ci        case SLType::kFloat3x3:
392cb93a386Sopenharmony_ci            return 48;
393cb93a386Sopenharmony_ci        case SLType::kFloat4x4:
394cb93a386Sopenharmony_ci            return 64;
395cb93a386Sopenharmony_ci
396cb93a386Sopenharmony_ci        case SLType::kShort:
397cb93a386Sopenharmony_ci        case SLType::kUShort:
398cb93a386Sopenharmony_ci        case SLType::kHalf:
399cb93a386Sopenharmony_ci            return 2;
400cb93a386Sopenharmony_ci        case SLType::kShort2:
401cb93a386Sopenharmony_ci        case SLType::kUShort2:
402cb93a386Sopenharmony_ci        case SLType::kHalf2:
403cb93a386Sopenharmony_ci            return 4;
404cb93a386Sopenharmony_ci        case SLType::kShort3:
405cb93a386Sopenharmony_ci        case SLType::kShort4:
406cb93a386Sopenharmony_ci        case SLType::kUShort3:
407cb93a386Sopenharmony_ci        case SLType::kUShort4:
408cb93a386Sopenharmony_ci        case SLType::kHalf3:
409cb93a386Sopenharmony_ci        case SLType::kHalf4:
410cb93a386Sopenharmony_ci            return 8;
411cb93a386Sopenharmony_ci
412cb93a386Sopenharmony_ci        case SLType::kHalf2x2:
413cb93a386Sopenharmony_ci            return 8;
414cb93a386Sopenharmony_ci        case SLType::kHalf3x3:
415cb93a386Sopenharmony_ci            return 24;
416cb93a386Sopenharmony_ci        case SLType::kHalf4x4:
417cb93a386Sopenharmony_ci            return 32;
418cb93a386Sopenharmony_ci
419cb93a386Sopenharmony_ci        // This query is only valid for certain types.
420cb93a386Sopenharmony_ci        case SLType::kVoid:
421cb93a386Sopenharmony_ci        case SLType::kBool:
422cb93a386Sopenharmony_ci        case SLType::kBool2:
423cb93a386Sopenharmony_ci        case SLType::kBool3:
424cb93a386Sopenharmony_ci        case SLType::kBool4:
425cb93a386Sopenharmony_ci        case SLType::kTexture2DSampler:
426cb93a386Sopenharmony_ci        case SLType::kTextureExternalSampler:
427cb93a386Sopenharmony_ci        case SLType::kTexture2DRectSampler:
428cb93a386Sopenharmony_ci        case SLType::kSampler:
429cb93a386Sopenharmony_ci        case SLType::kTexture2D:
430cb93a386Sopenharmony_ci        case SLType::kInput:
431cb93a386Sopenharmony_ci            break;
432cb93a386Sopenharmony_ci    }
433cb93a386Sopenharmony_ci    SK_ABORT("Unexpected type");
434cb93a386Sopenharmony_ci}
435cb93a386Sopenharmony_ci
436cb93a386Sopenharmony_ci// Given the current offset into the ubo, calculate the offset for the uniform we're trying to add
437cb93a386Sopenharmony_ci// taking into consideration all alignment requirements. The uniformOffset is set to the offset for
438cb93a386Sopenharmony_ci// the new uniform, and currentOffset is updated to be the offset to the end of the new uniform.
439cb93a386Sopenharmony_cistatic uint32_t get_ubo_aligned_offset(uint32_t* currentOffset,
440cb93a386Sopenharmony_ci                                       uint32_t* maxAlignment,
441cb93a386Sopenharmony_ci                                       SLType type,
442cb93a386Sopenharmony_ci                                       int arrayCount) {
443cb93a386Sopenharmony_ci    uint32_t alignmentMask = sltype_to_alignment_mask(type);
444cb93a386Sopenharmony_ci    if (alignmentMask > *maxAlignment) {
445cb93a386Sopenharmony_ci        *maxAlignment = alignmentMask;
446cb93a386Sopenharmony_ci    }
447cb93a386Sopenharmony_ci    uint32_t offsetDiff = *currentOffset & alignmentMask;
448cb93a386Sopenharmony_ci    if (offsetDiff != 0) {
449cb93a386Sopenharmony_ci        offsetDiff = alignmentMask - offsetDiff + 1;
450cb93a386Sopenharmony_ci    }
451cb93a386Sopenharmony_ci    uint32_t uniformOffset = *currentOffset + offsetDiff;
452cb93a386Sopenharmony_ci    SkASSERT(sizeof(float) == 4);
453cb93a386Sopenharmony_ci    if (arrayCount) {
454cb93a386Sopenharmony_ci        *currentOffset = uniformOffset + sltype_to_mtl_size(type) * arrayCount;
455cb93a386Sopenharmony_ci    } else {
456cb93a386Sopenharmony_ci        *currentOffset = uniformOffset + sltype_to_mtl_size(type);
457cb93a386Sopenharmony_ci    }
458cb93a386Sopenharmony_ci    return uniformOffset;
459cb93a386Sopenharmony_ci}
460cb93a386Sopenharmony_ci#endif // SK_DEBUG
461cb93a386Sopenharmony_ci
462cb93a386Sopenharmony_ciSLType UniformManager::getUniformTypeForLayout(SLType type) {
463cb93a386Sopenharmony_ci    if (fLayout != Layout::kMetal) {
464cb93a386Sopenharmony_ci        // GL/Vk expect uniforms in 32-bit precision. Convert lower-precision types to 32-bit.
465cb93a386Sopenharmony_ci        switch (type) {
466cb93a386Sopenharmony_ci            case SLType::kShort:            return SLType::kInt;
467cb93a386Sopenharmony_ci            case SLType::kUShort:           return SLType::kUInt;
468cb93a386Sopenharmony_ci            case SLType::kHalf:             return SLType::kFloat;
469cb93a386Sopenharmony_ci
470cb93a386Sopenharmony_ci            case SLType::kShort2:           return SLType::kInt2;
471cb93a386Sopenharmony_ci            case SLType::kUShort2:          return SLType::kUInt2;
472cb93a386Sopenharmony_ci            case SLType::kHalf2:            return SLType::kFloat2;
473cb93a386Sopenharmony_ci
474cb93a386Sopenharmony_ci            case SLType::kShort3:           return SLType::kInt3;
475cb93a386Sopenharmony_ci            case SLType::kUShort3:          return SLType::kUInt3;
476cb93a386Sopenharmony_ci            case SLType::kHalf3:            return SLType::kFloat3;
477cb93a386Sopenharmony_ci
478cb93a386Sopenharmony_ci            case SLType::kShort4:           return SLType::kInt4;
479cb93a386Sopenharmony_ci            case SLType::kUShort4:          return SLType::kUInt4;
480cb93a386Sopenharmony_ci            case SLType::kHalf4:            return SLType::kFloat4;
481cb93a386Sopenharmony_ci
482cb93a386Sopenharmony_ci            case SLType::kHalf2x2:          return SLType::kFloat2x2;
483cb93a386Sopenharmony_ci            case SLType::kHalf3x3:          return SLType::kFloat3x3;
484cb93a386Sopenharmony_ci            case SLType::kHalf4x4:          return SLType::kFloat4x4;
485cb93a386Sopenharmony_ci
486cb93a386Sopenharmony_ci            default:                        break;
487cb93a386Sopenharmony_ci        }
488cb93a386Sopenharmony_ci    }
489cb93a386Sopenharmony_ci
490cb93a386Sopenharmony_ci    return type;
491cb93a386Sopenharmony_ci}
492cb93a386Sopenharmony_ci
493cb93a386Sopenharmony_ciuint32_t UniformManager::writeUniforms(SkSpan<const Uniform> uniforms,
494cb93a386Sopenharmony_ci                                       void** srcs,
495cb93a386Sopenharmony_ci                                       uint32_t* offsets,
496cb93a386Sopenharmony_ci                                       void *dst) {
497cb93a386Sopenharmony_ci    decltype(&Writer<Rules140>::WriteUniform) write;
498cb93a386Sopenharmony_ci    switch (fLayout) {
499cb93a386Sopenharmony_ci        case Layout::kStd140:
500cb93a386Sopenharmony_ci            write = Writer<Rules140>::WriteUniform;
501cb93a386Sopenharmony_ci            break;
502cb93a386Sopenharmony_ci        case Layout::kStd430:
503cb93a386Sopenharmony_ci            write = Writer<Rules430>::WriteUniform;
504cb93a386Sopenharmony_ci            break;
505cb93a386Sopenharmony_ci        case Layout::kMetal:
506cb93a386Sopenharmony_ci            write = Writer<RulesMetal>::WriteUniform;
507cb93a386Sopenharmony_ci            break;
508cb93a386Sopenharmony_ci    }
509cb93a386Sopenharmony_ci
510cb93a386Sopenharmony_ci#ifdef SK_DEBUG
511cb93a386Sopenharmony_ci    uint32_t curUBOOffset = 0;
512cb93a386Sopenharmony_ci    uint32_t curUBOMaxAlignment = 0;
513cb93a386Sopenharmony_ci#endif // SK_DEBUG
514cb93a386Sopenharmony_ci
515cb93a386Sopenharmony_ci    uint32_t offset = 0;
516cb93a386Sopenharmony_ci
517cb93a386Sopenharmony_ci    for (int i = 0; i < (int) uniforms.size(); ++i) {
518cb93a386Sopenharmony_ci        const Uniform& u = uniforms[i];
519cb93a386Sopenharmony_ci        SLType uniformType = this->getUniformTypeForLayout(u.type());
520cb93a386Sopenharmony_ci
521cb93a386Sopenharmony_ci#ifdef SK_DEBUG
522cb93a386Sopenharmony_ci        uint32_t debugOffset = get_ubo_aligned_offset(&curUBOOffset,
523cb93a386Sopenharmony_ci                                                      &curUBOMaxAlignment,
524cb93a386Sopenharmony_ci                                                      uniformType,
525cb93a386Sopenharmony_ci                                                      u.count());
526cb93a386Sopenharmony_ci#endif // SK_DEBUG
527cb93a386Sopenharmony_ci
528cb93a386Sopenharmony_ci        uint32_t bytesWritten = write(uniformType,
529cb93a386Sopenharmony_ci                                      CType::kDefault,
530cb93a386Sopenharmony_ci                                      dst,
531cb93a386Sopenharmony_ci                                      u.count(),
532cb93a386Sopenharmony_ci                                      srcs ? srcs[i] : nullptr);
533cb93a386Sopenharmony_ci        SkASSERT(debugOffset == offset);
534cb93a386Sopenharmony_ci
535cb93a386Sopenharmony_ci        if (offsets) {
536cb93a386Sopenharmony_ci            offsets[i] = offset;
537cb93a386Sopenharmony_ci        }
538cb93a386Sopenharmony_ci        offset += bytesWritten;
539cb93a386Sopenharmony_ci    }
540cb93a386Sopenharmony_ci
541cb93a386Sopenharmony_ci    return offset;
542cb93a386Sopenharmony_ci}
543cb93a386Sopenharmony_ci
544cb93a386Sopenharmony_ci} // namespace skgpu
545