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 "GrDefaultGeoProcFactory.h"
9
10 #include "GrCaps.h"
11 #include "SkRefCnt.h"
12 #include "glsl/GrGLSLColorSpaceXformHelper.h"
13 #include "glsl/GrGLSLFragmentShaderBuilder.h"
14 #include "glsl/GrGLSLGeometryProcessor.h"
15 #include "glsl/GrGLSLVertexGeoBuilder.h"
16 #include "glsl/GrGLSLVarying.h"
17 #include "glsl/GrGLSLUniformHandler.h"
18 #include "glsl/GrGLSLUtil.h"
19
20 /*
21 * The default Geometry Processor simply takes position and multiplies it by the uniform view
22 * matrix. It also leaves coverage untouched. Behind the scenes, we may add per vertex color or
23 * local coords.
24 */
25
26 enum GPFlag {
27 kColorAttribute_GPFlag = 0x1,
28 kColorAttributeIsSkColor_GPFlag = 0x2,
29 kColorAttributeIsWide_GPFlag = 0x4,
30 kLocalCoordAttribute_GPFlag = 0x8,
31 kCoverageAttribute_GPFlag = 0x10,
32 kCoverageAttributeTweak_GPFlag = 0x20,
33 kBonesAttribute_GPFlag = 0x40,
34 };
35
36 static constexpr int kNumVec2sPerBone = 3; // Our bone matrices are 3x2 matrices passed in as
37 // vec2s in column major order, and thus there are 3
38 // vec2s per bone.
39
40 class DefaultGeoProc : public GrGeometryProcessor {
41 public:
Make(const GrShaderCaps * shaderCaps,uint32_t gpTypeFlags,const SkPMColor4f & color,sk_sp<GrColorSpaceXform> colorSpaceXform,const SkMatrix & viewMatrix,const SkMatrix & localMatrix,bool localCoordsWillBeRead,uint8_t coverage,const float * bones,int boneCount)42 static sk_sp<GrGeometryProcessor> Make(const GrShaderCaps* shaderCaps,
43 uint32_t gpTypeFlags,
44 const SkPMColor4f& color,
45 sk_sp<GrColorSpaceXform> colorSpaceXform,
46 const SkMatrix& viewMatrix,
47 const SkMatrix& localMatrix,
48 bool localCoordsWillBeRead,
49 uint8_t coverage,
50 const float* bones,
51 int boneCount) {
52 return sk_sp<GrGeometryProcessor>(new DefaultGeoProc(
53 shaderCaps, gpTypeFlags, color, std::move(colorSpaceXform), viewMatrix, localMatrix,
54 coverage, localCoordsWillBeRead, bones, boneCount));
55 }
56
name() const57 const char* name() const override { return "DefaultGeometryProcessor"; }
58
color() const59 const SkPMColor4f& color() const { return fColor; }
hasVertexColor() const60 bool hasVertexColor() const { return fInColor.isInitialized(); }
viewMatrix() const61 const SkMatrix& viewMatrix() const { return fViewMatrix; }
localMatrix() const62 const SkMatrix& localMatrix() const { return fLocalMatrix; }
localCoordsWillBeRead() const63 bool localCoordsWillBeRead() const { return fLocalCoordsWillBeRead; }
coverage() const64 uint8_t coverage() const { return fCoverage; }
hasVertexCoverage() const65 bool hasVertexCoverage() const { return fInCoverage.isInitialized(); }
bones() const66 const float* bones() const { return fBones; }
boneCount() const67 int boneCount() const { return fBoneCount; }
hasBones() const68 bool hasBones() const { return SkToBool(fBones); }
69
70 class GLSLProcessor : public GrGLSLGeometryProcessor {
71 public:
GLSLProcessor()72 GLSLProcessor()
73 : fViewMatrix(SkMatrix::InvalidMatrix())
74 , fColor(SK_PMColor4fILLEGAL)
75 , fCoverage(0xff) {}
76
onEmitCode(EmitArgs & args,GrGPArgs * gpArgs)77 void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override {
78 const DefaultGeoProc& gp = args.fGP.cast<DefaultGeoProc>();
79 GrGLSLVertexBuilder* vertBuilder = args.fVertBuilder;
80 GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
81 GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler;
82 GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
83
84 // emit attributes
85 varyingHandler->emitAttributes(gp);
86
87 bool tweakAlpha = SkToBool(gp.fFlags & kCoverageAttributeTweak_GPFlag);
88 SkASSERT(!tweakAlpha || gp.hasVertexCoverage());
89
90 // Setup pass through color
91 if (gp.hasVertexColor() || tweakAlpha) {
92 GrGLSLVarying varying(kHalf4_GrSLType);
93 varyingHandler->addVarying("color", &varying);
94
95 // There are several optional steps to process the color. Start with the attribute,
96 // or with uniform color (in the case of folding coverage into a uniform color):
97 if (gp.hasVertexColor()) {
98 vertBuilder->codeAppendf("half4 color = %s;", gp.fInColor.name());
99 } else {
100 const char* colorUniformName;
101 fColorUniform = uniformHandler->addUniform(kVertex_GrShaderFlag,
102 kHalf4_GrSLType,
103 "Color",
104 &colorUniformName);
105 vertBuilder->codeAppendf("half4 color = %s;", colorUniformName);
106 }
107
108 // For SkColor, do a red/blue swap, possible color space conversion, and premul
109 if (gp.fFlags & kColorAttributeIsSkColor_GPFlag) {
110 vertBuilder->codeAppend("color = color.bgra;");
111
112 if (gp.fColorSpaceXform) {
113 fColorSpaceHelper.emitCode(uniformHandler, gp.fColorSpaceXform.get(),
114 kVertex_GrShaderFlag);
115 SkString xformedColor;
116 vertBuilder->appendColorGamutXform(&xformedColor, "color",
117 &fColorSpaceHelper);
118 vertBuilder->codeAppendf("color = %s;", xformedColor.c_str());
119 }
120
121 vertBuilder->codeAppend("color = half4(color.rgb * color.a, color.a);");
122 }
123
124 // Optionally fold coverage into alpha (color).
125 if (tweakAlpha) {
126 vertBuilder->codeAppendf("color = color * %s;", gp.fInCoverage.name());
127 }
128 vertBuilder->codeAppendf("%s = color;\n", varying.vsOut());
129 fragBuilder->codeAppendf("%s = %s;", args.fOutputColor, varying.fsIn());
130 } else {
131 this->setupUniformColor(fragBuilder, uniformHandler, args.fOutputColor,
132 &fColorUniform);
133 }
134
135 // Setup bone transforms
136 // NOTE: This code path is currently unused. Benchmarks have found that for all
137 // reasonable cases of skinned vertices, the overhead involved in copying and uploading
138 // bone data makes performing the transformations on the CPU faster than doing so on
139 // the GPU. This is being kept here in case that changes.
140 const char* transformedPositionName = gp.fInPosition.name();
141 if (gp.hasBones()) {
142 // Set up the uniform for the bones.
143 const char* vertBonesUniformName;
144 fBonesUniform = uniformHandler->addUniformArray(kVertex_GrShaderFlag,
145 kFloat2_GrSLType,
146 "Bones",
147 kMaxBones * kNumVec2sPerBone,
148 &vertBonesUniformName);
149
150 // Set up the bone application function.
151 SkString applyBoneFunctionName;
152 this->emitApplyBoneFunction(vertBuilder,
153 vertBonesUniformName,
154 &applyBoneFunctionName);
155
156 // Apply the world transform to the position first.
157 vertBuilder->codeAppendf(
158 "float2 worldPosition = %s(0, %s);"
159 "float2 transformedPosition = float2(0, 0);"
160 "for (int i = 0; i < 4; i++) {",
161 applyBoneFunctionName.c_str(),
162 gp.fInPosition.name());
163
164 // If the GPU supports unsigned integers, then we can read the index. Otherwise,
165 // we have to estimate it given the float representation.
166 if (args.fShaderCaps->unsignedSupport()) {
167 vertBuilder->codeAppendf(
168 " byte index = %s[i];",
169 gp.fInBoneIndices.name());
170 } else {
171 vertBuilder->codeAppendf(
172 " byte index = byte(floor(%s[i] * 255 + 0.5));",
173 gp.fInBoneIndices.name());
174 }
175
176 // Get the weight and apply the transformation.
177 vertBuilder->codeAppendf(
178 " float weight = %s[i];"
179 " transformedPosition += %s(index, worldPosition) * weight;"
180 "}",
181 gp.fInBoneWeights.name(),
182 applyBoneFunctionName.c_str());
183 transformedPositionName = "transformedPosition";
184 }
185
186 // Setup position
187 this->writeOutputPosition(vertBuilder,
188 uniformHandler,
189 gpArgs,
190 transformedPositionName,
191 gp.viewMatrix(),
192 &fViewMatrixUniform);
193
194 if (gp.fInLocalCoords.isInitialized()) {
195 // emit transforms with explicit local coords
196 this->emitTransforms(vertBuilder,
197 varyingHandler,
198 uniformHandler,
199 gp.fInLocalCoords.asShaderVar(),
200 gp.localMatrix(),
201 args.fFPCoordTransformHandler);
202 } else {
203 // emit transforms with position
204 this->emitTransforms(vertBuilder,
205 varyingHandler,
206 uniformHandler,
207 gp.fInPosition.asShaderVar(),
208 gp.localMatrix(),
209 args.fFPCoordTransformHandler);
210 }
211
212 // Setup coverage as pass through
213 if (gp.hasVertexCoverage() && !tweakAlpha) {
214 fragBuilder->codeAppendf("half alpha = 1.0;");
215 varyingHandler->addPassThroughAttribute(gp.fInCoverage, "alpha");
216 fragBuilder->codeAppendf("%s = half4(alpha);", args.fOutputCoverage);
217 } else if (gp.coverage() == 0xff) {
218 fragBuilder->codeAppendf("%s = half4(1);", args.fOutputCoverage);
219 } else {
220 const char* fragCoverage;
221 fCoverageUniform = uniformHandler->addUniform(kFragment_GrShaderFlag,
222 kHalf_GrSLType,
223 "Coverage",
224 &fragCoverage);
225 fragBuilder->codeAppendf("%s = half4(%s);", args.fOutputCoverage, fragCoverage);
226 }
227 }
228
GenKey(const GrGeometryProcessor & gp,const GrShaderCaps &,GrProcessorKeyBuilder * b)229 static inline void GenKey(const GrGeometryProcessor& gp,
230 const GrShaderCaps&,
231 GrProcessorKeyBuilder* b) {
232 const DefaultGeoProc& def = gp.cast<DefaultGeoProc>();
233 uint32_t key = def.fFlags;
234 key |= (def.coverage() == 0xff) ? 0x80 : 0;
235 key |= (def.localCoordsWillBeRead() && def.localMatrix().hasPerspective()) ? 0x100 : 0;
236 key |= ComputePosKey(def.viewMatrix()) << 20;
237 b->add32(key);
238 b->add32(GrColorSpaceXform::XformKey(def.fColorSpaceXform.get()));
239 }
240
setData(const GrGLSLProgramDataManager & pdman,const GrPrimitiveProcessor & gp,FPCoordTransformIter && transformIter)241 void setData(const GrGLSLProgramDataManager& pdman,
242 const GrPrimitiveProcessor& gp,
243 FPCoordTransformIter&& transformIter) override {
244 const DefaultGeoProc& dgp = gp.cast<DefaultGeoProc>();
245
246 if (!dgp.viewMatrix().isIdentity() && !fViewMatrix.cheapEqualTo(dgp.viewMatrix())) {
247 fViewMatrix = dgp.viewMatrix();
248 float viewMatrix[3 * 3];
249 GrGLSLGetMatrix<3>(viewMatrix, fViewMatrix);
250 pdman.setMatrix3f(fViewMatrixUniform, viewMatrix);
251 }
252
253 if (!dgp.hasVertexColor() && dgp.color() != fColor) {
254 pdman.set4fv(fColorUniform, 1, dgp.color().vec());
255 fColor = dgp.color();
256 }
257
258 if (dgp.coverage() != fCoverage && !dgp.hasVertexCoverage()) {
259 pdman.set1f(fCoverageUniform, GrNormalizeByteToFloat(dgp.coverage()));
260 fCoverage = dgp.coverage();
261 }
262 this->setTransformDataHelper(dgp.fLocalMatrix, pdman, &transformIter);
263
264 fColorSpaceHelper.setData(pdman, dgp.fColorSpaceXform.get());
265
266 if (dgp.hasBones()) {
267 pdman.set2fv(fBonesUniform, dgp.boneCount() * kNumVec2sPerBone, dgp.bones());
268 }
269 }
270
271 private:
emitApplyBoneFunction(GrGLSLVertexBuilder * vertBuilder,const char * vertBonesUniformName,SkString * funcName)272 void emitApplyBoneFunction(GrGLSLVertexBuilder* vertBuilder,
273 const char* vertBonesUniformName,
274 SkString* funcName) {
275 // The bone matrices are passed in as 3x2 matrices in column-major order as groups
276 // of 3 float2s. This code takes those float2s and performs the matrix operation on
277 // a given matrix and float2.
278 const GrShaderVar gApplyBoneArgs[] = {
279 GrShaderVar("index", kByte_GrSLType),
280 GrShaderVar("vec", kFloat2_GrSLType),
281 };
282 SkString body;
283 body.appendf(
284 " float2 c0 = %s[index * 3];"
285 " float2 c1 = %s[index * 3 + 1];"
286 " float2 c2 = %s[index * 3 + 2];"
287 " float x = c0.x * vec.x + c1.x * vec.y + c2.x;"
288 " float y = c0.y * vec.x + c1.y * vec.y + c2.y;"
289 " return float2(x, y);",
290 vertBonesUniformName,
291 vertBonesUniformName,
292 vertBonesUniformName);
293 vertBuilder->emitFunction(kFloat2_GrSLType,
294 "applyBone",
295 SK_ARRAY_COUNT(gApplyBoneArgs),
296 gApplyBoneArgs,
297 body.c_str(),
298 funcName);
299 }
300
301 private:
302 SkMatrix fViewMatrix;
303 SkPMColor4f fColor;
304 uint8_t fCoverage;
305 UniformHandle fViewMatrixUniform;
306 UniformHandle fColorUniform;
307 UniformHandle fCoverageUniform;
308 UniformHandle fBonesUniform;
309 GrGLSLColorSpaceXformHelper fColorSpaceHelper;
310
311 typedef GrGLSLGeometryProcessor INHERITED;
312 };
313
getGLSLProcessorKey(const GrShaderCaps & caps,GrProcessorKeyBuilder * b) const314 void getGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override {
315 GLSLProcessor::GenKey(*this, caps, b);
316 }
317
createGLSLInstance(const GrShaderCaps &) const318 GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps&) const override {
319 return new GLSLProcessor();
320 }
321
322 private:
DefaultGeoProc(const GrShaderCaps * shaderCaps,uint32_t gpTypeFlags,const SkPMColor4f & color,sk_sp<GrColorSpaceXform> colorSpaceXform,const SkMatrix & viewMatrix,const SkMatrix & localMatrix,uint8_t coverage,bool localCoordsWillBeRead,const float * bones,int boneCount)323 DefaultGeoProc(const GrShaderCaps* shaderCaps,
324 uint32_t gpTypeFlags,
325 const SkPMColor4f& color,
326 sk_sp<GrColorSpaceXform> colorSpaceXform,
327 const SkMatrix& viewMatrix,
328 const SkMatrix& localMatrix,
329 uint8_t coverage,
330 bool localCoordsWillBeRead,
331 const float* bones,
332 int boneCount)
333 : INHERITED(kDefaultGeoProc_ClassID)
334 , fColor(color)
335 , fViewMatrix(viewMatrix)
336 , fLocalMatrix(localMatrix)
337 , fCoverage(coverage)
338 , fFlags(gpTypeFlags)
339 , fLocalCoordsWillBeRead(localCoordsWillBeRead)
340 , fColorSpaceXform(std::move(colorSpaceXform))
341 , fBones(bones)
342 , fBoneCount(boneCount) {
343 fInPosition = {"inPosition", kFloat2_GrVertexAttribType, kFloat2_GrSLType};
344 if (fFlags & kColorAttribute_GPFlag) {
345 fInColor = MakeColorAttribute("inColor",
346 SkToBool(fFlags & kColorAttributeIsWide_GPFlag));
347 }
348 if (fFlags & kLocalCoordAttribute_GPFlag) {
349 fInLocalCoords = {"inLocalCoord", kFloat2_GrVertexAttribType,
350 kFloat2_GrSLType};
351 }
352 if (fFlags & kCoverageAttribute_GPFlag) {
353 fInCoverage = {"inCoverage", kFloat_GrVertexAttribType, kHalf_GrSLType};
354 }
355 if (fFlags & kBonesAttribute_GPFlag) {
356 SkASSERT(bones && (boneCount > 0));
357 // GLSL 1.10 and 1.20 don't support integer attributes.
358 GrVertexAttribType indicesCPUType = kByte4_GrVertexAttribType;
359 GrSLType indicesGPUType = kByte4_GrSLType;
360 if (!shaderCaps->unsignedSupport()) {
361 indicesCPUType = kUByte4_norm_GrVertexAttribType;
362 indicesGPUType = kHalf4_GrSLType;
363 }
364 fInBoneIndices = {"inBoneIndices", indicesCPUType, indicesGPUType};
365 fInBoneWeights = {"inBoneWeights", kUByte4_norm_GrVertexAttribType,
366 kHalf4_GrSLType};
367 }
368 this->setVertexAttributes(&fInPosition, 6);
369 }
370
371 Attribute fInPosition;
372 Attribute fInColor;
373 Attribute fInLocalCoords;
374 Attribute fInCoverage;
375 Attribute fInBoneIndices;
376 Attribute fInBoneWeights;
377 SkPMColor4f fColor;
378 SkMatrix fViewMatrix;
379 SkMatrix fLocalMatrix;
380 uint8_t fCoverage;
381 uint32_t fFlags;
382 bool fLocalCoordsWillBeRead;
383 sk_sp<GrColorSpaceXform> fColorSpaceXform;
384 const float* fBones;
385 int fBoneCount;
386
387 GR_DECLARE_GEOMETRY_PROCESSOR_TEST
388
389 typedef GrGeometryProcessor INHERITED;
390 };
391
392 GR_DEFINE_GEOMETRY_PROCESSOR_TEST(DefaultGeoProc);
393
394 #if GR_TEST_UTILS
395 static constexpr int kNumFloatsPerBone = 6;
396 static constexpr int kTestBoneCount = 4;
397 static constexpr float kTestBones[kTestBoneCount * kNumFloatsPerBone] = {
398 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
399 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
400 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
401 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
402 };
403
TestCreate(GrProcessorTestData * d)404 sk_sp<GrGeometryProcessor> DefaultGeoProc::TestCreate(GrProcessorTestData* d) {
405 uint32_t flags = 0;
406 if (d->fRandom->nextBool()) {
407 flags |= kColorAttribute_GPFlag;
408 }
409 if (d->fRandom->nextBool()) {
410 flags |= kColorAttributeIsSkColor_GPFlag;
411 }
412 if (d->fRandom->nextBool()) {
413 flags |= kColorAttributeIsWide_GPFlag;
414 }
415 if (d->fRandom->nextBool()) {
416 flags |= kCoverageAttribute_GPFlag;
417 if (d->fRandom->nextBool()) {
418 flags |= kCoverageAttributeTweak_GPFlag;
419 }
420 }
421 if (d->fRandom->nextBool()) {
422 flags |= kLocalCoordAttribute_GPFlag;
423 }
424 if (d->fRandom->nextBool()) {
425 flags |= kBonesAttribute_GPFlag;
426 }
427
428 return DefaultGeoProc::Make(d->caps()->shaderCaps(),
429 flags,
430 SkPMColor4f::FromBytes_RGBA(GrRandomColor(d->fRandom)),
431 GrTest::TestColorXform(d->fRandom),
432 GrTest::TestMatrix(d->fRandom),
433 GrTest::TestMatrix(d->fRandom),
434 d->fRandom->nextBool(),
435 GrRandomCoverage(d->fRandom),
436 kTestBones,
437 kTestBoneCount);
438 }
439 #endif
440
Make(const GrShaderCaps * shaderCaps,const Color & color,const Coverage & coverage,const LocalCoords & localCoords,const SkMatrix & viewMatrix)441 sk_sp<GrGeometryProcessor> GrDefaultGeoProcFactory::Make(const GrShaderCaps* shaderCaps,
442 const Color& color,
443 const Coverage& coverage,
444 const LocalCoords& localCoords,
445 const SkMatrix& viewMatrix) {
446 uint32_t flags = 0;
447 if (Color::kPremulGrColorAttribute_Type == color.fType) {
448 flags |= kColorAttribute_GPFlag;
449 } else if (Color::kUnpremulSkColorAttribute_Type == color.fType) {
450 flags |= kColorAttribute_GPFlag | kColorAttributeIsSkColor_GPFlag;
451 } else if (Color::kPremulWideColorAttribute_Type == color.fType) {
452 flags |= kColorAttribute_GPFlag | kColorAttributeIsWide_GPFlag;
453 }
454 if (Coverage::kAttribute_Type == coverage.fType) {
455 flags |= kCoverageAttribute_GPFlag;
456 } else if (Coverage::kAttributeTweakAlpha_Type == coverage.fType) {
457 flags |= kCoverageAttribute_GPFlag | kCoverageAttributeTweak_GPFlag;
458 }
459 flags |= localCoords.fType == LocalCoords::kHasExplicit_Type ? kLocalCoordAttribute_GPFlag : 0;
460
461 uint8_t inCoverage = coverage.fCoverage;
462 bool localCoordsWillBeRead = localCoords.fType != LocalCoords::kUnused_Type;
463
464 return DefaultGeoProc::Make(shaderCaps,
465 flags,
466 color.fColor,
467 color.fColorSpaceXform,
468 viewMatrix,
469 localCoords.fMatrix ? *localCoords.fMatrix : SkMatrix::I(),
470 localCoordsWillBeRead,
471 inCoverage,
472 nullptr,
473 0);
474 }
475
MakeForDeviceSpace(const GrShaderCaps * shaderCaps,const Color & color,const Coverage & coverage,const LocalCoords & localCoords,const SkMatrix & viewMatrix)476 sk_sp<GrGeometryProcessor> GrDefaultGeoProcFactory::MakeForDeviceSpace(
477 const GrShaderCaps* shaderCaps,
478 const Color& color,
479 const Coverage& coverage,
480 const LocalCoords& localCoords,
481 const SkMatrix& viewMatrix) {
482 SkMatrix invert = SkMatrix::I();
483 if (LocalCoords::kUnused_Type != localCoords.fType) {
484 SkASSERT(LocalCoords::kUsePosition_Type == localCoords.fType);
485 if (!viewMatrix.isIdentity() && !viewMatrix.invert(&invert)) {
486 return nullptr;
487 }
488
489 if (localCoords.hasLocalMatrix()) {
490 invert.postConcat(*localCoords.fMatrix);
491 }
492 }
493
494 LocalCoords inverted(LocalCoords::kUsePosition_Type, &invert);
495 return Make(shaderCaps, color, coverage, inverted, SkMatrix::I());
496 }
497
MakeWithBones(const GrShaderCaps * shaderCaps,const Color & color,const Coverage & coverage,const LocalCoords & localCoords,const Bones & bones,const SkMatrix & viewMatrix)498 sk_sp<GrGeometryProcessor> GrDefaultGeoProcFactory::MakeWithBones(const GrShaderCaps* shaderCaps,
499 const Color& color,
500 const Coverage& coverage,
501 const LocalCoords& localCoords,
502 const Bones& bones,
503 const SkMatrix& viewMatrix) {
504 uint32_t flags = 0;
505 if (Color::kPremulGrColorAttribute_Type == color.fType) {
506 flags |= kColorAttribute_GPFlag;
507 } else if (Color::kUnpremulSkColorAttribute_Type == color.fType) {
508 flags |= kColorAttribute_GPFlag | kColorAttributeIsSkColor_GPFlag;
509 } else if (Color::kPremulWideColorAttribute_Type == color.fType) {
510 flags |= kColorAttribute_GPFlag | kColorAttributeIsWide_GPFlag;
511 }
512 if (Coverage::kAttribute_Type == coverage.fType) {
513 flags |= kCoverageAttribute_GPFlag;
514 } else if (Coverage::kAttributeTweakAlpha_Type == coverage.fType) {
515 flags |= kCoverageAttribute_GPFlag | kCoverageAttributeTweak_GPFlag;
516 }
517 flags |= localCoords.fType == LocalCoords::kHasExplicit_Type ? kLocalCoordAttribute_GPFlag : 0;
518 flags |= kBonesAttribute_GPFlag;
519
520 uint8_t inCoverage = coverage.fCoverage;
521 bool localCoordsWillBeRead = localCoords.fType != LocalCoords::kUnused_Type;
522
523 return DefaultGeoProc::Make(shaderCaps,
524 flags,
525 color.fColor,
526 color.fColorSpaceXform,
527 viewMatrix,
528 localCoords.fMatrix ? *localCoords.fMatrix : SkMatrix::I(),
529 localCoordsWillBeRead,
530 inCoverage,
531 bones.fBones,
532 bones.fBoneCount);
533 }
534