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 "SkRefCnt.h"
11 #include "glsl/GrGLSLColorSpaceXformHelper.h"
12 #include "glsl/GrGLSLFragmentShaderBuilder.h"
13 #include "glsl/GrGLSLGeometryProcessor.h"
14 #include "glsl/GrGLSLVertexGeoBuilder.h"
15 #include "glsl/GrGLSLVarying.h"
16 #include "glsl/GrGLSLUniformHandler.h"
17 #include "glsl/GrGLSLUtil.h"
18 
19 /*
20  * The default Geometry Processor simply takes position and multiplies it by the uniform view
21  * matrix. It also leaves coverage untouched.  Behind the scenes, we may add per vertex color or
22  * local coords.
23  */
24 
25 enum GPFlag {
26     kColorAttribute_GPFlag          = 0x1,
27     kColorAttributeIsSkColor_GPFlag = 0x2,
28     kLocalCoordAttribute_GPFlag     = 0x4,
29     kCoverageAttribute_GPFlag       = 0x8,
30 
31     kLinearizeColorAttribute_GPFlag = 0x10,
32 };
33 
34 class DefaultGeoProc : public GrGeometryProcessor {
35 public:
Make(uint32_t gpTypeFlags,GrColor color,sk_sp<GrColorSpaceXform> colorSpaceXform,const SkMatrix & viewMatrix,const SkMatrix & localMatrix,bool localCoordsWillBeRead,uint8_t coverage)36     static sk_sp<GrGeometryProcessor> Make(uint32_t gpTypeFlags,
37                                            GrColor color,
38                                            sk_sp<GrColorSpaceXform> colorSpaceXform,
39                                            const SkMatrix& viewMatrix,
40                                            const SkMatrix& localMatrix,
41                                            bool localCoordsWillBeRead,
42                                            uint8_t coverage) {
43         return sk_sp<GrGeometryProcessor>(new DefaultGeoProc(
44                 gpTypeFlags, color, std::move(colorSpaceXform), viewMatrix, localMatrix, coverage,
45                 localCoordsWillBeRead));
46     }
47 
name() const48     const char* name() const override { return "DefaultGeometryProcessor"; }
49 
inPosition() const50     const Attribute* inPosition() const { return fInPosition; }
inColor() const51     const Attribute* inColor() const { return fInColor; }
inLocalCoords() const52     const Attribute* inLocalCoords() const { return fInLocalCoords; }
inCoverage() const53     const Attribute* inCoverage() const { return fInCoverage; }
color() const54     GrColor color() const { return fColor; }
hasVertexColor() const55     bool hasVertexColor() const { return SkToBool(fInColor); }
viewMatrix() const56     const SkMatrix& viewMatrix() const { return fViewMatrix; }
localMatrix() const57     const SkMatrix& localMatrix() const { return fLocalMatrix; }
localCoordsWillBeRead() const58     bool localCoordsWillBeRead() const { return fLocalCoordsWillBeRead; }
coverage() const59     uint8_t coverage() const { return fCoverage; }
hasVertexCoverage() const60     bool hasVertexCoverage() const { return SkToBool(fInCoverage); }
linearizeColor() const61     bool linearizeColor() const {
62         // Linearization should only happen with SkColor
63         bool linearize = SkToBool(fFlags & kLinearizeColorAttribute_GPFlag);
64         SkASSERT(!linearize || (fFlags & kColorAttributeIsSkColor_GPFlag));
65         return linearize;
66     }
67 
68     class GLSLProcessor : public GrGLSLGeometryProcessor {
69     public:
GLSLProcessor()70         GLSLProcessor()
71             : fViewMatrix(SkMatrix::InvalidMatrix()), fColor(GrColor_ILLEGAL), fCoverage(0xff) {}
72 
onEmitCode(EmitArgs & args,GrGPArgs * gpArgs)73         void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override {
74             const DefaultGeoProc& gp = args.fGP.cast<DefaultGeoProc>();
75             GrGLSLVertexBuilder* vertBuilder = args.fVertBuilder;
76             GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
77             GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler;
78             GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
79 
80             // emit attributes
81             varyingHandler->emitAttributes(gp);
82 
83             // Setup pass through color
84             if (gp.hasVertexColor()) {
85                 GrGLSLVarying varying(kHalf4_GrSLType);
86                 varyingHandler->addVarying("color", &varying);
87 
88                 // There are several optional steps to process the color. Start with the attribute:
89                 vertBuilder->codeAppendf("half4 color = %s;", gp.inColor()->fName);
90 
91                 // Linearize
92                 if (gp.linearizeColor()) {
93                     SkString srgbFuncName;
94                     static const GrShaderVar gSrgbArgs[] = {
95                         GrShaderVar("x", kHalf_GrSLType),
96                     };
97                     vertBuilder->emitFunction(kHalf_GrSLType,
98                                               "srgb_to_linear",
99                                               SK_ARRAY_COUNT(gSrgbArgs),
100                                               gSrgbArgs,
101                                               "return (x <= 0.04045) ? (x / 12.92) "
102                                               ": pow((x + 0.055) / 1.055, 2.4);",
103                                               &srgbFuncName);
104                     vertBuilder->codeAppendf("color = half4(%s(%s.r), %s(%s.g), %s(%s.b), %s.a);",
105                                              srgbFuncName.c_str(), gp.inColor()->fName,
106                                              srgbFuncName.c_str(), gp.inColor()->fName,
107                                              srgbFuncName.c_str(), gp.inColor()->fName,
108                                              gp.inColor()->fName);
109                 }
110 
111                 // For SkColor, do a red/blue swap and premul
112                 if (gp.fFlags & kColorAttributeIsSkColor_GPFlag) {
113                     vertBuilder->codeAppend("color = half4(color.a * color.bgr, color.a);");
114                 }
115 
116                 // Do color-correction to destination gamut
117                 if (gp.linearizeColor()) {
118                     fColorSpaceHelper.emitCode(uniformHandler, gp.fColorSpaceXform.get(),
119                                                kVertex_GrShaderFlag);
120                     if (fColorSpaceHelper.isValid()) {
121                         SkString xformedColor;
122                         vertBuilder->appendColorGamutXform(&xformedColor, "color",
123                                                            &fColorSpaceHelper);
124                         vertBuilder->codeAppendf("color = %s;", xformedColor.c_str());
125                     }
126                 }
127                 vertBuilder->codeAppendf("%s = color;\n", varying.vsOut());
128                 fragBuilder->codeAppendf("%s = %s;", args.fOutputColor, varying.fsIn());
129             } else {
130                 this->setupUniformColor(fragBuilder, uniformHandler, args.fOutputColor,
131                                         &fColorUniform);
132             }
133 
134             // Setup position
135             this->writeOutputPosition(vertBuilder,
136                                       uniformHandler,
137                                       gpArgs,
138                                       gp.inPosition()->fName,
139                                       gp.viewMatrix(),
140                                       &fViewMatrixUniform);
141 
142             if (gp.hasExplicitLocalCoords()) {
143                 // emit transforms with explicit local coords
144                 this->emitTransforms(vertBuilder,
145                                      varyingHandler,
146                                      uniformHandler,
147                                      gp.inLocalCoords()->asShaderVar(),
148                                      gp.localMatrix(),
149                                      args.fFPCoordTransformHandler);
150             } else {
151                 // emit transforms with position
152                 this->emitTransforms(vertBuilder,
153                                      varyingHandler,
154                                      uniformHandler,
155                                      gp.inPosition()->asShaderVar(),
156                                      gp.localMatrix(),
157                                      args.fFPCoordTransformHandler);
158             }
159 
160             // Setup coverage as pass through
161             if (gp.hasVertexCoverage()) {
162                 fragBuilder->codeAppendf("half alpha = 1.0;");
163                 varyingHandler->addPassThroughAttribute(gp.inCoverage(), "alpha");
164                 fragBuilder->codeAppendf("%s = half4(alpha);", args.fOutputCoverage);
165             } else if (gp.coverage() == 0xff) {
166                 fragBuilder->codeAppendf("%s = half4(1);", args.fOutputCoverage);
167             } else {
168                 const char* fragCoverage;
169                 fCoverageUniform = uniformHandler->addUniform(kFragment_GrShaderFlag,
170                                                               kHalf_GrSLType,
171                                                               "Coverage",
172                                                               &fragCoverage);
173                 fragBuilder->codeAppendf("%s = half4(%s);", args.fOutputCoverage, fragCoverage);
174             }
175         }
176 
GenKey(const GrGeometryProcessor & gp,const GrShaderCaps &,GrProcessorKeyBuilder * b)177         static inline void GenKey(const GrGeometryProcessor& gp,
178                                   const GrShaderCaps&,
179                                   GrProcessorKeyBuilder* b) {
180             const DefaultGeoProc& def = gp.cast<DefaultGeoProc>();
181             uint32_t key = def.fFlags;
182             key |= (def.coverage() == 0xff) ? 0x10 : 0;
183             key |= (def.localCoordsWillBeRead() && def.localMatrix().hasPerspective()) ? 0x20 : 0x0;
184             key |= ComputePosKey(def.viewMatrix()) << 20;
185             b->add32(key);
186             if (def.linearizeColor()) {
187                 b->add32(GrColorSpaceXform::XformKey(def.fColorSpaceXform.get()));
188             }
189         }
190 
setData(const GrGLSLProgramDataManager & pdman,const GrPrimitiveProcessor & gp,FPCoordTransformIter && transformIter)191         void setData(const GrGLSLProgramDataManager& pdman,
192                      const GrPrimitiveProcessor& gp,
193                      FPCoordTransformIter&& transformIter) override {
194             const DefaultGeoProc& dgp = gp.cast<DefaultGeoProc>();
195 
196             if (!dgp.viewMatrix().isIdentity() && !fViewMatrix.cheapEqualTo(dgp.viewMatrix())) {
197                 fViewMatrix = dgp.viewMatrix();
198                 float viewMatrix[3 * 3];
199                 GrGLSLGetMatrix<3>(viewMatrix, fViewMatrix);
200                 pdman.setMatrix3f(fViewMatrixUniform, viewMatrix);
201             }
202 
203             if (dgp.color() != fColor && !dgp.hasVertexColor()) {
204                 float c[4];
205                 GrColorToRGBAFloat(dgp.color(), c);
206                 pdman.set4fv(fColorUniform, 1, c);
207                 fColor = dgp.color();
208             }
209 
210             if (dgp.coverage() != fCoverage && !dgp.hasVertexCoverage()) {
211                 pdman.set1f(fCoverageUniform, GrNormalizeByteToFloat(dgp.coverage()));
212                 fCoverage = dgp.coverage();
213             }
214             this->setTransformDataHelper(dgp.fLocalMatrix, pdman, &transformIter);
215 
216             if (dgp.linearizeColor() && dgp.fColorSpaceXform) {
217                 fColorSpaceHelper.setData(pdman, dgp.fColorSpaceXform.get());
218             }
219         }
220 
221     private:
222         SkMatrix fViewMatrix;
223         GrColor fColor;
224         uint8_t fCoverage;
225         UniformHandle fViewMatrixUniform;
226         UniformHandle fColorUniform;
227         UniformHandle fCoverageUniform;
228         GrGLSLColorSpaceXformHelper fColorSpaceHelper;
229 
230         typedef GrGLSLGeometryProcessor INHERITED;
231     };
232 
getGLSLProcessorKey(const GrShaderCaps & caps,GrProcessorKeyBuilder * b) const233     void getGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override {
234         GLSLProcessor::GenKey(*this, caps, b);
235     }
236 
createGLSLInstance(const GrShaderCaps &) const237     GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps&) const override {
238         return new GLSLProcessor();
239     }
240 
241 private:
DefaultGeoProc(uint32_t gpTypeFlags,GrColor color,sk_sp<GrColorSpaceXform> colorSpaceXform,const SkMatrix & viewMatrix,const SkMatrix & localMatrix,uint8_t coverage,bool localCoordsWillBeRead)242     DefaultGeoProc(uint32_t gpTypeFlags,
243                    GrColor color,
244                    sk_sp<GrColorSpaceXform> colorSpaceXform,
245                    const SkMatrix& viewMatrix,
246                    const SkMatrix& localMatrix,
247                    uint8_t coverage,
248                    bool localCoordsWillBeRead)
249             : INHERITED(kDefaultGeoProc_ClassID)
250             , fColor(color)
251             , fViewMatrix(viewMatrix)
252             , fLocalMatrix(localMatrix)
253             , fCoverage(coverage)
254             , fFlags(gpTypeFlags)
255             , fLocalCoordsWillBeRead(localCoordsWillBeRead)
256             , fColorSpaceXform(std::move(colorSpaceXform)) {
257         fInPosition = &this->addVertexAttrib("inPosition", kFloat2_GrVertexAttribType);
258         if (fFlags & kColorAttribute_GPFlag) {
259             fInColor = &this->addVertexAttrib("inColor", kUByte4_norm_GrVertexAttribType);
260         }
261         if (fFlags & kLocalCoordAttribute_GPFlag) {
262             fInLocalCoords = &this->addVertexAttrib("inLocalCoord", kFloat2_GrVertexAttribType);
263             this->setHasExplicitLocalCoords();
264         }
265         if (fFlags & kCoverageAttribute_GPFlag) {
266             fInCoverage = &this->addVertexAttrib("inCoverage", kHalf_GrVertexAttribType);
267         }
268     }
269 
270     const Attribute* fInPosition = nullptr;
271     const Attribute* fInColor = nullptr;
272     const Attribute* fInLocalCoords = nullptr;
273     const Attribute* fInCoverage = nullptr;
274     GrColor fColor;
275     SkMatrix fViewMatrix;
276     SkMatrix fLocalMatrix;
277     uint8_t fCoverage;
278     uint32_t fFlags;
279     bool fLocalCoordsWillBeRead;
280     sk_sp<GrColorSpaceXform> fColorSpaceXform;
281 
282     GR_DECLARE_GEOMETRY_PROCESSOR_TEST
283 
284     typedef GrGeometryProcessor INHERITED;
285 };
286 
287 GR_DEFINE_GEOMETRY_PROCESSOR_TEST(DefaultGeoProc);
288 
289 #if GR_TEST_UTILS
TestCreate(GrProcessorTestData * d)290 sk_sp<GrGeometryProcessor> DefaultGeoProc::TestCreate(GrProcessorTestData* d) {
291     uint32_t flags = 0;
292     if (d->fRandom->nextBool()) {
293         flags |= kColorAttribute_GPFlag;
294     }
295     if (d->fRandom->nextBool()) {
296         flags |= kColorAttributeIsSkColor_GPFlag;
297     }
298     if (d->fRandom->nextBool()) {
299         flags |= kCoverageAttribute_GPFlag;
300     }
301     if (d->fRandom->nextBool()) {
302         flags |= kLocalCoordAttribute_GPFlag;
303     }
304 
305     return DefaultGeoProc::Make(flags,
306                                 GrRandomColor(d->fRandom),
307                                 GrTest::TestColorXform(d->fRandom),
308                                 GrTest::TestMatrix(d->fRandom),
309                                 GrTest::TestMatrix(d->fRandom),
310                                 d->fRandom->nextBool(),
311                                 GrRandomCoverage(d->fRandom));
312 }
313 #endif
314 
Make(const Color & color,const Coverage & coverage,const LocalCoords & localCoords,const SkMatrix & viewMatrix)315 sk_sp<GrGeometryProcessor> GrDefaultGeoProcFactory::Make(const Color& color,
316                                                          const Coverage& coverage,
317                                                          const LocalCoords& localCoords,
318                                                          const SkMatrix& viewMatrix) {
319     uint32_t flags = 0;
320     if (Color::kPremulGrColorAttribute_Type == color.fType) {
321         flags |= kColorAttribute_GPFlag;
322     } else if (Color::kUnpremulSkColorAttribute_Type == color.fType) {
323         flags |= kColorAttribute_GPFlag | kColorAttributeIsSkColor_GPFlag;
324     }
325     if (color.fLinearize) {
326         // It only makes sense to linearize SkColors (which are always sRGB). GrColor values should
327         // have been linearized and gamut-converted during paint conversion
328         SkASSERT(Color::kUnpremulSkColorAttribute_Type == color.fType);
329         flags |= kLinearizeColorAttribute_GPFlag;
330     }
331     flags |= coverage.fType == Coverage::kAttribute_Type ? kCoverageAttribute_GPFlag : 0;
332     flags |= localCoords.fType == LocalCoords::kHasExplicit_Type ? kLocalCoordAttribute_GPFlag : 0;
333 
334     uint8_t inCoverage = coverage.fCoverage;
335     bool localCoordsWillBeRead = localCoords.fType != LocalCoords::kUnused_Type;
336 
337     GrColor inColor = color.fColor;
338     return DefaultGeoProc::Make(flags,
339                                 inColor,
340                                 color.fColorSpaceXform,
341                                 viewMatrix,
342                                 localCoords.fMatrix ? *localCoords.fMatrix : SkMatrix::I(),
343                                 localCoordsWillBeRead,
344                                 inCoverage);
345 }
346 
MakeForDeviceSpace(const Color & color,const Coverage & coverage,const LocalCoords & localCoords,const SkMatrix & viewMatrix)347 sk_sp<GrGeometryProcessor> GrDefaultGeoProcFactory::MakeForDeviceSpace(
348                                                                      const Color& color,
349                                                                      const Coverage& coverage,
350                                                                      const LocalCoords& localCoords,
351                                                                      const SkMatrix& viewMatrix) {
352     SkMatrix invert = SkMatrix::I();
353     if (LocalCoords::kUnused_Type != localCoords.fType) {
354         SkASSERT(LocalCoords::kUsePosition_Type == localCoords.fType);
355         if (!viewMatrix.isIdentity() && !viewMatrix.invert(&invert)) {
356             return nullptr;
357         }
358 
359         if (localCoords.hasLocalMatrix()) {
360             invert.preConcat(*localCoords.fMatrix);
361         }
362     }
363 
364     LocalCoords inverted(LocalCoords::kUsePosition_Type, &invert);
365     return Make(color, coverage, inverted, SkMatrix::I());
366 }
367