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:
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 
57     const char* name() const override { return "DefaultGeometryProcessor"; }
58 
59     const SkPMColor4f& color() const { return fColor; }
60     bool hasVertexColor() const { return fInColor.isInitialized(); }
61     const SkMatrix& viewMatrix() const { return fViewMatrix; }
62     const SkMatrix& localMatrix() const { return fLocalMatrix; }
63     bool localCoordsWillBeRead() const { return fLocalCoordsWillBeRead; }
64     uint8_t coverage() const { return fCoverage; }
65     bool hasVertexCoverage() const { return fInCoverage.isInitialized(); }
66     const float* bones() const { return fBones; }
67     int boneCount() const { return fBoneCount; }
68     bool hasBones() const { return SkToBool(fBones); }
69 
70     class GLSLProcessor : public GrGLSLGeometryProcessor {
71     public:
72         GLSLProcessor()
73             : fViewMatrix(SkMatrix::InvalidMatrix())
74             , fColor(SK_PMColor4fILLEGAL)
75             , fCoverage(0xff) {}
76 
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 
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 
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:
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 
314     void getGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override {
315         GLSLProcessor::GenKey(*this, caps, b);
316     }
317 
318     GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps&) const override {
319         return new GLSLProcessor();
320     }
321 
322 private:
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 
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 
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 
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 
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