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/GrGLSLFragmentShaderBuilder.h"
12 #include "glsl/GrGLSLGeometryProcessor.h"
13 #include "glsl/GrGLSLVertexShaderBuilder.h"
14 #include "glsl/GrGLSLVarying.h"
15 #include "glsl/GrGLSLUniformHandler.h"
16 #include "glsl/GrGLSLUtil.h"
17 
18 /*
19  * The default Geometry Processor simply takes position and multiplies it by the uniform view
20  * matrix. It also leaves coverage untouched.  Behind the scenes, we may add per vertex color or
21  * local coords.
22  */
23 
24 enum GPFlag {
25     kColorAttribute_GPFlag          = 0x1,
26     kColorAttributeIsSkColor_GPFlag = 0x2,
27     kLocalCoordAttribute_GPFlag     = 0x4,
28     kCoverageAttribute_GPFlag       = 0x8,
29 };
30 
31 class DefaultGeoProc : public GrGeometryProcessor {
32 public:
Make(uint32_t gpTypeFlags,GrColor color,const SkMatrix & viewMatrix,const SkMatrix & localMatrix,bool localCoordsWillBeRead,uint8_t coverage)33     static sk_sp<GrGeometryProcessor> Make(uint32_t gpTypeFlags,
34                                            GrColor color,
35                                            const SkMatrix& viewMatrix,
36                                            const SkMatrix& localMatrix,
37                                            bool localCoordsWillBeRead,
38                                            uint8_t coverage) {
39         return sk_sp<GrGeometryProcessor>(new DefaultGeoProc(
40                 gpTypeFlags, color, viewMatrix, localMatrix, coverage, localCoordsWillBeRead));
41     }
42 
name() const43     const char* name() const override { return "DefaultGeometryProcessor"; }
44 
inPosition() const45     const Attribute* inPosition() const { return fInPosition; }
inColor() const46     const Attribute* inColor() const { return fInColor; }
inLocalCoords() const47     const Attribute* inLocalCoords() const { return fInLocalCoords; }
inCoverage() const48     const Attribute* inCoverage() const { return fInCoverage; }
color() const49     GrColor color() const { return fColor; }
hasVertexColor() const50     bool hasVertexColor() const { return SkToBool(fInColor); }
viewMatrix() const51     const SkMatrix& viewMatrix() const { return fViewMatrix; }
localMatrix() const52     const SkMatrix& localMatrix() const { return fLocalMatrix; }
localCoordsWillBeRead() const53     bool localCoordsWillBeRead() const { return fLocalCoordsWillBeRead; }
coverage() const54     uint8_t coverage() const { return fCoverage; }
hasVertexCoverage() const55     bool hasVertexCoverage() const { return SkToBool(fInCoverage); }
56 
57     class GLSLProcessor : public GrGLSLGeometryProcessor {
58     public:
GLSLProcessor()59         GLSLProcessor()
60             : fViewMatrix(SkMatrix::InvalidMatrix()), fColor(GrColor_ILLEGAL), fCoverage(0xff) {}
61 
onEmitCode(EmitArgs & args,GrGPArgs * gpArgs)62         void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override {
63             const DefaultGeoProc& gp = args.fGP.cast<DefaultGeoProc>();
64             GrGLSLVertexBuilder* vertBuilder = args.fVertBuilder;
65             GrGLSLPPFragmentBuilder* fragBuilder = args.fFragBuilder;
66             GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler;
67             GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
68 
69             // emit attributes
70             varyingHandler->emitAttributes(gp);
71 
72             // Setup pass through color
73             if (gp.hasVertexColor()) {
74                 GrGLSLVertToFrag varying(kVec4f_GrSLType);
75                 varyingHandler->addVarying("color", &varying);
76                 if (gp.fFlags & kColorAttributeIsSkColor_GPFlag) {
77                     // Do a red/blue swap and premul the color.
78                     vertBuilder->codeAppendf("%s = vec4(%s.a*%s.bgr, %s.a);", varying.vsOut(),
79                                              gp.inColor()->fName, gp.inColor()->fName,
80                                              gp.inColor()->fName);
81                 } else {
82                     vertBuilder->codeAppendf("%s = %s;\n", varying.vsOut(), gp.inColor()->fName);
83                 }
84                 fragBuilder->codeAppendf("%s = %s;", args.fOutputColor, varying.fsIn());
85             } else {
86                 this->setupUniformColor(fragBuilder, uniformHandler, args.fOutputColor,
87                                         &fColorUniform);
88             }
89 
90             // Setup position
91             this->setupPosition(vertBuilder,
92                                 uniformHandler,
93                                 gpArgs,
94                                 gp.inPosition()->fName,
95                                 gp.viewMatrix(),
96                                 &fViewMatrixUniform);
97 
98             if (gp.hasExplicitLocalCoords()) {
99                 // emit transforms with explicit local coords
100                 this->emitTransforms(vertBuilder,
101                                      varyingHandler,
102                                      uniformHandler,
103                                      gpArgs->fPositionVar,
104                                      gp.inLocalCoords()->fName,
105                                      gp.localMatrix(),
106                                      args.fFPCoordTransformHandler);
107             } else {
108                 // emit transforms with position
109                 this->emitTransforms(vertBuilder,
110                                      varyingHandler,
111                                      uniformHandler,
112                                      gpArgs->fPositionVar,
113                                      gp.inPosition()->fName,
114                                      gp.localMatrix(),
115                                      args.fFPCoordTransformHandler);
116             }
117 
118             // Setup coverage as pass through
119             if (gp.hasVertexCoverage()) {
120                 fragBuilder->codeAppendf("float alpha = 1.0;");
121                 varyingHandler->addPassThroughAttribute(gp.inCoverage(), "alpha");
122                 fragBuilder->codeAppendf("%s = vec4(alpha);", args.fOutputCoverage);
123             } else if (gp.coverage() == 0xff) {
124                 fragBuilder->codeAppendf("%s = vec4(1);", args.fOutputCoverage);
125             } else {
126                 const char* fragCoverage;
127                 fCoverageUniform = uniformHandler->addUniform(kFragment_GrShaderFlag,
128                                                               kFloat_GrSLType,
129                                                               kDefault_GrSLPrecision,
130                                                               "Coverage",
131                                                               &fragCoverage);
132                 fragBuilder->codeAppendf("%s = vec4(%s);", args.fOutputCoverage, fragCoverage);
133             }
134         }
135 
GenKey(const GrGeometryProcessor & gp,const GrShaderCaps &,GrProcessorKeyBuilder * b)136         static inline void GenKey(const GrGeometryProcessor& gp,
137                                   const GrShaderCaps&,
138                                   GrProcessorKeyBuilder* b) {
139             const DefaultGeoProc& def = gp.cast<DefaultGeoProc>();
140             uint32_t key = def.fFlags;
141             key |= (def.coverage() == 0xff) ? 0x10 : 0;
142             key |= (def.localCoordsWillBeRead() && def.localMatrix().hasPerspective()) ? 0x20 : 0x0;
143             key |= ComputePosKey(def.viewMatrix()) << 20;
144             b->add32(key);
145         }
146 
setData(const GrGLSLProgramDataManager & pdman,const GrPrimitiveProcessor & gp,FPCoordTransformIter && transformIter)147         void setData(const GrGLSLProgramDataManager& pdman,
148                      const GrPrimitiveProcessor& gp,
149                      FPCoordTransformIter&& transformIter) override {
150             const DefaultGeoProc& dgp = gp.cast<DefaultGeoProc>();
151 
152             if (!dgp.viewMatrix().isIdentity() && !fViewMatrix.cheapEqualTo(dgp.viewMatrix())) {
153                 fViewMatrix = dgp.viewMatrix();
154                 float viewMatrix[3 * 3];
155                 GrGLSLGetMatrix<3>(viewMatrix, fViewMatrix);
156                 pdman.setMatrix3f(fViewMatrixUniform, viewMatrix);
157             }
158 
159             if (dgp.color() != fColor && !dgp.hasVertexColor()) {
160                 float c[4];
161                 GrColorToRGBAFloat(dgp.color(), c);
162                 pdman.set4fv(fColorUniform, 1, c);
163                 fColor = dgp.color();
164             }
165 
166             if (dgp.coverage() != fCoverage && !dgp.hasVertexCoverage()) {
167                 pdman.set1f(fCoverageUniform, GrNormalizeByteToFloat(dgp.coverage()));
168                 fCoverage = dgp.coverage();
169             }
170             this->setTransformDataHelper(dgp.fLocalMatrix, pdman, &transformIter);
171         }
172 
173     private:
174         SkMatrix fViewMatrix;
175         GrColor fColor;
176         uint8_t fCoverage;
177         UniformHandle fViewMatrixUniform;
178         UniformHandle fColorUniform;
179         UniformHandle fCoverageUniform;
180 
181         typedef GrGLSLGeometryProcessor INHERITED;
182     };
183 
getGLSLProcessorKey(const GrShaderCaps & caps,GrProcessorKeyBuilder * b) const184     void getGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override {
185         GLSLProcessor::GenKey(*this, caps, b);
186     }
187 
createGLSLInstance(const GrShaderCaps &) const188     GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps&) const override {
189         return new GLSLProcessor();
190     }
191 
192 private:
DefaultGeoProc(uint32_t gpTypeFlags,GrColor color,const SkMatrix & viewMatrix,const SkMatrix & localMatrix,uint8_t coverage,bool localCoordsWillBeRead)193     DefaultGeoProc(uint32_t gpTypeFlags,
194                    GrColor color,
195                    const SkMatrix& viewMatrix,
196                    const SkMatrix& localMatrix,
197                    uint8_t coverage,
198                    bool localCoordsWillBeRead)
199             : fColor(color)
200             , fViewMatrix(viewMatrix)
201             , fLocalMatrix(localMatrix)
202             , fCoverage(coverage)
203             , fFlags(gpTypeFlags)
204             , fLocalCoordsWillBeRead(localCoordsWillBeRead) {
205         this->initClassID<DefaultGeoProc>();
206         fInPosition = &this->addVertexAttrib("inPosition", kVec2f_GrVertexAttribType,
207                                              kHigh_GrSLPrecision);
208         if (fFlags & kColorAttribute_GPFlag) {
209             fInColor = &this->addVertexAttrib("inColor", kVec4ub_GrVertexAttribType);
210         }
211         if (fFlags & kLocalCoordAttribute_GPFlag) {
212             fInLocalCoords = &this->addVertexAttrib("inLocalCoord", kVec2f_GrVertexAttribType,
213                                                     kHigh_GrSLPrecision);
214             this->setHasExplicitLocalCoords();
215         }
216         if (fFlags & kCoverageAttribute_GPFlag) {
217             fInCoverage = &this->addVertexAttrib("inCoverage", kFloat_GrVertexAttribType);
218         }
219     }
220 
221     const Attribute* fInPosition = nullptr;
222     const Attribute* fInColor = nullptr;
223     const Attribute* fInLocalCoords = nullptr;
224     const Attribute* fInCoverage = nullptr;
225     GrColor fColor;
226     SkMatrix fViewMatrix;
227     SkMatrix fLocalMatrix;
228     uint8_t fCoverage;
229     uint32_t fFlags;
230     bool fLocalCoordsWillBeRead;
231 
232     GR_DECLARE_GEOMETRY_PROCESSOR_TEST;
233 
234     typedef GrGeometryProcessor INHERITED;
235 };
236 
237 GR_DEFINE_GEOMETRY_PROCESSOR_TEST(DefaultGeoProc);
238 
239 #if GR_TEST_UTILS
TestCreate(GrProcessorTestData * d)240 sk_sp<GrGeometryProcessor> DefaultGeoProc::TestCreate(GrProcessorTestData* d) {
241     uint32_t flags = 0;
242     if (d->fRandom->nextBool()) {
243         flags |= kColorAttribute_GPFlag;
244     }
245     if (d->fRandom->nextBool()) {
246         flags |= kColorAttributeIsSkColor_GPFlag;
247     }
248     if (d->fRandom->nextBool()) {
249         flags |= kCoverageAttribute_GPFlag;
250     }
251     if (d->fRandom->nextBool()) {
252         flags |= kLocalCoordAttribute_GPFlag;
253     }
254 
255     return DefaultGeoProc::Make(flags,
256                                 GrRandomColor(d->fRandom),
257                                 GrTest::TestMatrix(d->fRandom),
258                                 GrTest::TestMatrix(d->fRandom),
259 
260                                 d->fRandom->nextBool(),
261                                 GrRandomCoverage(d->fRandom));
262 }
263 #endif
264 
Make(const Color & color,const Coverage & coverage,const LocalCoords & localCoords,const SkMatrix & viewMatrix)265 sk_sp<GrGeometryProcessor> GrDefaultGeoProcFactory::Make(const Color& color,
266                                                          const Coverage& coverage,
267                                                          const LocalCoords& localCoords,
268                                                          const SkMatrix& viewMatrix) {
269     uint32_t flags = 0;
270     if (Color::kPremulGrColorAttribute_Type == color.fType) {
271         flags |= kColorAttribute_GPFlag;
272     } else if (Color::kUnpremulSkColorAttribute_Type == color.fType) {
273         flags |= kColorAttribute_GPFlag | kColorAttributeIsSkColor_GPFlag;
274     }
275     flags |= coverage.fType == Coverage::kAttribute_Type ? kCoverageAttribute_GPFlag : 0;
276     flags |= localCoords.fType == LocalCoords::kHasExplicit_Type ? kLocalCoordAttribute_GPFlag : 0;
277 
278     uint8_t inCoverage = coverage.fCoverage;
279     bool localCoordsWillBeRead = localCoords.fType != LocalCoords::kUnused_Type;
280 
281     GrColor inColor = color.fColor;
282     return DefaultGeoProc::Make(flags,
283                                 inColor,
284                                 viewMatrix,
285                                 localCoords.fMatrix ? *localCoords.fMatrix : SkMatrix::I(),
286                                 localCoordsWillBeRead,
287                                 inCoverage);
288 }
289 
MakeForDeviceSpace(const Color & color,const Coverage & coverage,const LocalCoords & localCoords,const SkMatrix & viewMatrix)290 sk_sp<GrGeometryProcessor> GrDefaultGeoProcFactory::MakeForDeviceSpace(
291                                                                      const Color& color,
292                                                                      const Coverage& coverage,
293                                                                      const LocalCoords& localCoords,
294                                                                      const SkMatrix& viewMatrix) {
295     SkMatrix invert = SkMatrix::I();
296     if (LocalCoords::kUnused_Type != localCoords.fType) {
297         SkASSERT(LocalCoords::kUsePosition_Type == localCoords.fType);
298         if (!viewMatrix.isIdentity() && !viewMatrix.invert(&invert)) {
299             SkDebugf("Could not invert\n");
300             return nullptr;
301         }
302 
303         if (localCoords.hasLocalMatrix()) {
304             invert.preConcat(*localCoords.fMatrix);
305         }
306     }
307 
308     LocalCoords inverted(LocalCoords::kUsePosition_Type, &invert);
309     return Make(color, coverage, inverted, SkMatrix::I());
310 }
311