• 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 "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/GrGLSLVertexShaderBuilder.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             GrGLSLPPFragmentBuilder* 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                 GrGLSLVertToFrag varying(kVec4f_GrSLType);
86                 varyingHandler->addVarying("color", &varying);
87 
88                 // There are several optional steps to process the color. Start with the attribute:
89                 vertBuilder->codeAppendf("vec4 color = %s;", gp.inColor()->fName);
90 
91                 // Linearize
92                 if (gp.linearizeColor()) {
93                     SkString srgbFuncName;
94                     static const GrShaderVar gSrgbArgs[] = {
95                         GrShaderVar("x", kFloat_GrSLType),
96                     };
97                     vertBuilder->emitFunction(kFloat_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 = vec4(%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 = vec4(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->setupPosition(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                                      gpArgs->fPositionVar,
148                                      gp.inLocalCoords()->fName,
149                                      gp.localMatrix(),
150                                      args.fFPCoordTransformHandler);
151             } else {
152                 // emit transforms with position
153                 this->emitTransforms(vertBuilder,
154                                      varyingHandler,
155                                      uniformHandler,
156                                      gpArgs->fPositionVar,
157                                      gp.inPosition()->fName,
158                                      gp.localMatrix(),
159                                      args.fFPCoordTransformHandler);
160             }
161 
162             // Setup coverage as pass through
163             if (gp.hasVertexCoverage()) {
164                 fragBuilder->codeAppendf("float alpha = 1.0;");
165                 varyingHandler->addPassThroughAttribute(gp.inCoverage(), "alpha");
166                 fragBuilder->codeAppendf("%s = vec4(alpha);", args.fOutputCoverage);
167             } else if (gp.coverage() == 0xff) {
168                 fragBuilder->codeAppendf("%s = vec4(1);", args.fOutputCoverage);
169             } else {
170                 const char* fragCoverage;
171                 fCoverageUniform = uniformHandler->addUniform(kFragment_GrShaderFlag,
172                                                               kFloat_GrSLType,
173                                                               kDefault_GrSLPrecision,
174                                                               "Coverage",
175                                                               &fragCoverage);
176                 fragBuilder->codeAppendf("%s = vec4(%s);", args.fOutputCoverage, fragCoverage);
177             }
178         }
179 
GenKey(const GrGeometryProcessor & gp,const GrShaderCaps &,GrProcessorKeyBuilder * b)180         static inline void GenKey(const GrGeometryProcessor& gp,
181                                   const GrShaderCaps&,
182                                   GrProcessorKeyBuilder* b) {
183             const DefaultGeoProc& def = gp.cast<DefaultGeoProc>();
184             uint32_t key = def.fFlags;
185             key |= (def.coverage() == 0xff) ? 0x10 : 0;
186             key |= (def.localCoordsWillBeRead() && def.localMatrix().hasPerspective()) ? 0x20 : 0x0;
187             key |= ComputePosKey(def.viewMatrix()) << 20;
188             b->add32(key);
189             if (def.linearizeColor()) {
190                 b->add32(GrColorSpaceXform::XformKey(def.fColorSpaceXform.get()));
191             }
192         }
193 
setData(const GrGLSLProgramDataManager & pdman,const GrPrimitiveProcessor & gp,FPCoordTransformIter && transformIter)194         void setData(const GrGLSLProgramDataManager& pdman,
195                      const GrPrimitiveProcessor& gp,
196                      FPCoordTransformIter&& transformIter) override {
197             const DefaultGeoProc& dgp = gp.cast<DefaultGeoProc>();
198 
199             if (!dgp.viewMatrix().isIdentity() && !fViewMatrix.cheapEqualTo(dgp.viewMatrix())) {
200                 fViewMatrix = dgp.viewMatrix();
201                 float viewMatrix[3 * 3];
202                 GrGLSLGetMatrix<3>(viewMatrix, fViewMatrix);
203                 pdman.setMatrix3f(fViewMatrixUniform, viewMatrix);
204             }
205 
206             if (dgp.color() != fColor && !dgp.hasVertexColor()) {
207                 float c[4];
208                 GrColorToRGBAFloat(dgp.color(), c);
209                 pdman.set4fv(fColorUniform, 1, c);
210                 fColor = dgp.color();
211             }
212 
213             if (dgp.coverage() != fCoverage && !dgp.hasVertexCoverage()) {
214                 pdman.set1f(fCoverageUniform, GrNormalizeByteToFloat(dgp.coverage()));
215                 fCoverage = dgp.coverage();
216             }
217             this->setTransformDataHelper(dgp.fLocalMatrix, pdman, &transformIter);
218 
219             if (dgp.linearizeColor() && dgp.fColorSpaceXform) {
220                 fColorSpaceHelper.setData(pdman, dgp.fColorSpaceXform.get());
221             }
222         }
223 
224     private:
225         SkMatrix fViewMatrix;
226         GrColor fColor;
227         uint8_t fCoverage;
228         UniformHandle fViewMatrixUniform;
229         UniformHandle fColorUniform;
230         UniformHandle fCoverageUniform;
231         GrGLSLColorSpaceXformHelper fColorSpaceHelper;
232 
233         typedef GrGLSLGeometryProcessor INHERITED;
234     };
235 
getGLSLProcessorKey(const GrShaderCaps & caps,GrProcessorKeyBuilder * b) const236     void getGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override {
237         GLSLProcessor::GenKey(*this, caps, b);
238     }
239 
createGLSLInstance(const GrShaderCaps &) const240     GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps&) const override {
241         return new GLSLProcessor();
242     }
243 
244 private:
DefaultGeoProc(uint32_t gpTypeFlags,GrColor color,sk_sp<GrColorSpaceXform> colorSpaceXform,const SkMatrix & viewMatrix,const SkMatrix & localMatrix,uint8_t coverage,bool localCoordsWillBeRead)245     DefaultGeoProc(uint32_t gpTypeFlags,
246                    GrColor color,
247                    sk_sp<GrColorSpaceXform> colorSpaceXform,
248                    const SkMatrix& viewMatrix,
249                    const SkMatrix& localMatrix,
250                    uint8_t coverage,
251                    bool localCoordsWillBeRead)
252             : fColor(color)
253             , fViewMatrix(viewMatrix)
254             , fLocalMatrix(localMatrix)
255             , fCoverage(coverage)
256             , fFlags(gpTypeFlags)
257             , fLocalCoordsWillBeRead(localCoordsWillBeRead)
258             , fColorSpaceXform(std::move(colorSpaceXform)) {
259         this->initClassID<DefaultGeoProc>();
260         fInPosition = &this->addVertexAttrib("inPosition", kVec2f_GrVertexAttribType,
261                                              kHigh_GrSLPrecision);
262         if (fFlags & kColorAttribute_GPFlag) {
263             fInColor = &this->addVertexAttrib("inColor", kVec4ub_GrVertexAttribType);
264         }
265         if (fFlags & kLocalCoordAttribute_GPFlag) {
266             fInLocalCoords = &this->addVertexAttrib("inLocalCoord", kVec2f_GrVertexAttribType,
267                                                     kHigh_GrSLPrecision);
268             this->setHasExplicitLocalCoords();
269         }
270         if (fFlags & kCoverageAttribute_GPFlag) {
271             fInCoverage = &this->addVertexAttrib("inCoverage", kFloat_GrVertexAttribType);
272         }
273     }
274 
275     const Attribute* fInPosition = nullptr;
276     const Attribute* fInColor = nullptr;
277     const Attribute* fInLocalCoords = nullptr;
278     const Attribute* fInCoverage = nullptr;
279     GrColor fColor;
280     SkMatrix fViewMatrix;
281     SkMatrix fLocalMatrix;
282     uint8_t fCoverage;
283     uint32_t fFlags;
284     bool fLocalCoordsWillBeRead;
285     sk_sp<GrColorSpaceXform> fColorSpaceXform;
286 
287     GR_DECLARE_GEOMETRY_PROCESSOR_TEST
288 
289     typedef GrGeometryProcessor INHERITED;
290 };
291 
292 GR_DEFINE_GEOMETRY_PROCESSOR_TEST(DefaultGeoProc);
293 
294 #if GR_TEST_UTILS
TestCreate(GrProcessorTestData * d)295 sk_sp<GrGeometryProcessor> DefaultGeoProc::TestCreate(GrProcessorTestData* d) {
296     uint32_t flags = 0;
297     if (d->fRandom->nextBool()) {
298         flags |= kColorAttribute_GPFlag;
299     }
300     if (d->fRandom->nextBool()) {
301         flags |= kColorAttributeIsSkColor_GPFlag;
302     }
303     if (d->fRandom->nextBool()) {
304         flags |= kCoverageAttribute_GPFlag;
305     }
306     if (d->fRandom->nextBool()) {
307         flags |= kLocalCoordAttribute_GPFlag;
308     }
309 
310     return DefaultGeoProc::Make(flags,
311                                 GrRandomColor(d->fRandom),
312                                 GrTest::TestColorXform(d->fRandom),
313                                 GrTest::TestMatrix(d->fRandom),
314                                 GrTest::TestMatrix(d->fRandom),
315                                 d->fRandom->nextBool(),
316                                 GrRandomCoverage(d->fRandom));
317 }
318 #endif
319 
Make(const Color & color,const Coverage & coverage,const LocalCoords & localCoords,const SkMatrix & viewMatrix)320 sk_sp<GrGeometryProcessor> GrDefaultGeoProcFactory::Make(const Color& color,
321                                                          const Coverage& coverage,
322                                                          const LocalCoords& localCoords,
323                                                          const SkMatrix& viewMatrix) {
324     uint32_t flags = 0;
325     if (Color::kPremulGrColorAttribute_Type == color.fType) {
326         flags |= kColorAttribute_GPFlag;
327     } else if (Color::kUnpremulSkColorAttribute_Type == color.fType) {
328         flags |= kColorAttribute_GPFlag | kColorAttributeIsSkColor_GPFlag;
329     }
330     if (color.fLinearize) {
331         // It only makes sense to linearize SkColors (which are always sRGB). GrColor values should
332         // have been linearized and gamut-converted during paint conversion
333         SkASSERT(Color::kUnpremulSkColorAttribute_Type == color.fType);
334         flags |= kLinearizeColorAttribute_GPFlag;
335     }
336     flags |= coverage.fType == Coverage::kAttribute_Type ? kCoverageAttribute_GPFlag : 0;
337     flags |= localCoords.fType == LocalCoords::kHasExplicit_Type ? kLocalCoordAttribute_GPFlag : 0;
338 
339     uint8_t inCoverage = coverage.fCoverage;
340     bool localCoordsWillBeRead = localCoords.fType != LocalCoords::kUnused_Type;
341 
342     GrColor inColor = color.fColor;
343     return DefaultGeoProc::Make(flags,
344                                 inColor,
345                                 color.fColorSpaceXform,
346                                 viewMatrix,
347                                 localCoords.fMatrix ? *localCoords.fMatrix : SkMatrix::I(),
348                                 localCoordsWillBeRead,
349                                 inCoverage);
350 }
351 
MakeForDeviceSpace(const Color & color,const Coverage & coverage,const LocalCoords & localCoords,const SkMatrix & viewMatrix)352 sk_sp<GrGeometryProcessor> GrDefaultGeoProcFactory::MakeForDeviceSpace(
353                                                                      const Color& color,
354                                                                      const Coverage& coverage,
355                                                                      const LocalCoords& localCoords,
356                                                                      const SkMatrix& viewMatrix) {
357     SkMatrix invert = SkMatrix::I();
358     if (LocalCoords::kUnused_Type != localCoords.fType) {
359         SkASSERT(LocalCoords::kUsePosition_Type == localCoords.fType);
360         if (!viewMatrix.isIdentity() && !viewMatrix.invert(&invert)) {
361             return nullptr;
362         }
363 
364         if (localCoords.hasLocalMatrix()) {
365             invert.preConcat(*localCoords.fMatrix);
366         }
367     }
368 
369     LocalCoords inverted(LocalCoords::kUsePosition_Type, &invert);
370     return Make(color, coverage, inverted, SkMatrix::I());
371 }
372