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