• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2014 Google Inc.
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/ganesh/GrGeometryProcessor.h"
9 
10 #include "src/core/SkMatrixPriv.h"
11 #include "src/gpu/KeyBuilder.h"
12 #include "src/gpu/ganesh/GrPipeline.h"
13 #include "src/gpu/ganesh/glsl/GrGLSLFragmentShaderBuilder.h"
14 #include "src/gpu/ganesh/glsl/GrGLSLProgramBuilder.h"
15 #include "src/gpu/ganesh/glsl/GrGLSLUniformHandler.h"
16 #include "src/gpu/ganesh/glsl/GrGLSLVarying.h"
17 
18 #include <queue>
19 
GrGeometryProcessor(ClassID classID)20 GrGeometryProcessor::GrGeometryProcessor(ClassID classID) : GrProcessor(classID) {}
21 
textureSampler(int i) const22 const GrGeometryProcessor::TextureSampler& GrGeometryProcessor::textureSampler(int i) const {
23     SkASSERT(i >= 0 && i < this->numTextureSamplers());
24     return this->onTextureSampler(i);
25 }
26 
ComputeCoordTransformsKey(const GrFragmentProcessor & fp)27 uint32_t GrGeometryProcessor::ComputeCoordTransformsKey(const GrFragmentProcessor& fp) {
28     // This is highly coupled with the code in ProgramImpl::collectTransforms().
29     uint32_t key = static_cast<uint32_t>(fp.sampleUsage().kind()) << 1;
30     // This needs to be updated if GP starts specializing varyings on additional matrix types.
31     if (fp.sampleUsage().hasPerspective()) {
32         key |= 0b1;
33     }
34     return key;
35 }
36 
getAttributeKey(skgpu::KeyBuilder * b) const37 void GrGeometryProcessor::getAttributeKey(skgpu::KeyBuilder* b) const {
38     b->appendComment("vertex attributes");
39     fVertexAttributes.addToKey(b);
40     b->appendComment("instance attributes");
41     fInstanceAttributes.addToKey(b);
42 }
43 
44 ///////////////////////////////////////////////////////////////////////////////////////////////////
45 
clamp_filter(GrTextureType type,GrSamplerState::Filter requestedFilter)46 static inline GrSamplerState::Filter clamp_filter(GrTextureType type,
47                                                   GrSamplerState::Filter requestedFilter) {
48     if (GrTextureTypeHasRestrictedSampling(type)) {
49         return std::min(requestedFilter, GrSamplerState::Filter::kLinear);
50     }
51     return requestedFilter;
52 }
53 
TextureSampler(GrSamplerState samplerState,const GrBackendFormat & backendFormat,const skgpu::Swizzle & swizzle)54 GrGeometryProcessor::TextureSampler::TextureSampler(GrSamplerState samplerState,
55                                                     const GrBackendFormat& backendFormat,
56                                                     const skgpu::Swizzle& swizzle) {
57     this->reset(samplerState, backendFormat, swizzle);
58 }
59 
reset(GrSamplerState samplerState,const GrBackendFormat & backendFormat,const skgpu::Swizzle & swizzle)60 void GrGeometryProcessor::TextureSampler::reset(GrSamplerState samplerState,
61                                                 const GrBackendFormat& backendFormat,
62                                                 const skgpu::Swizzle& swizzle) {
63     fSamplerState = samplerState;
64     fSamplerState = GrSamplerState(samplerState.wrapModeX(),
65                                    samplerState.wrapModeY(),
66                                    clamp_filter(backendFormat.textureType(), samplerState.filter()),
67                                    samplerState.mipmapMode());
68     fBackendFormat = backendFormat;
69     fSwizzle = swizzle;
70     fIsInitialized = true;
71 }
72 
73 //////////////////////////////////////////////////////////////////////////////
74 
75 using ProgramImpl = GrGeometryProcessor::ProgramImpl;
76 
77 std::tuple<ProgramImpl::FPCoordsMap, GrShaderVar>
emitCode(EmitArgs & args,const GrPipeline & pipeline)78 ProgramImpl::emitCode(EmitArgs& args, const GrPipeline& pipeline) {
79     GrGPArgs gpArgs;
80     this->onEmitCode(args, &gpArgs);
81 
82     FPCoordsMap transformMap = this->collectTransforms(args.fVertBuilder,
83                                                        args.fVaryingHandler,
84                                                        args.fUniformHandler,
85                                                        gpArgs.fLocalCoordShader,
86                                                        gpArgs.fLocalCoordVar,
87                                                        gpArgs.fPositionVar,
88                                                        pipeline);
89 
90     GrGLSLVertexBuilder* vBuilder = args.fVertBuilder;
91     // Emit the vertex position to the hardware in the normalized window coordinates it expects.
92     SkASSERT(SkSLType::kFloat2 == gpArgs.fPositionVar.getType() ||
93                 SkSLType::kFloat3 == gpArgs.fPositionVar.getType());
94     vBuilder->emitNormalizedSkPosition(gpArgs.fPositionVar.c_str(),
95                                         gpArgs.fPositionVar.getType());
96     if (SkSLType::kFloat2 == gpArgs.fPositionVar.getType()) {
97         args.fVaryingHandler->setNoPerspective();
98     }
99 
100     return {transformMap, gpArgs.fLocalCoordVar};
101 }
102 
collectTransforms(GrGLSLVertexBuilder * vb,GrGLSLVaryingHandler * varyingHandler,GrGLSLUniformHandler * uniformHandler,GrShaderType localCoordsShader,const GrShaderVar & localCoordsVar,const GrShaderVar & positionVar,const GrPipeline & pipeline)103 ProgramImpl::FPCoordsMap ProgramImpl::collectTransforms(GrGLSLVertexBuilder* vb,
104                                                         GrGLSLVaryingHandler* varyingHandler,
105                                                         GrGLSLUniformHandler* uniformHandler,
106                                                         GrShaderType localCoordsShader,
107                                                         const GrShaderVar& localCoordsVar,
108                                                         const GrShaderVar& positionVar,
109                                                         const GrPipeline& pipeline) {
110     SkASSERT(localCoordsVar.getType() == SkSLType::kFloat2 ||
111              localCoordsVar.getType() == SkSLType::kFloat3 ||
112              localCoordsVar.getType() == SkSLType::kVoid);
113     SkASSERT(positionVar.getType() == SkSLType::kFloat2 ||
114              positionVar.getType() == SkSLType::kFloat3 ||
115              positionVar.getType() == SkSLType::kVoid);
116 
117     auto baseLocalCoordFSVar = [&, baseLocalCoordVarying = GrGLSLVarying()]() mutable {
118         if (localCoordsShader == kFragment_GrShaderType) {
119             return localCoordsVar;
120         }
121         SkASSERT(localCoordsShader == kVertex_GrShaderType);
122         SkASSERT(SkSLTypeIsFloatType(localCoordsVar.getType()));
123         if (baseLocalCoordVarying.type() == SkSLType::kVoid) {
124             // Initialize to the GP provided coordinate
125             baseLocalCoordVarying = GrGLSLVarying(localCoordsVar.getType());
126             varyingHandler->addVarying("LocalCoord", &baseLocalCoordVarying);
127             vb->codeAppendf("%s = %s;\n",
128                             baseLocalCoordVarying.vsOut(),
129                             localCoordsVar.getName().c_str());
130         }
131         return baseLocalCoordVarying.fsInVar();
132     };
133 
134     bool canUsePosition = positionVar.getType() != SkSLType::kVoid;
135 
136     FPCoordsMap result;
137     // Performs a pre-order traversal of FP hierarchy rooted at fp and identifies FPs that are
138     // sampled with a series of matrices applied to local coords. For each such FP a varying is
139     // added to the varying handler and added to 'result'.
140     auto liftTransforms = [&, traversalIndex = 0](
141                                   auto& self,
142                                   const GrFragmentProcessor& fp,
143                                   bool hasPerspective,
144                                   const GrFragmentProcessor* lastMatrixFP = nullptr,
145                                   int lastMatrixTraversalIndex = -1,
146                                   BaseCoord baseCoord = BaseCoord::kLocal) mutable -> void {
147         ++traversalIndex;
148         if (localCoordsShader == kVertex_GrShaderType) {
149             switch (fp.sampleUsage().kind()) {
150                 case SkSL::SampleUsage::Kind::kNone:
151                     // This should only happen at the root. Otherwise how did this FP get added?
152                     SkASSERT(!fp.parent());
153                     break;
154                 case SkSL::SampleUsage::Kind::kPassThrough:
155                     break;
156                 case SkSL::SampleUsage::Kind::kUniformMatrix:
157                     // Update tracking of last matrix and matrix props.
158                     hasPerspective |= fp.sampleUsage().hasPerspective();
159                     lastMatrixFP = &fp;
160                     lastMatrixTraversalIndex = traversalIndex;
161                     break;
162                 case SkSL::SampleUsage::Kind::kFragCoord:
163                     hasPerspective = positionVar.getType() == SkSLType::kFloat3;
164                     lastMatrixFP = nullptr;
165                     lastMatrixTraversalIndex = -1;
166                     baseCoord = BaseCoord::kPosition;
167                     break;
168                 case SkSL::SampleUsage::Kind::kExplicit:
169                     baseCoord = BaseCoord::kNone;
170                     break;
171             }
172         } else {
173             // If the GP doesn't provide an interpolatable local coord then there is no hope to
174             // lift.
175             baseCoord = BaseCoord::kNone;
176         }
177 
178         auto& [varyingFSVar, hasCoordsParam] = result[&fp];
179         hasCoordsParam = fp.usesSampleCoordsDirectly();
180 
181         // We add a varying if we're in a chain of matrices multiplied by local or device coords.
182         // If the coord is the untransformed local coord we add a varying. We don't if it is
183         // untransformed device coords since it doesn't save us anything over "sk_FragCoord.xy". Of
184         // course, if the FP doesn't directly use its coords then we don't add a varying.
185         if (fp.usesSampleCoordsDirectly() &&
186             (baseCoord == BaseCoord::kLocal ||
187              (baseCoord == BaseCoord::kPosition && lastMatrixFP && canUsePosition))) {
188             // Associate the varying with the highest possible node in the FP tree that shares the
189             // same coordinates so that multiple FPs in a subtree can share. If there are no matrix
190             // sample nodes on the way up the tree then directly use the local coord.
191             if (!lastMatrixFP) {
192                 varyingFSVar = baseLocalCoordFSVar();
193             } else {
194                 // If there is an already a varying that incorporates all matrices from the root to
195                 // lastMatrixFP just use it. Otherwise, we add it.
196                 auto& [varying, inputCoords, varyingIdx] = fTransformVaryingsMap[lastMatrixFP];
197                 if (varying.type() == SkSLType::kVoid) {
198                     varying = GrGLSLVarying(hasPerspective ? SkSLType::kFloat3 : SkSLType::kFloat2);
199                     SkString strVaryingName = SkStringPrintf("TransformedCoords_%d",
200                                                              lastMatrixTraversalIndex);
201                     varyingHandler->addVarying(strVaryingName.c_str(), &varying);
202                     inputCoords = baseCoord == BaseCoord::kLocal ? localCoordsVar : positionVar;
203                     varyingIdx = lastMatrixTraversalIndex;
204                 }
205                 SkASSERT(varyingIdx == lastMatrixTraversalIndex);
206                 // The FP will use the varying in the fragment shader as its coords.
207                 varyingFSVar = varying.fsInVar();
208             }
209             hasCoordsParam = false;
210         }
211 
212         for (int c = 0; c < fp.numChildProcessors(); ++c) {
213             if (auto* child = fp.childProcessor(c)) {
214                 self(self,
215                      *child,
216                      hasPerspective,
217                      lastMatrixFP,
218                      lastMatrixTraversalIndex,
219                      baseCoord);
220                 // If we have a varying then we never need a param. Otherwise, if one of our
221                 // children takes a non-explicit coord then we'll need our coord.
222                 hasCoordsParam |= varyingFSVar.getType() == SkSLType::kVoid &&
223                                   !child->sampleUsage().isExplicit()        &&
224                                   !child->sampleUsage().isFragCoord()       &&
225                                   result[child].hasCoordsParam;
226             }
227         }
228     };
229 
230     bool hasPerspective = SkSLTypeVecLength(localCoordsVar.getType()) == 3;
231     for (int i = 0; i < pipeline.numFragmentProcessors(); ++i) {
232         liftTransforms(liftTransforms, pipeline.getFragmentProcessor(i), hasPerspective);
233     }
234     return result;
235 }
236 
emitTransformCode(GrGLSLVertexBuilder * vb,GrGLSLUniformHandler * uniformHandler)237 void ProgramImpl::emitTransformCode(GrGLSLVertexBuilder* vb, GrGLSLUniformHandler* uniformHandler) {
238     // Because descendant varyings may be computed using the varyings of ancestor FPs we make
239     // sure to visit the varyings according to FP pre-order traversal by dumping them into a
240     // priority queue.
241     using FPAndInfo = std::tuple<const GrFragmentProcessor*, TransformInfo>;
242     auto compare = [](const FPAndInfo& a, const FPAndInfo& b) {
243         return std::get<1>(a).traversalOrder > std::get<1>(b).traversalOrder;
244     };
245     std::priority_queue<FPAndInfo, std::vector<FPAndInfo>, decltype(compare)> pq(compare);
246     std::for_each(fTransformVaryingsMap.begin(), fTransformVaryingsMap.end(), [&pq](auto entry) {
247         pq.push(entry);
248     });
249     for (; !pq.empty(); pq.pop()) {
250         const auto& [fp, info] = pq.top();
251         // If we recorded a transform info, its sample matrix must be uniform
252         SkASSERT(fp->sampleUsage().isUniformMatrix());
253         GrShaderVar uniform = uniformHandler->liftUniformToVertexShader(
254                 *fp->parent(), SkString(SkSL::SampleUsage::MatrixUniformName()));
255         // Start with this matrix and accumulate additional matrices as we walk up the FP tree
256         // to either the base coords or an ancestor FP that has an associated varying.
257         SkString transformExpression = uniform.getName();
258 
259         // If we hit an ancestor with a varying on our walk up then save off the varying as the
260         // input to our accumulated transformExpression. Start off assuming we'll reach the root.
261         GrShaderVar inputCoords = info.inputCoords;
262 
263         for (const auto* base = fp->parent(); base; base = base->parent()) {
264             if (auto iter = fTransformVaryingsMap.find(base); iter != fTransformVaryingsMap.end()) {
265                 // Can stop here, as this varying already holds all transforms from higher FPs
266                 // We'll apply the residual transformExpression we've accumulated up from our
267                 // starting FP to this varying.
268                 inputCoords = iter->second.varying.vsOutVar();
269                 break;
270             } else if (base->sampleUsage().isUniformMatrix()) {
271                 // Accumulate any matrices along the path to either the original local/device coords
272                 // or a parent varying. Getting here means this FP was sampled with a uniform matrix
273                 // but all uses of coords below here in the FP hierarchy are beneath additional
274                 // matrix samples and thus this node wasn't assigned a varying.
275                 GrShaderVar parentUniform = uniformHandler->liftUniformToVertexShader(
276                         *base->parent(), SkString(SkSL::SampleUsage::MatrixUniformName()));
277                 transformExpression.appendf(" * %s", parentUniform.getName().c_str());
278             } else if (base->sampleUsage().isFragCoord()) {
279                 // Our chain of matrices starts here and is based on the device space position.
280                 break;
281             } else {
282                 // This intermediate FP is just a pass through and doesn't need to be built
283                 // in to the expression, but we must visit its parents in case they add transforms.
284                 SkASSERT(base->sampleUsage().isPassThrough() || !base->sampleUsage().isSampled());
285             }
286         }
287 
288         SkString inputStr;
289         if (inputCoords.getType() == SkSLType::kFloat2) {
290             inputStr = SkStringPrintf("%s.xy1", inputCoords.getName().c_str());
291         } else {
292             SkASSERT(inputCoords.getType() == SkSLType::kFloat3);
293             inputStr = inputCoords.getName();
294         }
295 
296         vb->codeAppend("{\n");
297         if (info.varying.type() == SkSLType::kFloat2) {
298             if (vb->getProgramBuilder()->shaderCaps()->fNonsquareMatrixSupport) {
299                 vb->codeAppendf("%s = float3x2(%s) * %s",
300                                 info.varying.vsOut(),
301                                 transformExpression.c_str(),
302                                 inputStr.c_str());
303             } else {
304                 vb->codeAppendf("%s = (%s * %s).xy",
305                                 info.varying.vsOut(),
306                                 transformExpression.c_str(),
307                                 inputStr.c_str());
308             }
309         } else {
310             SkASSERT(info.varying.type() == SkSLType::kFloat3);
311             vb->codeAppendf("%s = %s * %s",
312                             info.varying.vsOut(),
313                             transformExpression.c_str(),
314                             inputStr.c_str());
315         }
316         vb->codeAppend(";\n");
317         vb->codeAppend("}\n");
318     }
319     // We don't need this map anymore.
320     fTransformVaryingsMap.clear();
321 }
322 
setupUniformColor(GrGLSLFPFragmentBuilder * fragBuilder,GrGLSLUniformHandler * uniformHandler,const char * outputName,UniformHandle * colorUniform)323 void ProgramImpl::setupUniformColor(GrGLSLFPFragmentBuilder* fragBuilder,
324                                     GrGLSLUniformHandler* uniformHandler,
325                                     const char* outputName,
326                                     UniformHandle* colorUniform) {
327     SkASSERT(colorUniform);
328     const char* stagedLocalVarName;
329     *colorUniform = uniformHandler->addUniform(nullptr,
330                                                kFragment_GrShaderFlag,
331                                                SkSLType::kHalf4,
332                                                "Color",
333                                                &stagedLocalVarName);
334     fragBuilder->codeAppendf("%s = %s;", outputName, stagedLocalVarName);
335     if (fragBuilder->getProgramBuilder()->shaderCaps()->fMustObfuscateUniformColor) {
336         fragBuilder->codeAppendf("%s = max(%s, half4(0));", outputName, outputName);
337     }
338 }
339 
SetTransform(const GrGLSLProgramDataManager & pdman,const GrShaderCaps & shaderCaps,const UniformHandle & uniform,const SkMatrix & matrix,SkMatrix * state)340 void ProgramImpl::SetTransform(const GrGLSLProgramDataManager& pdman,
341                                const GrShaderCaps& shaderCaps,
342                                const UniformHandle& uniform,
343                                const SkMatrix& matrix,
344                                SkMatrix* state) {
345     if (!uniform.isValid() || (state && SkMatrixPriv::CheapEqual(*state, matrix))) {
346         // No update needed
347         return;
348     }
349     if (state) {
350         *state = matrix;
351     }
352     if (matrix.isScaleTranslate() && !shaderCaps.fReducedShaderMode) {
353         // ComputeMatrixKey and writeX() assume the uniform is a float4 (can't assert since nothing
354         // is exposed on a handle, but should be caught lower down).
355         float values[4] = {matrix.getScaleX(), matrix.getTranslateX(),
356                            matrix.getScaleY(), matrix.getTranslateY()};
357         pdman.set4fv(uniform, 1, values);
358     } else {
359         pdman.setSkMatrix(uniform, matrix);
360     }
361 }
362 
write_passthrough_vertex_position(GrGLSLVertexBuilder * vertBuilder,const GrShaderVar & inPos,GrShaderVar * outPos)363 static void write_passthrough_vertex_position(GrGLSLVertexBuilder* vertBuilder,
364                                               const GrShaderVar& inPos,
365                                               GrShaderVar* outPos) {
366     SkASSERT(inPos.getType() == SkSLType::kFloat3 || inPos.getType() == SkSLType::kFloat2);
367     SkString outName = vertBuilder->newTmpVarName(inPos.getName().c_str());
368     outPos->set(inPos.getType(), outName.c_str());
369     vertBuilder->codeAppendf("float%d %s = %s;",
370                              SkSLTypeVecLength(inPos.getType()),
371                              outName.c_str(),
372                              inPos.getName().c_str());
373 }
374 
write_vertex_position(GrGLSLVertexBuilder * vertBuilder,GrGLSLUniformHandler * uniformHandler,const GrShaderCaps & shaderCaps,const GrShaderVar & inPos,const SkMatrix & matrix,const char * matrixName,GrShaderVar * outPos,ProgramImpl::UniformHandle * matrixUniform)375 static void write_vertex_position(GrGLSLVertexBuilder* vertBuilder,
376                                   GrGLSLUniformHandler* uniformHandler,
377                                   const GrShaderCaps& shaderCaps,
378                                   const GrShaderVar& inPos,
379                                   const SkMatrix& matrix,
380                                   const char* matrixName,
381                                   GrShaderVar* outPos,
382                                   ProgramImpl::UniformHandle* matrixUniform) {
383     SkASSERT(inPos.getType() == SkSLType::kFloat3 || inPos.getType() == SkSLType::kFloat2);
384     SkString outName = vertBuilder->newTmpVarName(inPos.getName().c_str());
385 
386     if (matrix.isIdentity() && !shaderCaps.fReducedShaderMode) {
387         write_passthrough_vertex_position(vertBuilder, inPos, outPos);
388         return;
389     }
390     SkASSERT(matrixUniform);
391 
392     bool useCompactTransform = matrix.isScaleTranslate() && !shaderCaps.fReducedShaderMode;
393     const char* mangledMatrixName;
394     *matrixUniform = uniformHandler->addUniform(nullptr,
395                                                 kVertex_GrShaderFlag,
396                                                 useCompactTransform ? SkSLType::kFloat4
397                                                                     : SkSLType::kFloat3x3,
398                                                 matrixName,
399                                                 &mangledMatrixName);
400 
401     if (inPos.getType() == SkSLType::kFloat3) {
402         // A float3 stays a float3 whether or not the matrix adds perspective
403         if (useCompactTransform) {
404             vertBuilder->codeAppendf("float3 %s = %s.xz1 * %s + %s.yw0;\n",
405                                      outName.c_str(),
406                                      mangledMatrixName,
407                                      inPos.getName().c_str(),
408                                      mangledMatrixName);
409         } else {
410             vertBuilder->codeAppendf("float3 %s = %s * %s;\n",
411                                      outName.c_str(),
412                                      mangledMatrixName,
413                                      inPos.getName().c_str());
414         }
415         outPos->set(SkSLType::kFloat3, outName.c_str());
416         return;
417     }
418     if (matrix.hasPerspective()) {
419         // A float2 is promoted to a float3 if we add perspective via the matrix
420         SkASSERT(!useCompactTransform);
421         vertBuilder->codeAppendf("float3 %s = (%s * %s.xy1);",
422                                  outName.c_str(),
423                                  mangledMatrixName,
424                                  inPos.getName().c_str());
425         outPos->set(SkSLType::kFloat3, outName.c_str());
426         return;
427     }
428     if (useCompactTransform) {
429         vertBuilder->codeAppendf("float2 %s = %s.xz * %s + %s.yw;\n",
430                                  outName.c_str(),
431                                  mangledMatrixName,
432                                  inPos.getName().c_str(),
433                                  mangledMatrixName);
434     } else if (shaderCaps.fNonsquareMatrixSupport) {
435         vertBuilder->codeAppendf("float2 %s = float3x2(%s) * %s.xy1;\n",
436                                  outName.c_str(),
437                                  mangledMatrixName,
438                                  inPos.getName().c_str());
439     } else {
440         vertBuilder->codeAppendf("float2 %s = (%s * %s.xy1).xy;\n",
441                                  outName.c_str(),
442                                  mangledMatrixName,
443                                  inPos.getName().c_str());
444     }
445     outPos->set(SkSLType::kFloat2, outName.c_str());
446 }
447 
WriteOutputPosition(GrGLSLVertexBuilder * vertBuilder,GrGPArgs * gpArgs,const char * posName)448 void ProgramImpl::WriteOutputPosition(GrGLSLVertexBuilder* vertBuilder,
449                                       GrGPArgs* gpArgs,
450                                       const char* posName) {
451     // writeOutputPosition assumes the incoming pos name points to a float2 variable
452     GrShaderVar inPos(posName, SkSLType::kFloat2);
453     write_passthrough_vertex_position(vertBuilder, inPos, &gpArgs->fPositionVar);
454 }
455 
WriteOutputPosition(GrGLSLVertexBuilder * vertBuilder,GrGLSLUniformHandler * uniformHandler,const GrShaderCaps & shaderCaps,GrGPArgs * gpArgs,const char * posName,const SkMatrix & mat,UniformHandle * viewMatrixUniform)456 void ProgramImpl::WriteOutputPosition(GrGLSLVertexBuilder* vertBuilder,
457                                       GrGLSLUniformHandler* uniformHandler,
458                                       const GrShaderCaps& shaderCaps,
459                                       GrGPArgs* gpArgs,
460                                       const char* posName,
461                                       const SkMatrix& mat,
462                                       UniformHandle* viewMatrixUniform) {
463     GrShaderVar inPos(posName, SkSLType::kFloat2);
464     write_vertex_position(vertBuilder,
465                           uniformHandler,
466                           shaderCaps,
467                           inPos,
468                           mat,
469                           "viewMatrix",
470                           &gpArgs->fPositionVar,
471                           viewMatrixUniform);
472 }
473 
WriteLocalCoord(GrGLSLVertexBuilder * vertBuilder,GrGLSLUniformHandler * uniformHandler,const GrShaderCaps & shaderCaps,GrGPArgs * gpArgs,GrShaderVar localVar,const SkMatrix & localMatrix,UniformHandle * localMatrixUniform)474 void ProgramImpl::WriteLocalCoord(GrGLSLVertexBuilder* vertBuilder,
475                                   GrGLSLUniformHandler* uniformHandler,
476                                   const GrShaderCaps& shaderCaps,
477                                   GrGPArgs* gpArgs,
478                                   GrShaderVar localVar,
479                                   const SkMatrix& localMatrix,
480                                   UniformHandle* localMatrixUniform) {
481     write_vertex_position(vertBuilder,
482                           uniformHandler,
483                           shaderCaps,
484                           localVar,
485                           localMatrix,
486                           "localMatrix",
487                           &gpArgs->fLocalCoordVar,
488                           localMatrixUniform);
489 }
490 
491 //////////////////////////////////////////////////////////////////////////////
492 
493 using Attribute    = GrGeometryProcessor::Attribute;
494 using AttributeSet = GrGeometryProcessor::AttributeSet;
495 
operator *() const496 GrGeometryProcessor::Attribute AttributeSet::Iter::operator*() const {
497     if (fCurr->offset().has_value()) {
498         return *fCurr;
499     }
500     return Attribute(fCurr->name(), fCurr->cpuType(), fCurr->gpuType(), fImplicitOffset);
501 }
502 
operator ++()503 void AttributeSet::Iter::operator++() {
504     if (fRemaining) {
505         fRemaining--;
506         fImplicitOffset += Attribute::AlignOffset(fCurr->size());
507         fCurr++;
508         this->skipUninitialized();
509     }
510 }
511 
skipUninitialized()512 void AttributeSet::Iter::skipUninitialized() {
513     if (!fRemaining) {
514         fCurr = nullptr;
515     } else {
516         while (!fCurr->isInitialized()) {
517             ++fCurr;
518         }
519     }
520 }
521 
initImplicit(const Attribute * attrs,int count)522 void AttributeSet::initImplicit(const Attribute* attrs, int count) {
523     fAttributes = attrs;
524     fRawCount   = count;
525     fCount      = 0;
526     fStride     = 0;
527     for (int i = 0; i < count; ++i) {
528         if (attrs[i].isInitialized()) {
529             fCount++;
530             fStride += Attribute::AlignOffset(attrs[i].size());
531         }
532     }
533 }
534 
initExplicit(const Attribute * attrs,int count,size_t stride)535 void AttributeSet::initExplicit(const Attribute* attrs, int count, size_t stride) {
536     fAttributes = attrs;
537     fRawCount   = count;
538     fCount      = count;
539     fStride     = stride;
540     SkASSERT(Attribute::AlignOffset(fStride) == fStride);
541     for (int i = 0; i < count; ++i) {
542         SkASSERT(attrs[i].isInitialized());
543         SkASSERT(attrs[i].offset().has_value());
544         SkASSERT(Attribute::AlignOffset(*attrs[i].offset()) == *attrs[i].offset());
545         SkASSERT(*attrs[i].offset() + attrs[i].size() <= fStride);
546     }
547 }
548 
addToKey(skgpu::KeyBuilder * b) const549 void AttributeSet::addToKey(skgpu::KeyBuilder* b) const {
550     int rawCount = SkAbs32(fRawCount);
551     b->addBits(16, SkToU16(this->stride()), "stride");
552     b->addBits(16, rawCount, "attribute count");
553     size_t implicitOffset = 0;
554     for (int i = 0; i < rawCount; ++i) {
555         const Attribute& attr = fAttributes[i];
556         b->appendComment(attr.isInitialized() ? attr.name() : "unusedAttr");
557         static_assert(kGrVertexAttribTypeCount < (1 << 8), "");
558         static_assert(kSkSLTypeCount           < (1 << 8), "");
559         b->addBits(8,  attr.isInitialized() ? attr.cpuType() : 0xff, "attrType");
560         b->addBits(8 , attr.isInitialized() ? static_cast<int>(attr.gpuType()) : 0xff,
561                    "attrGpuType");
562         int16_t offset = -1;
563         if (attr.isInitialized()) {
564             if (attr.offset().has_value()) {
565                 offset = *attr.offset();
566             } else {
567                 offset = implicitOffset;
568                 implicitOffset += Attribute::AlignOffset(attr.size());
569             }
570         }
571         b->addBits(16, static_cast<uint16_t>(offset), "attrOffset");
572     }
573 }
574 
begin() const575 AttributeSet::Iter AttributeSet::begin() const { return Iter(fAttributes, fCount); }
end() const576 AttributeSet::Iter AttributeSet::end() const { return Iter(); }
577