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