• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2021 Google LLC
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #include "src/gpu/graphite/UniformManager.h"
9 
10 #include "src/gpu/graphite/PipelineData.h"
11 
12 // ensure that these types are the sizes the uniform data is expecting
13 static_assert(sizeof(int32_t) == 4);
14 static_assert(sizeof(float) == 4);
15 static_assert(sizeof(SkHalf) == 2);
16 
17 namespace skgpu::graphite {
18 
advanceOffset(SkSLType type,int count)19 int UniformOffsetCalculator::advanceOffset(SkSLType type, int count) {
20     SkASSERT(SkSLTypeCanBeUniformValue(type));
21 
22     int dimension = SkSLTypeMatrixSize(type);
23     if (dimension > 0) {
24         // All SkSL matrices are square and can be interpreted as an array of column vectors
25         count = std::max(count, 1) * dimension;
26     } else {
27         dimension = SkSLTypeVecLength(type);
28     }
29     SkASSERT(1 <= dimension && dimension <= 4);
30 
31     // Bump dimension up to 4 if the array or vec3 consumes 4 primitives per element
32     // NOTE: This affects the size, alignment already rounds up to a power of 2 automatically.
33     const bool isArray = count > Uniform::kNonArray;
34     if ((isArray && LayoutRules::AlignArraysAsVec4(fLayout)) ||
35         (dimension == 3 && (isArray || LayoutRules::PadVec3Size(fLayout)))) {
36         dimension = 4;
37     }
38 
39     const int primitiveSize = LayoutRules::UseFullPrecision(fLayout) ||
40                               SkSLTypeIsFullPrecisionNumericType(type) ? 4 : 2;
41     const int align = SkNextPow2(dimension) * primitiveSize;
42     const int alignedOffset = SkAlignTo(fOffset, align);
43     fOffset = alignedOffset + dimension * primitiveSize * std::max(count, 1);
44     fReqAlignment = std::max(fReqAlignment, align);
45 
46     return alignedOffset;
47 }
48 
49 //////////////////////////////////////////////////////////////////////////////
50 
finishUniformDataBlock()51 UniformDataBlock UniformManager::finishUniformDataBlock() {
52     size_t size = SkAlignTo(fStorage.size(), fReqAlignment);
53     size_t paddingSize = size - fStorage.size();
54     if (paddingSize > 0) {
55         char* padding = fStorage.append(paddingSize);
56         memset(padding, 0, paddingSize);
57     }
58     return UniformDataBlock(SkSpan(fStorage.begin(), size));
59 }
60 
resetWithNewLayout(Layout layout)61 void UniformManager::resetWithNewLayout(Layout layout) {
62     fStorage.clear();
63     fLayout = layout;
64     fReqAlignment = 0;
65     fWrotePaintColor = false;
66 
67 #ifdef SK_DEBUG
68     fOffsetCalculator = UniformOffsetCalculator(layout, 0);
69     fExpectedUniforms = {};
70     fExpectedUniformIndex = 0;
71 #endif
72 }
73 
adjust_for_matrix_type(SkSLType type,int count)74 static std::pair<SkSLType, int> adjust_for_matrix_type(SkSLType type, int count) {
75     // All Layouts flatten matrices and arrays of matrices into arrays of columns, so update
76     // 'type' to be the column type and either multiply 'count' by the number of columns for
77     // arrays of matrices, or set to exactly the number of columns for a "non-array" matrix.
78     switch(type) {
79         case SkSLType::kFloat2x2: return {SkSLType::kFloat2, 2*std::max(1, count)};
80         case SkSLType::kFloat3x3: return {SkSLType::kFloat3, 3*std::max(1, count)};
81         case SkSLType::kFloat4x4: return {SkSLType::kFloat4, 4*std::max(1, count)};
82 
83         case SkSLType::kHalf2x2:  return {SkSLType::kHalf2,  2*std::max(1, count)};
84         case SkSLType::kHalf3x3:  return {SkSLType::kHalf3,  3*std::max(1, count)};
85         case SkSLType::kHalf4x4:  return {SkSLType::kHalf4,  4*std::max(1, count)};
86 
87         // Otherwise leave type and count alone.
88         default:                  return {type, count};
89     }
90 }
91 
write(const Uniform & u,const void * data)92 void UniformManager::write(const Uniform& u, const void* data) {
93     SkASSERT(SkSLTypeCanBeUniformValue(u.type()));
94     SkASSERT(!u.isPaintColor()); // Must go through writePaintColor()
95 
96     auto [type, count] = adjust_for_matrix_type(u.type(), u.count());
97     SkASSERT(SkSLTypeMatrixSize(type) < 0); // Matrix types should have been flattened
98 
99     const bool fullPrecision = LayoutRules::UseFullPrecision(fLayout) || !IsHalfVector(type);
100     if (count == Uniform::kNonArray) {
101         if (fullPrecision) {
102             switch(SkSLTypeVecLength(type)) {
103                 case 1: this->write<1, /*Half=*/false>(data, type); break;
104                 case 2: this->write<2, /*Half=*/false>(data, type); break;
105                 case 3: this->write<3, /*Half=*/false>(data, type); break;
106                 case 4: this->write<4, /*Half=*/false>(data, type); break;
107             }
108         } else {
109             switch(SkSLTypeVecLength(type)) {
110                 case 1: this->write<1, /*Half=*/true>(data, type); break;
111                 case 2: this->write<2, /*Half=*/true>(data, type); break;
112                 case 3: this->write<3, /*Half=*/true>(data, type); break;
113                 case 4: this->write<4, /*Half=*/true>(data, type); break;
114             }
115         }
116     } else {
117         if (fullPrecision) {
118             switch(SkSLTypeVecLength(type)) {
119                 case 1: this->writeArray<1, /*Half=*/false>(data, count, type); break;
120                 case 2: this->writeArray<2, /*Half=*/false>(data, count, type); break;
121                 case 3: this->writeArray<3, /*Half=*/false>(data, count, type); break;
122                 case 4: this->writeArray<4, /*Half=*/false>(data, count, type); break;
123             }
124         } else {
125             switch(SkSLTypeVecLength(type)) {
126                 case 1: this->writeArray<1, /*Half=*/true>(data, count, type); break;
127                 case 2: this->writeArray<2, /*Half=*/true>(data, count, type); break;
128                 case 3: this->writeArray<3, /*Half=*/true>(data, count, type); break;
129                 case 4: this->writeArray<4, /*Half=*/true>(data, count, type); break;
130             }
131         }
132     }
133 }
134 
135 #ifdef SK_DEBUG
136 
checkExpected(const void * dst,SkSLType type,int count)137 bool UniformManager::checkExpected(const void* dst, SkSLType type, int count) {
138     if (fExpectedUniformIndex >= (int) fExpectedUniforms.size()) {
139         // A write() outside of a UniformExpectationsVisitor or too many uniforms written for what
140         // is expected.
141         return false;
142     }
143 
144     const Uniform& expected = fExpectedUniforms[fExpectedUniformIndex++];
145     if (!SkSLTypeCanBeUniformValue(expected.type())) {
146         // Not all types are supported as uniforms or supported by UniformManager
147         return false;
148     }
149 
150     auto [expectedType, expectedCount] = adjust_for_matrix_type(expected.type(), expected.count());
151     if (expectedType != type || expectedCount != count) {
152         return false;
153     }
154 
155     if (dst) {
156         // If we have 'dst', it's the aligned starting offset of the uniform being checked, so
157         // subtracting the address of the first byte in fStorage gives us the offset.
158         int offset = static_cast<int>(reinterpret_cast<intptr_t>(dst) -
159                                       reinterpret_cast<intptr_t>(fStorage.data()));
160         // Pass original expected type and count to the offset calculator for validation.
161         if (offset != fOffsetCalculator.advanceOffset(expected.type(), expected.count())) {
162             return false;
163         }
164         if (fReqAlignment != fOffsetCalculator.requiredAlignment()) {
165             return false;
166         }
167         // And if it is the paint color uniform, we should not have already written it
168         return !(fWrotePaintColor && expected.isPaintColor());
169     } else {
170         // If 'dst' is null, it's an already-visited paint color uniform, so it's not being written
171         // and not changing the offset.
172         SkASSERT(fWrotePaintColor);
173         return expected.isPaintColor();
174     }
175 }
176 
isReset() const177 bool UniformManager::isReset() const {
178     return fStorage.empty();
179 }
180 
setExpectedUniforms(SkSpan<const Uniform> expected)181 void UniformManager::setExpectedUniforms(SkSpan<const Uniform> expected) {
182     fExpectedUniforms = expected;
183     fExpectedUniformIndex = 0;
184 }
185 
doneWithExpectedUniforms()186 void UniformManager::doneWithExpectedUniforms() {
187     SkASSERT(fExpectedUniformIndex == static_cast<int>(fExpectedUniforms.size()));
188     fExpectedUniforms = {};
189 }
190 
191 #endif // SK_DEBUG
192 
193 } // namespace skgpu::graphite
194