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 };
34 
35 class DefaultGeoProc : public GrGeometryProcessor {
36 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)37     static sk_sp<GrGeometryProcessor> Make(const GrShaderCaps* shaderCaps,
38                                            uint32_t gpTypeFlags,
39                                            const SkPMColor4f& color,
40                                            sk_sp<GrColorSpaceXform> colorSpaceXform,
41                                            const SkMatrix& viewMatrix,
42                                            const SkMatrix& localMatrix,
43                                            bool localCoordsWillBeRead,
44                                            uint8_t coverage) {
45         return sk_sp<GrGeometryProcessor>(new DefaultGeoProc(
46                 shaderCaps, gpTypeFlags, color, std::move(colorSpaceXform), viewMatrix, localMatrix,
47                 coverage, localCoordsWillBeRead));
48     }
49 
name() const50     const char* name() const override { return "DefaultGeometryProcessor"; }
51 
color() const52     const SkPMColor4f& color() const { return fColor; }
hasVertexColor() const53     bool hasVertexColor() const { return fInColor.isInitialized(); }
viewMatrix() const54     const SkMatrix& viewMatrix() const { return fViewMatrix; }
localMatrix() const55     const SkMatrix& localMatrix() const { return fLocalMatrix; }
localCoordsWillBeRead() const56     bool localCoordsWillBeRead() const { return fLocalCoordsWillBeRead; }
coverage() const57     uint8_t coverage() const { return fCoverage; }
hasVertexCoverage() const58     bool hasVertexCoverage() const { return fInCoverage.isInitialized(); }
59 
60     class GLSLProcessor : public GrGLSLGeometryProcessor {
61     public:
GLSLProcessor()62         GLSLProcessor()
63             : fViewMatrix(SkMatrix::InvalidMatrix())
64             , fColor(SK_PMColor4fILLEGAL)
65             , fCoverage(0xff) {}
66 
onEmitCode(EmitArgs & args,GrGPArgs * gpArgs)67         void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override {
68             const DefaultGeoProc& gp = args.fGP.cast<DefaultGeoProc>();
69             GrGLSLVertexBuilder* vertBuilder = args.fVertBuilder;
70             GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
71             GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler;
72             GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
73 
74             // emit attributes
75             varyingHandler->emitAttributes(gp);
76 
77             bool tweakAlpha = SkToBool(gp.fFlags & kCoverageAttributeTweak_GPFlag);
78             SkASSERT(!tweakAlpha || gp.hasVertexCoverage());
79 
80             // Setup pass through color
81             if (gp.hasVertexColor() || tweakAlpha) {
82                 GrGLSLVarying varying(kHalf4_GrSLType);
83                 varyingHandler->addVarying("color", &varying);
84 
85                 // There are several optional steps to process the color. Start with the attribute,
86                 // or with uniform color (in the case of folding coverage into a uniform color):
87                 if (gp.hasVertexColor()) {
88                     vertBuilder->codeAppendf("half4 color = %s;", gp.fInColor.name());
89                 } else {
90                     const char* colorUniformName;
91                     fColorUniform = uniformHandler->addUniform(kVertex_GrShaderFlag,
92                                                                kHalf4_GrSLType,
93                                                                "Color",
94                                                                &colorUniformName);
95                     vertBuilder->codeAppendf("half4 color = %s;", colorUniformName);
96                 }
97 
98                 // For SkColor, do a red/blue swap, possible color space conversion, and premul
99                 if (gp.fFlags & kColorAttributeIsSkColor_GPFlag) {
100                     vertBuilder->codeAppend("color = color.bgra;");
101 
102                     if (gp.fColorSpaceXform) {
103                         fColorSpaceHelper.emitCode(uniformHandler, gp.fColorSpaceXform.get(),
104                                                    kVertex_GrShaderFlag);
105                         SkString xformedColor;
106                         vertBuilder->appendColorGamutXform(&xformedColor, "color",
107                                                            &fColorSpaceHelper);
108                         vertBuilder->codeAppendf("color = %s;", xformedColor.c_str());
109                     }
110 
111                     vertBuilder->codeAppend("color = half4(color.rgb * color.a, color.a);");
112                 }
113 
114                 // Optionally fold coverage into alpha (color).
115                 if (tweakAlpha) {
116                     vertBuilder->codeAppendf("color = color * %s;", gp.fInCoverage.name());
117                 }
118                 vertBuilder->codeAppendf("%s = color;\n", varying.vsOut());
119                 fragBuilder->codeAppendf("%s = %s;", args.fOutputColor, varying.fsIn());
120             } else {
121                 this->setupUniformColor(fragBuilder, uniformHandler, args.fOutputColor,
122                                         &fColorUniform);
123             }
124 
125             // Setup position
126             this->writeOutputPosition(vertBuilder,
127                                       uniformHandler,
128                                       gpArgs,
129                                       gp.fInPosition.name(),
130                                       gp.viewMatrix(),
131                                       &fViewMatrixUniform);
132 
133             if (gp.fInLocalCoords.isInitialized()) {
134                 // emit transforms with explicit local coords
135                 this->emitTransforms(vertBuilder,
136                                      varyingHandler,
137                                      uniformHandler,
138                                      gp.fInLocalCoords.asShaderVar(),
139                                      gp.localMatrix(),
140                                      args.fFPCoordTransformHandler);
141             } else {
142                 // emit transforms with position
143                 this->emitTransforms(vertBuilder,
144                                      varyingHandler,
145                                      uniformHandler,
146                                      gp.fInPosition.asShaderVar(),
147                                      gp.localMatrix(),
148                                      args.fFPCoordTransformHandler);
149             }
150 
151             // Setup coverage as pass through
152             if (gp.hasVertexCoverage() && !tweakAlpha) {
153                 fragBuilder->codeAppendf("half alpha = 1.0;");
154                 varyingHandler->addPassThroughAttribute(gp.fInCoverage, "alpha");
155                 fragBuilder->codeAppendf("%s = half4(alpha);", args.fOutputCoverage);
156             } else if (gp.coverage() == 0xff) {
157                 fragBuilder->codeAppendf("%s = half4(1);", args.fOutputCoverage);
158             } else {
159                 const char* fragCoverage;
160                 fCoverageUniform = uniformHandler->addUniform(kFragment_GrShaderFlag,
161                                                               kHalf_GrSLType,
162                                                               "Coverage",
163                                                               &fragCoverage);
164                 fragBuilder->codeAppendf("%s = half4(%s);", args.fOutputCoverage, fragCoverage);
165             }
166         }
167 
GenKey(const GrGeometryProcessor & gp,const GrShaderCaps &,GrProcessorKeyBuilder * b)168         static inline void GenKey(const GrGeometryProcessor& gp,
169                                   const GrShaderCaps&,
170                                   GrProcessorKeyBuilder* b) {
171             const DefaultGeoProc& def = gp.cast<DefaultGeoProc>();
172             uint32_t key = def.fFlags;
173             key |= (def.coverage() == 0xff) ? 0x80 : 0;
174             key |= (def.localCoordsWillBeRead() && def.localMatrix().hasPerspective()) ? 0x100 : 0;
175             key |= ComputePosKey(def.viewMatrix()) << 20;
176             b->add32(key);
177             b->add32(GrColorSpaceXform::XformKey(def.fColorSpaceXform.get()));
178         }
179 
setData(const GrGLSLProgramDataManager & pdman,const GrPrimitiveProcessor & gp,FPCoordTransformIter && transformIter)180         void setData(const GrGLSLProgramDataManager& pdman,
181                      const GrPrimitiveProcessor& gp,
182                      FPCoordTransformIter&& transformIter) override {
183             const DefaultGeoProc& dgp = gp.cast<DefaultGeoProc>();
184 
185             if (!dgp.viewMatrix().isIdentity() && !fViewMatrix.cheapEqualTo(dgp.viewMatrix())) {
186                 fViewMatrix = dgp.viewMatrix();
187                 float viewMatrix[3 * 3];
188                 GrGLSLGetMatrix<3>(viewMatrix, fViewMatrix);
189                 pdman.setMatrix3f(fViewMatrixUniform, viewMatrix);
190             }
191 
192             if (!dgp.hasVertexColor() && dgp.color() != fColor) {
193                 pdman.set4fv(fColorUniform, 1, dgp.color().vec());
194                 fColor = dgp.color();
195             }
196 
197             if (dgp.coverage() != fCoverage && !dgp.hasVertexCoverage()) {
198                 pdman.set1f(fCoverageUniform, GrNormalizeByteToFloat(dgp.coverage()));
199                 fCoverage = dgp.coverage();
200             }
201             this->setTransformDataHelper(dgp.fLocalMatrix, pdman, &transformIter);
202 
203             fColorSpaceHelper.setData(pdman, dgp.fColorSpaceXform.get());
204         }
205 
206     private:
207         SkMatrix fViewMatrix;
208         SkPMColor4f fColor;
209         uint8_t fCoverage;
210         UniformHandle fViewMatrixUniform;
211         UniformHandle fColorUniform;
212         UniformHandle fCoverageUniform;
213         GrGLSLColorSpaceXformHelper fColorSpaceHelper;
214 
215         typedef GrGLSLGeometryProcessor INHERITED;
216     };
217 
getGLSLProcessorKey(const GrShaderCaps & caps,GrProcessorKeyBuilder * b) const218     void getGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override {
219         GLSLProcessor::GenKey(*this, caps, b);
220     }
221 
createGLSLInstance(const GrShaderCaps &) const222     GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps&) const override {
223         return new GLSLProcessor();
224     }
225 
226 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)227     DefaultGeoProc(const GrShaderCaps* shaderCaps,
228                    uint32_t gpTypeFlags,
229                    const SkPMColor4f& color,
230                    sk_sp<GrColorSpaceXform> colorSpaceXform,
231                    const SkMatrix& viewMatrix,
232                    const SkMatrix& localMatrix,
233                    uint8_t coverage,
234                    bool localCoordsWillBeRead)
235             : INHERITED(kDefaultGeoProc_ClassID)
236             , fColor(color)
237             , fViewMatrix(viewMatrix)
238             , fLocalMatrix(localMatrix)
239             , fCoverage(coverage)
240             , fFlags(gpTypeFlags)
241             , fLocalCoordsWillBeRead(localCoordsWillBeRead)
242             , fColorSpaceXform(std::move(colorSpaceXform)) {
243         fInPosition = {"inPosition", kFloat2_GrVertexAttribType, kFloat2_GrSLType};
244         if (fFlags & kColorAttribute_GPFlag) {
245             fInColor = MakeColorAttribute("inColor",
246                                           SkToBool(fFlags & kColorAttributeIsWide_GPFlag));
247         }
248         if (fFlags & kLocalCoordAttribute_GPFlag) {
249             fInLocalCoords = {"inLocalCoord", kFloat2_GrVertexAttribType,
250                                               kFloat2_GrSLType};
251         }
252         if (fFlags & kCoverageAttribute_GPFlag) {
253             fInCoverage = {"inCoverage", kFloat_GrVertexAttribType, kHalf_GrSLType};
254         }
255         this->setVertexAttributes(&fInPosition, 4);
256     }
257 
258     Attribute fInPosition;
259     Attribute fInColor;
260     Attribute fInLocalCoords;
261     Attribute fInCoverage;
262     SkPMColor4f fColor;
263     SkMatrix fViewMatrix;
264     SkMatrix fLocalMatrix;
265     uint8_t fCoverage;
266     uint32_t fFlags;
267     bool fLocalCoordsWillBeRead;
268     sk_sp<GrColorSpaceXform> fColorSpaceXform;
269 
270     GR_DECLARE_GEOMETRY_PROCESSOR_TEST
271 
272     typedef GrGeometryProcessor INHERITED;
273 };
274 
275 GR_DEFINE_GEOMETRY_PROCESSOR_TEST(DefaultGeoProc);
276 
277 #if GR_TEST_UTILS
TestCreate(GrProcessorTestData * d)278 sk_sp<GrGeometryProcessor> DefaultGeoProc::TestCreate(GrProcessorTestData* d) {
279     uint32_t flags = 0;
280     if (d->fRandom->nextBool()) {
281         flags |= kColorAttribute_GPFlag;
282     }
283     if (d->fRandom->nextBool()) {
284         flags |= kColorAttributeIsSkColor_GPFlag;
285     }
286     if (d->fRandom->nextBool()) {
287         flags |= kColorAttributeIsWide_GPFlag;
288     }
289     if (d->fRandom->nextBool()) {
290         flags |= kCoverageAttribute_GPFlag;
291         if (d->fRandom->nextBool()) {
292             flags |= kCoverageAttributeTweak_GPFlag;
293         }
294     }
295     if (d->fRandom->nextBool()) {
296         flags |= kLocalCoordAttribute_GPFlag;
297     }
298 
299     return DefaultGeoProc::Make(d->caps()->shaderCaps(),
300                                 flags,
301                                 SkPMColor4f::FromBytes_RGBA(GrRandomColor(d->fRandom)),
302                                 GrTest::TestColorXform(d->fRandom),
303                                 GrTest::TestMatrix(d->fRandom),
304                                 GrTest::TestMatrix(d->fRandom),
305                                 d->fRandom->nextBool(),
306                                 GrRandomCoverage(d->fRandom));
307 }
308 #endif
309 
Make(const GrShaderCaps * shaderCaps,const Color & color,const Coverage & coverage,const LocalCoords & localCoords,const SkMatrix & viewMatrix)310 sk_sp<GrGeometryProcessor> GrDefaultGeoProcFactory::Make(const GrShaderCaps* shaderCaps,
311                                                          const Color& color,
312                                                          const Coverage& coverage,
313                                                          const LocalCoords& localCoords,
314                                                          const SkMatrix& viewMatrix) {
315     uint32_t flags = 0;
316     if (Color::kPremulGrColorAttribute_Type == color.fType) {
317         flags |= kColorAttribute_GPFlag;
318     } else if (Color::kUnpremulSkColorAttribute_Type == color.fType) {
319         flags |= kColorAttribute_GPFlag | kColorAttributeIsSkColor_GPFlag;
320     } else if (Color::kPremulWideColorAttribute_Type == color.fType) {
321         flags |= kColorAttribute_GPFlag | kColorAttributeIsWide_GPFlag;
322     }
323     if (Coverage::kAttribute_Type == coverage.fType) {
324         flags |= kCoverageAttribute_GPFlag;
325     } else if (Coverage::kAttributeTweakAlpha_Type == coverage.fType) {
326         flags |= kCoverageAttribute_GPFlag | kCoverageAttributeTweak_GPFlag;
327     }
328     flags |= localCoords.fType == LocalCoords::kHasExplicit_Type ? kLocalCoordAttribute_GPFlag : 0;
329 
330     uint8_t inCoverage = coverage.fCoverage;
331     bool localCoordsWillBeRead = localCoords.fType != LocalCoords::kUnused_Type;
332 
333     return DefaultGeoProc::Make(shaderCaps,
334                                 flags,
335                                 color.fColor,
336                                 color.fColorSpaceXform,
337                                 viewMatrix,
338                                 localCoords.fMatrix ? *localCoords.fMatrix : SkMatrix::I(),
339                                 localCoordsWillBeRead,
340                                 inCoverage);
341 }
342 
MakeForDeviceSpace(const GrShaderCaps * shaderCaps,const Color & color,const Coverage & coverage,const LocalCoords & localCoords,const SkMatrix & viewMatrix)343 sk_sp<GrGeometryProcessor> GrDefaultGeoProcFactory::MakeForDeviceSpace(
344                                                                      const GrShaderCaps* shaderCaps,
345                                                                      const Color& color,
346                                                                      const Coverage& coverage,
347                                                                      const LocalCoords& localCoords,
348                                                                      const SkMatrix& viewMatrix) {
349     SkMatrix invert = SkMatrix::I();
350     if (LocalCoords::kUnused_Type != localCoords.fType) {
351         SkASSERT(LocalCoords::kUsePosition_Type == localCoords.fType);
352         if (!viewMatrix.isIdentity() && !viewMatrix.invert(&invert)) {
353             return nullptr;
354         }
355 
356         if (localCoords.hasLocalMatrix()) {
357             invert.postConcat(*localCoords.fMatrix);
358         }
359     }
360 
361     LocalCoords inverted(LocalCoords::kUsePosition_Type, &invert);
362     return Make(shaderCaps, color, coverage, inverted, SkMatrix::I());
363 }
364