xref: /aosp_15_r20/external/skia/src/gpu/graphite/UniformManager.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker  * Copyright 2021 Google LLC
3*c8dee2aaSAndroid Build Coastguard Worker  *
4*c8dee2aaSAndroid Build Coastguard Worker  * Use of this source code is governed by a BSD-style license that can be
5*c8dee2aaSAndroid Build Coastguard Worker  * found in the LICENSE file.
6*c8dee2aaSAndroid Build Coastguard Worker  */
7*c8dee2aaSAndroid Build Coastguard Worker 
8*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/UniformManager.h"
9*c8dee2aaSAndroid Build Coastguard Worker 
10*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/PipelineData.h"
11*c8dee2aaSAndroid Build Coastguard Worker 
12*c8dee2aaSAndroid Build Coastguard Worker // ensure that these types are the sizes the uniform data is expecting
13*c8dee2aaSAndroid Build Coastguard Worker static_assert(sizeof(int32_t) == 4);
14*c8dee2aaSAndroid Build Coastguard Worker static_assert(sizeof(float) == 4);
15*c8dee2aaSAndroid Build Coastguard Worker static_assert(sizeof(SkHalf) == 2);
16*c8dee2aaSAndroid Build Coastguard Worker 
17*c8dee2aaSAndroid Build Coastguard Worker namespace skgpu::graphite {
18*c8dee2aaSAndroid Build Coastguard Worker 
advanceOffset(SkSLType type,int count)19*c8dee2aaSAndroid Build Coastguard Worker int UniformOffsetCalculator::advanceOffset(SkSLType type, int count) {
20*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(SkSLTypeCanBeUniformValue(type));
21*c8dee2aaSAndroid Build Coastguard Worker 
22*c8dee2aaSAndroid Build Coastguard Worker     int dimension = SkSLTypeMatrixSize(type);
23*c8dee2aaSAndroid Build Coastguard Worker     if (dimension > 0) {
24*c8dee2aaSAndroid Build Coastguard Worker         // All SkSL matrices are square and can be interpreted as an array of column vectors
25*c8dee2aaSAndroid Build Coastguard Worker         count = std::max(count, 1) * dimension;
26*c8dee2aaSAndroid Build Coastguard Worker     } else {
27*c8dee2aaSAndroid Build Coastguard Worker         dimension = SkSLTypeVecLength(type);
28*c8dee2aaSAndroid Build Coastguard Worker     }
29*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(1 <= dimension && dimension <= 4);
30*c8dee2aaSAndroid Build Coastguard Worker 
31*c8dee2aaSAndroid Build Coastguard Worker     // Bump dimension up to 4 if the array or vec3 consumes 4 primitives per element
32*c8dee2aaSAndroid Build Coastguard Worker     // NOTE: This affects the size, alignment already rounds up to a power of 2 automatically.
33*c8dee2aaSAndroid Build Coastguard Worker     const bool isArray = count > Uniform::kNonArray;
34*c8dee2aaSAndroid Build Coastguard Worker     if ((isArray && LayoutRules::AlignArraysAsVec4(fLayout)) ||
35*c8dee2aaSAndroid Build Coastguard Worker         (dimension == 3 && (isArray || LayoutRules::PadVec3Size(fLayout)))) {
36*c8dee2aaSAndroid Build Coastguard Worker         dimension = 4;
37*c8dee2aaSAndroid Build Coastguard Worker     }
38*c8dee2aaSAndroid Build Coastguard Worker 
39*c8dee2aaSAndroid Build Coastguard Worker     const int primitiveSize = LayoutRules::UseFullPrecision(fLayout) ||
40*c8dee2aaSAndroid Build Coastguard Worker                               SkSLTypeIsFullPrecisionNumericType(type) ? 4 : 2;
41*c8dee2aaSAndroid Build Coastguard Worker     const int align = SkNextPow2(dimension) * primitiveSize;
42*c8dee2aaSAndroid Build Coastguard Worker     const int alignedOffset = SkAlignTo(fOffset, align);
43*c8dee2aaSAndroid Build Coastguard Worker     fOffset = alignedOffset + dimension * primitiveSize * std::max(count, 1);
44*c8dee2aaSAndroid Build Coastguard Worker     fReqAlignment = std::max(fReqAlignment, align);
45*c8dee2aaSAndroid Build Coastguard Worker 
46*c8dee2aaSAndroid Build Coastguard Worker     return alignedOffset;
47*c8dee2aaSAndroid Build Coastguard Worker }
48*c8dee2aaSAndroid Build Coastguard Worker 
advanceStruct(const UniformOffsetCalculator & substruct,int count)49*c8dee2aaSAndroid Build Coastguard Worker int UniformOffsetCalculator::advanceStruct(const UniformOffsetCalculator& substruct, int count) {
50*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(substruct.fLayout == fLayout); // Invalid if the layout rules used aren't consistent
51*c8dee2aaSAndroid Build Coastguard Worker 
52*c8dee2aaSAndroid Build Coastguard Worker     // If array element strides are forced to 16-byte alignment, structs must also have their
53*c8dee2aaSAndroid Build Coastguard Worker     // base alignment rounded up to 16-byte alignment, which should have been accounted for in
54*c8dee2aaSAndroid Build Coastguard Worker     // 'substruct's constructor.
55*c8dee2aaSAndroid Build Coastguard Worker     const int baseAlignment = substruct.requiredAlignment();
56*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(!LayoutRules::AlignArraysAsVec4(fLayout) || SkIsAlign16(baseAlignment));
57*c8dee2aaSAndroid Build Coastguard Worker 
58*c8dee2aaSAndroid Build Coastguard Worker     // Per layout rule #9, the struct size must be padded to its base alignment
59*c8dee2aaSAndroid Build Coastguard Worker     // (see https://registry.khronos.org/OpenGL/specs/gl/glspec45.core.pdf#page=159).
60*c8dee2aaSAndroid Build Coastguard Worker     const int alignedSize = SkAlignTo(substruct.size(), baseAlignment);
61*c8dee2aaSAndroid Build Coastguard Worker 
62*c8dee2aaSAndroid Build Coastguard Worker     const int alignedOffset = SkAlignTo(fOffset, baseAlignment);
63*c8dee2aaSAndroid Build Coastguard Worker     fOffset = alignedOffset + alignedSize * std::max(count, 1);
64*c8dee2aaSAndroid Build Coastguard Worker     fReqAlignment = std::max(fReqAlignment, baseAlignment);
65*c8dee2aaSAndroid Build Coastguard Worker 
66*c8dee2aaSAndroid Build Coastguard Worker     return alignedOffset;
67*c8dee2aaSAndroid Build Coastguard Worker }
68*c8dee2aaSAndroid Build Coastguard Worker 
69*c8dee2aaSAndroid Build Coastguard Worker //////////////////////////////////////////////////////////////////////////////
70*c8dee2aaSAndroid Build Coastguard Worker 
resetWithNewLayout(Layout layout)71*c8dee2aaSAndroid Build Coastguard Worker void UniformManager::resetWithNewLayout(Layout layout) {
72*c8dee2aaSAndroid Build Coastguard Worker     fStorage.clear();
73*c8dee2aaSAndroid Build Coastguard Worker     fLayout = layout;
74*c8dee2aaSAndroid Build Coastguard Worker     fReqAlignment = 0;
75*c8dee2aaSAndroid Build Coastguard Worker     fStructBaseAlignment = 0;
76*c8dee2aaSAndroid Build Coastguard Worker     fWrotePaintColor = false;
77*c8dee2aaSAndroid Build Coastguard Worker 
78*c8dee2aaSAndroid Build Coastguard Worker #ifdef SK_DEBUG
79*c8dee2aaSAndroid Build Coastguard Worker     fOffsetCalculator = UniformOffsetCalculator::ForTopLevel(layout);
80*c8dee2aaSAndroid Build Coastguard Worker     fSubstructCalculator = {};
81*c8dee2aaSAndroid Build Coastguard Worker     fExpectedUniforms = {};
82*c8dee2aaSAndroid Build Coastguard Worker     fExpectedUniformIndex = 0;
83*c8dee2aaSAndroid Build Coastguard Worker #endif
84*c8dee2aaSAndroid Build Coastguard Worker }
85*c8dee2aaSAndroid Build Coastguard Worker 
adjust_for_matrix_type(SkSLType type,int count)86*c8dee2aaSAndroid Build Coastguard Worker static std::pair<SkSLType, int> adjust_for_matrix_type(SkSLType type, int count) {
87*c8dee2aaSAndroid Build Coastguard Worker     // All Layouts flatten matrices and arrays of matrices into arrays of columns, so update
88*c8dee2aaSAndroid Build Coastguard Worker     // 'type' to be the column type and either multiply 'count' by the number of columns for
89*c8dee2aaSAndroid Build Coastguard Worker     // arrays of matrices, or set to exactly the number of columns for a "non-array" matrix.
90*c8dee2aaSAndroid Build Coastguard Worker     switch(type) {
91*c8dee2aaSAndroid Build Coastguard Worker         case SkSLType::kFloat2x2: return {SkSLType::kFloat2, 2*std::max(1, count)};
92*c8dee2aaSAndroid Build Coastguard Worker         case SkSLType::kFloat3x3: return {SkSLType::kFloat3, 3*std::max(1, count)};
93*c8dee2aaSAndroid Build Coastguard Worker         case SkSLType::kFloat4x4: return {SkSLType::kFloat4, 4*std::max(1, count)};
94*c8dee2aaSAndroid Build Coastguard Worker 
95*c8dee2aaSAndroid Build Coastguard Worker         case SkSLType::kHalf2x2:  return {SkSLType::kHalf2,  2*std::max(1, count)};
96*c8dee2aaSAndroid Build Coastguard Worker         case SkSLType::kHalf3x3:  return {SkSLType::kHalf3,  3*std::max(1, count)};
97*c8dee2aaSAndroid Build Coastguard Worker         case SkSLType::kHalf4x4:  return {SkSLType::kHalf4,  4*std::max(1, count)};
98*c8dee2aaSAndroid Build Coastguard Worker 
99*c8dee2aaSAndroid Build Coastguard Worker         // Otherwise leave type and count alone.
100*c8dee2aaSAndroid Build Coastguard Worker         default:                  return {type, count};
101*c8dee2aaSAndroid Build Coastguard Worker     }
102*c8dee2aaSAndroid Build Coastguard Worker }
103*c8dee2aaSAndroid Build Coastguard Worker 
write(const Uniform & u,const void * data)104*c8dee2aaSAndroid Build Coastguard Worker void UniformManager::write(const Uniform& u, const void* data) {
105*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(SkSLTypeCanBeUniformValue(u.type()));
106*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(!u.isPaintColor()); // Must go through writePaintColor()
107*c8dee2aaSAndroid Build Coastguard Worker 
108*c8dee2aaSAndroid Build Coastguard Worker     auto [type, count] = adjust_for_matrix_type(u.type(), u.count());
109*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(SkSLTypeMatrixSize(type) < 0); // Matrix types should have been flattened
110*c8dee2aaSAndroid Build Coastguard Worker 
111*c8dee2aaSAndroid Build Coastguard Worker     const bool fullPrecision = LayoutRules::UseFullPrecision(fLayout) || !IsHalfVector(type);
112*c8dee2aaSAndroid Build Coastguard Worker     if (count == Uniform::kNonArray) {
113*c8dee2aaSAndroid Build Coastguard Worker         if (fullPrecision) {
114*c8dee2aaSAndroid Build Coastguard Worker             switch(SkSLTypeVecLength(type)) {
115*c8dee2aaSAndroid Build Coastguard Worker                 case 1: this->write<1, /*Half=*/false>(data, type); break;
116*c8dee2aaSAndroid Build Coastguard Worker                 case 2: this->write<2, /*Half=*/false>(data, type); break;
117*c8dee2aaSAndroid Build Coastguard Worker                 case 3: this->write<3, /*Half=*/false>(data, type); break;
118*c8dee2aaSAndroid Build Coastguard Worker                 case 4: this->write<4, /*Half=*/false>(data, type); break;
119*c8dee2aaSAndroid Build Coastguard Worker             }
120*c8dee2aaSAndroid Build Coastguard Worker         } else {
121*c8dee2aaSAndroid Build Coastguard Worker             switch(SkSLTypeVecLength(type)) {
122*c8dee2aaSAndroid Build Coastguard Worker                 case 1: this->write<1, /*Half=*/true>(data, type); break;
123*c8dee2aaSAndroid Build Coastguard Worker                 case 2: this->write<2, /*Half=*/true>(data, type); break;
124*c8dee2aaSAndroid Build Coastguard Worker                 case 3: this->write<3, /*Half=*/true>(data, type); break;
125*c8dee2aaSAndroid Build Coastguard Worker                 case 4: this->write<4, /*Half=*/true>(data, type); break;
126*c8dee2aaSAndroid Build Coastguard Worker             }
127*c8dee2aaSAndroid Build Coastguard Worker         }
128*c8dee2aaSAndroid Build Coastguard Worker     } else {
129*c8dee2aaSAndroid Build Coastguard Worker         if (fullPrecision) {
130*c8dee2aaSAndroid Build Coastguard Worker             switch(SkSLTypeVecLength(type)) {
131*c8dee2aaSAndroid Build Coastguard Worker                 case 1: this->writeArray<1, /*Half=*/false>(data, count, type); break;
132*c8dee2aaSAndroid Build Coastguard Worker                 case 2: this->writeArray<2, /*Half=*/false>(data, count, type); break;
133*c8dee2aaSAndroid Build Coastguard Worker                 case 3: this->writeArray<3, /*Half=*/false>(data, count, type); break;
134*c8dee2aaSAndroid Build Coastguard Worker                 case 4: this->writeArray<4, /*Half=*/false>(data, count, type); break;
135*c8dee2aaSAndroid Build Coastguard Worker             }
136*c8dee2aaSAndroid Build Coastguard Worker         } else {
137*c8dee2aaSAndroid Build Coastguard Worker             switch(SkSLTypeVecLength(type)) {
138*c8dee2aaSAndroid Build Coastguard Worker                 case 1: this->writeArray<1, /*Half=*/true>(data, count, type); break;
139*c8dee2aaSAndroid Build Coastguard Worker                 case 2: this->writeArray<2, /*Half=*/true>(data, count, type); break;
140*c8dee2aaSAndroid Build Coastguard Worker                 case 3: this->writeArray<3, /*Half=*/true>(data, count, type); break;
141*c8dee2aaSAndroid Build Coastguard Worker                 case 4: this->writeArray<4, /*Half=*/true>(data, count, type); break;
142*c8dee2aaSAndroid Build Coastguard Worker             }
143*c8dee2aaSAndroid Build Coastguard Worker         }
144*c8dee2aaSAndroid Build Coastguard Worker     }
145*c8dee2aaSAndroid Build Coastguard Worker }
146*c8dee2aaSAndroid Build Coastguard Worker 
147*c8dee2aaSAndroid Build Coastguard Worker #if defined(SK_DEBUG)
148*c8dee2aaSAndroid Build Coastguard Worker 
checkBeginStruct(int baseAlignment)149*c8dee2aaSAndroid Build Coastguard Worker bool UniformManager::checkBeginStruct(int baseAlignment) {
150*c8dee2aaSAndroid Build Coastguard Worker     if (fExpectedUniformIndex > 0) {
151*c8dee2aaSAndroid Build Coastguard Worker         return false; // Wrote a struct field before the struct was started
152*c8dee2aaSAndroid Build Coastguard Worker     }
153*c8dee2aaSAndroid Build Coastguard Worker     if (fSubstructCalculator.layout() == Layout::kInvalid) {
154*c8dee2aaSAndroid Build Coastguard Worker         return false; // Not expecting to start a struct
155*c8dee2aaSAndroid Build Coastguard Worker     }
156*c8dee2aaSAndroid Build Coastguard Worker     if (fStructBaseAlignment > 0) {
157*c8dee2aaSAndroid Build Coastguard Worker         return false; // Somehow already started a substruct
158*c8dee2aaSAndroid Build Coastguard Worker     }
159*c8dee2aaSAndroid Build Coastguard Worker     if (fExpectedUniforms.empty()) {
160*c8dee2aaSAndroid Build Coastguard Worker         return false; // Empty substructs are not allowed
161*c8dee2aaSAndroid Build Coastguard Worker     }
162*c8dee2aaSAndroid Build Coastguard Worker 
163*c8dee2aaSAndroid Build Coastguard Worker     // Assume the expected uniforms describe the whole substruct
164*c8dee2aaSAndroid Build Coastguard Worker     auto structCalculator = UniformOffsetCalculator::ForStruct(fLayout);
165*c8dee2aaSAndroid Build Coastguard Worker     for (const Uniform& f : fExpectedUniforms) {
166*c8dee2aaSAndroid Build Coastguard Worker         structCalculator.advanceOffset(f.type(), f.count());
167*c8dee2aaSAndroid Build Coastguard Worker     }
168*c8dee2aaSAndroid Build Coastguard Worker     if (baseAlignment != structCalculator.requiredAlignment()) {
169*c8dee2aaSAndroid Build Coastguard Worker         return false;
170*c8dee2aaSAndroid Build Coastguard Worker     }
171*c8dee2aaSAndroid Build Coastguard Worker     fSubstructStartingOffset = fOffsetCalculator.advanceStruct(structCalculator);
172*c8dee2aaSAndroid Build Coastguard Worker     return true;
173*c8dee2aaSAndroid Build Coastguard Worker }
174*c8dee2aaSAndroid Build Coastguard Worker 
checkEndStruct()175*c8dee2aaSAndroid Build Coastguard Worker bool UniformManager::checkEndStruct() {
176*c8dee2aaSAndroid Build Coastguard Worker     if (fExpectedUniformIndex != (int) fExpectedUniforms.size()) {
177*c8dee2aaSAndroid Build Coastguard Worker         return false; // Didn't write all the expected fields before ending the struct
178*c8dee2aaSAndroid Build Coastguard Worker     }
179*c8dee2aaSAndroid Build Coastguard Worker     if (fSubstructCalculator.layout() == Layout::kInvalid) {
180*c8dee2aaSAndroid Build Coastguard Worker         return false; // Not expecting a struct
181*c8dee2aaSAndroid Build Coastguard Worker     }
182*c8dee2aaSAndroid Build Coastguard Worker     if (fStructBaseAlignment <= 0) {
183*c8dee2aaSAndroid Build Coastguard Worker         return false; // Missing a beginStruct()
184*c8dee2aaSAndroid Build Coastguard Worker     }
185*c8dee2aaSAndroid Build Coastguard Worker 
186*c8dee2aaSAndroid Build Coastguard Worker     // `fStructCalculator` should now have been advanced equivalently to the substruct calculator
187*c8dee2aaSAndroid Build Coastguard Worker     // used in checkBeginStruct() to calculate the expected starting offset.
188*c8dee2aaSAndroid Build Coastguard Worker     const int structSize = SkAlignTo(fSubstructCalculator.size(),
189*c8dee2aaSAndroid Build Coastguard Worker                                      fSubstructCalculator.requiredAlignment());
190*c8dee2aaSAndroid Build Coastguard Worker     if (fStorage.size() != fSubstructStartingOffset + structSize) {
191*c8dee2aaSAndroid Build Coastguard Worker         return false; // Somehow didn't end on the correct boundary
192*c8dee2aaSAndroid Build Coastguard Worker     }
193*c8dee2aaSAndroid Build Coastguard Worker     if (fReqAlignment != fOffsetCalculator.requiredAlignment() ||
194*c8dee2aaSAndroid Build Coastguard Worker         fReqAlignment < fSubstructCalculator.requiredAlignment()) {
195*c8dee2aaSAndroid Build Coastguard Worker         return false; // UniformManager's alignment got out of sync with expected alignment
196*c8dee2aaSAndroid Build Coastguard Worker     }
197*c8dee2aaSAndroid Build Coastguard Worker 
198*c8dee2aaSAndroid Build Coastguard Worker     // Reset the substruct calculator to mark that the struct has been completed
199*c8dee2aaSAndroid Build Coastguard Worker     fSubstructCalculator = {};
200*c8dee2aaSAndroid Build Coastguard Worker     return true;
201*c8dee2aaSAndroid Build Coastguard Worker }
202*c8dee2aaSAndroid Build Coastguard Worker 
checkExpected(const void * dst,SkSLType type,int count)203*c8dee2aaSAndroid Build Coastguard Worker bool UniformManager::checkExpected(const void* dst, SkSLType type, int count) {
204*c8dee2aaSAndroid Build Coastguard Worker     if (fExpectedUniformIndex >= SkTo<int>(fExpectedUniforms.size())) {
205*c8dee2aaSAndroid Build Coastguard Worker         // A write() outside of a UniformExpectationsVisitor or too many uniforms written for what
206*c8dee2aaSAndroid Build Coastguard Worker         // is expected.
207*c8dee2aaSAndroid Build Coastguard Worker         return false;
208*c8dee2aaSAndroid Build Coastguard Worker     }
209*c8dee2aaSAndroid Build Coastguard Worker     if (fSubstructCalculator.layout() != Layout::kInvalid) {
210*c8dee2aaSAndroid Build Coastguard Worker         if (fStructBaseAlignment <= 0) {
211*c8dee2aaSAndroid Build Coastguard Worker             // A write() that should be inside a struct, but missing a call to beginStruct()
212*c8dee2aaSAndroid Build Coastguard Worker             return false;
213*c8dee2aaSAndroid Build Coastguard Worker         }
214*c8dee2aaSAndroid Build Coastguard Worker 
215*c8dee2aaSAndroid Build Coastguard Worker     } else if (fStructBaseAlignment > 0) {
216*c8dee2aaSAndroid Build Coastguard Worker         // A substruct was started when it shouldn't have been
217*c8dee2aaSAndroid Build Coastguard Worker         return false;
218*c8dee2aaSAndroid Build Coastguard Worker     }
219*c8dee2aaSAndroid Build Coastguard Worker 
220*c8dee2aaSAndroid Build Coastguard Worker     const Uniform& expected = fExpectedUniforms[fExpectedUniformIndex++];
221*c8dee2aaSAndroid Build Coastguard Worker     if (!SkSLTypeCanBeUniformValue(expected.type())) {
222*c8dee2aaSAndroid Build Coastguard Worker         // Not all types are supported as uniforms or supported by UniformManager
223*c8dee2aaSAndroid Build Coastguard Worker         return false;
224*c8dee2aaSAndroid Build Coastguard Worker     }
225*c8dee2aaSAndroid Build Coastguard Worker 
226*c8dee2aaSAndroid Build Coastguard Worker     auto [expectedType, expectedCount] = adjust_for_matrix_type(expected.type(), expected.count());
227*c8dee2aaSAndroid Build Coastguard Worker     if (expectedType != type || expectedCount != count) {
228*c8dee2aaSAndroid Build Coastguard Worker         return false;
229*c8dee2aaSAndroid Build Coastguard Worker     }
230*c8dee2aaSAndroid Build Coastguard Worker 
231*c8dee2aaSAndroid Build Coastguard Worker     if (dst) {
232*c8dee2aaSAndroid Build Coastguard Worker         // If we have 'dst', it's the aligned starting offset of the uniform being checked, so
233*c8dee2aaSAndroid Build Coastguard Worker         // subtracting the address of the first byte in fStorage gives us the offset.
234*c8dee2aaSAndroid Build Coastguard Worker         int offset = static_cast<int>(reinterpret_cast<intptr_t>(dst) -
235*c8dee2aaSAndroid Build Coastguard Worker                                       reinterpret_cast<intptr_t>(fStorage.data()));
236*c8dee2aaSAndroid Build Coastguard Worker 
237*c8dee2aaSAndroid Build Coastguard Worker         if (fSubstructCalculator.layout() == Layout::kInvalid) {
238*c8dee2aaSAndroid Build Coastguard Worker             // Pass original expected type and count to the offset calculator for validation.
239*c8dee2aaSAndroid Build Coastguard Worker             if (offset != fOffsetCalculator.advanceOffset(expected.type(), expected.count())) {
240*c8dee2aaSAndroid Build Coastguard Worker                 return false;
241*c8dee2aaSAndroid Build Coastguard Worker             }
242*c8dee2aaSAndroid Build Coastguard Worker             if (fReqAlignment != fOffsetCalculator.requiredAlignment()) {
243*c8dee2aaSAndroid Build Coastguard Worker                 return false;
244*c8dee2aaSAndroid Build Coastguard Worker             }
245*c8dee2aaSAndroid Build Coastguard Worker 
246*c8dee2aaSAndroid Build Coastguard Worker             // And if it is the paint color uniform, we should not have already written it
247*c8dee2aaSAndroid Build Coastguard Worker             return !(fWrotePaintColor && expected.isPaintColor());
248*c8dee2aaSAndroid Build Coastguard Worker         } else {
249*c8dee2aaSAndroid Build Coastguard Worker             int relOffset = fSubstructCalculator.advanceOffset(expected.type(), expected.count());
250*c8dee2aaSAndroid Build Coastguard Worker             if (offset != fSubstructStartingOffset + relOffset) {
251*c8dee2aaSAndroid Build Coastguard Worker                 return false;
252*c8dee2aaSAndroid Build Coastguard Worker             }
253*c8dee2aaSAndroid Build Coastguard Worker             // The overall required alignment might already be higher from prior fields, but should
254*c8dee2aaSAndroid Build Coastguard Worker             // be at least what's required by the substruct.
255*c8dee2aaSAndroid Build Coastguard Worker             if (fReqAlignment < fSubstructCalculator.requiredAlignment()) {
256*c8dee2aaSAndroid Build Coastguard Worker                 return false;
257*c8dee2aaSAndroid Build Coastguard Worker             }
258*c8dee2aaSAndroid Build Coastguard Worker 
259*c8dee2aaSAndroid Build Coastguard Worker             // And it should not be a paint color uniform within a substruct
260*c8dee2aaSAndroid Build Coastguard Worker             return !expected.isPaintColor();
261*c8dee2aaSAndroid Build Coastguard Worker         }
262*c8dee2aaSAndroid Build Coastguard Worker     } else {
263*c8dee2aaSAndroid Build Coastguard Worker         // If 'dst' is null, it's an already-visited paint color uniform, so it's not being written
264*c8dee2aaSAndroid Build Coastguard Worker         // and not changing the offset, and should not be part of a substruct.
265*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(fWrotePaintColor);
266*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(fSubstructCalculator.layout() == Layout::kInvalid);
267*c8dee2aaSAndroid Build Coastguard Worker         return expected.isPaintColor();
268*c8dee2aaSAndroid Build Coastguard Worker     }
269*c8dee2aaSAndroid Build Coastguard Worker }
270*c8dee2aaSAndroid Build Coastguard Worker 
isReset() const271*c8dee2aaSAndroid Build Coastguard Worker bool UniformManager::isReset() const {
272*c8dee2aaSAndroid Build Coastguard Worker     return fStorage.empty();
273*c8dee2aaSAndroid Build Coastguard Worker }
274*c8dee2aaSAndroid Build Coastguard Worker 
setExpectedUniforms(SkSpan<const Uniform> expected,bool isSubstruct)275*c8dee2aaSAndroid Build Coastguard Worker void UniformManager::setExpectedUniforms(SkSpan<const Uniform> expected, bool isSubstruct) {
276*c8dee2aaSAndroid Build Coastguard Worker     fExpectedUniforms = expected;
277*c8dee2aaSAndroid Build Coastguard Worker     fExpectedUniformIndex = 0;
278*c8dee2aaSAndroid Build Coastguard Worker 
279*c8dee2aaSAndroid Build Coastguard Worker     if (isSubstruct) {
280*c8dee2aaSAndroid Build Coastguard Worker         // Start collecting the subsequent uniforms with a 0-based offset to determine their
281*c8dee2aaSAndroid Build Coastguard Worker         // relative layout and required base alignment of the entire struct.
282*c8dee2aaSAndroid Build Coastguard Worker         fSubstructCalculator = UniformOffsetCalculator::ForStruct(fLayout);
283*c8dee2aaSAndroid Build Coastguard Worker     } else {
284*c8dee2aaSAndroid Build Coastguard Worker         // Expected uniforms will advance fOffsetCalculator directly
285*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(fSubstructCalculator.layout() == Layout::kInvalid);
286*c8dee2aaSAndroid Build Coastguard Worker     }
287*c8dee2aaSAndroid Build Coastguard Worker }
288*c8dee2aaSAndroid Build Coastguard Worker 
doneWithExpectedUniforms()289*c8dee2aaSAndroid Build Coastguard Worker void UniformManager::doneWithExpectedUniforms() {
290*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(fExpectedUniformIndex == static_cast<int>(fExpectedUniforms.size()));
291*c8dee2aaSAndroid Build Coastguard Worker     // Any expected substruct should have been ended and validated inside endStruct(); if this fails
292*c8dee2aaSAndroid Build Coastguard Worker     // it means there is a missing endStruct().
293*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(fSubstructCalculator.layout() == Layout::kInvalid);
294*c8dee2aaSAndroid Build Coastguard Worker     fExpectedUniforms = {};
295*c8dee2aaSAndroid Build Coastguard Worker }
296*c8dee2aaSAndroid Build Coastguard Worker 
297*c8dee2aaSAndroid Build Coastguard Worker #endif // SK_DEBUG
298*c8dee2aaSAndroid Build Coastguard Worker 
299*c8dee2aaSAndroid Build Coastguard Worker } // namespace skgpu::graphite
300