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 "src/gpu/GrDefaultGeoProcFactory.h"
9 
10 #include "include/core/SkRefCnt.h"
11 #include "src/core/SkArenaAlloc.h"
12 #include "src/gpu/GrCaps.h"
13 #include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
14 #include "src/gpu/glsl/GrGLSLGeometryProcessor.h"
15 #include "src/gpu/glsl/GrGLSLUniformHandler.h"
16 #include "src/gpu/glsl/GrGLSLVarying.h"
17 #include "src/gpu/glsl/GrGLSLVertexGeoBuilder.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     kColorAttributeIsWide_GPFlag    = 0x2,
28     kLocalCoordAttribute_GPFlag     = 0x4,
29     kCoverageAttribute_GPFlag       = 0x8,
30     kCoverageAttributeTweak_GPFlag  = 0x10,
31 };
32 
33 class DefaultGeoProc : public GrGeometryProcessor {
34 public:
Make(SkArenaAlloc * arena,uint32_t gpTypeFlags,const SkPMColor4f & color,const SkMatrix & viewMatrix,const SkMatrix & localMatrix,bool localCoordsWillBeRead,uint8_t coverage)35     static GrGeometryProcessor* Make(SkArenaAlloc* arena,
36                                      uint32_t gpTypeFlags,
37                                      const SkPMColor4f& color,
38                                      const SkMatrix& viewMatrix,
39                                      const SkMatrix& localMatrix,
40                                      bool localCoordsWillBeRead,
41                                      uint8_t coverage) {
42         return arena->make<DefaultGeoProc>(gpTypeFlags, color, viewMatrix, localMatrix, coverage,
43                                            localCoordsWillBeRead);
44     }
45 
name() const46     const char* name() const override { return "DefaultGeometryProcessor"; }
47 
color() const48     const SkPMColor4f& color() const { return fColor; }
hasVertexColor() const49     bool hasVertexColor() const { return fInColor.isInitialized(); }
viewMatrix() const50     const SkMatrix& viewMatrix() const { return fViewMatrix; }
localMatrix() const51     const SkMatrix& localMatrix() const { return fLocalMatrix; }
localCoordsWillBeRead() const52     bool localCoordsWillBeRead() const { return fLocalCoordsWillBeRead; }
coverage() const53     uint8_t coverage() const { return fCoverage; }
hasVertexCoverage() const54     bool hasVertexCoverage() const { return fInCoverage.isInitialized(); }
55 
56     class GLSLProcessor : public GrGLSLGeometryProcessor {
57     public:
GLSLProcessor()58         GLSLProcessor()
59             : fViewMatrix(SkMatrix::InvalidMatrix())
60             , fLocalMatrix(SkMatrix::InvalidMatrix())
61             , fColor(SK_PMColor4fILLEGAL)
62             , fCoverage(0xff) {}
63 
onEmitCode(EmitArgs & args,GrGPArgs * gpArgs)64         void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override {
65             const DefaultGeoProc& gp = args.fGP.cast<DefaultGeoProc>();
66             GrGLSLVertexBuilder* vertBuilder = args.fVertBuilder;
67             GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
68             GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler;
69             GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
70 
71             // emit attributes
72             varyingHandler->emitAttributes(gp);
73 
74             bool tweakAlpha = SkToBool(gp.fFlags & kCoverageAttributeTweak_GPFlag);
75             SkASSERT(!tweakAlpha || gp.hasVertexCoverage());
76 
77             // Setup pass through color
78             if (gp.hasVertexColor() || tweakAlpha) {
79                 GrGLSLVarying varying(kHalf4_GrSLType);
80                 varyingHandler->addVarying("color", &varying);
81 
82                 // Start with the attribute or with uniform color
83                 if (gp.hasVertexColor()) {
84                     vertBuilder->codeAppendf("half4 color = %s;", gp.fInColor.name());
85                 } else {
86                     const char* colorUniformName;
87                     fColorUniform = uniformHandler->addUniform(nullptr,
88                                                                kVertex_GrShaderFlag,
89                                                                kHalf4_GrSLType,
90                                                                "Color",
91                                                                &colorUniformName);
92                     vertBuilder->codeAppendf("half4 color = %s;", colorUniformName);
93                 }
94 
95                 // Optionally fold coverage into alpha (color).
96                 if (tweakAlpha) {
97                     vertBuilder->codeAppendf("color = color * %s;", gp.fInCoverage.name());
98                 }
99                 vertBuilder->codeAppendf("%s = color;\n", varying.vsOut());
100                 fragBuilder->codeAppendf("%s = %s;", args.fOutputColor, varying.fsIn());
101             } else {
102                 this->setupUniformColor(fragBuilder, uniformHandler, args.fOutputColor,
103                                         &fColorUniform);
104             }
105 
106             // Setup position
107             this->writeOutputPosition(vertBuilder,
108                                       uniformHandler,
109                                       gpArgs,
110                                       gp.fInPosition.name(),
111                                       gp.viewMatrix(),
112                                       &fViewMatrixUniform);
113 
114             // emit transforms using either explicit local coords or positions
115             if (gp.fInLocalCoords.isInitialized()) {
116                 SkASSERT(gp.localMatrix().isIdentity());
117                 gpArgs->fLocalCoordVar = gp.fInLocalCoords.asShaderVar();
118             } else if (gp.fLocalCoordsWillBeRead) {
119                 this->writeLocalCoord(vertBuilder, uniformHandler, gpArgs,
120                                       gp.fInPosition.asShaderVar(), gp.localMatrix(),
121                                       &fLocalMatrixUniform);
122             }
123 
124             // Setup coverage as pass through
125             if (gp.hasVertexCoverage() && !tweakAlpha) {
126                 fragBuilder->codeAppendf("half alpha = 1.0;");
127                 varyingHandler->addPassThroughAttribute(gp.fInCoverage, "alpha");
128                 fragBuilder->codeAppendf("%s = half4(alpha);", args.fOutputCoverage);
129             } else if (gp.coverage() == 0xff) {
130                 fragBuilder->codeAppendf("%s = half4(1);", args.fOutputCoverage);
131             } else {
132                 const char* fragCoverage;
133                 fCoverageUniform = uniformHandler->addUniform(nullptr,
134                                                               kFragment_GrShaderFlag,
135                                                               kHalf_GrSLType,
136                                                               "Coverage",
137                                                               &fragCoverage);
138                 fragBuilder->codeAppendf("%s = half4(%s);", args.fOutputCoverage, fragCoverage);
139             }
140         }
141 
GenKey(const GrGeometryProcessor & gp,const GrShaderCaps &,GrProcessorKeyBuilder * b)142         static inline void GenKey(const GrGeometryProcessor& gp,
143                                   const GrShaderCaps&,
144                                   GrProcessorKeyBuilder* b) {
145             const DefaultGeoProc& def = gp.cast<DefaultGeoProc>();
146             uint32_t key = def.fFlags;
147             key |= (def.coverage() == 0xff) ? 0x80 : 0;
148             key |= def.localCoordsWillBeRead() ? 0x100 : 0;
149 
150             bool usesLocalMatrix = def.localCoordsWillBeRead() &&
151                                    !def.fInLocalCoords.isInitialized();
152             key = AddMatrixKeys(key, def.viewMatrix(),
153                                 usesLocalMatrix ? def.localMatrix() : SkMatrix::I());
154             b->add32(key);
155         }
156 
setData(const GrGLSLProgramDataManager & pdman,const GrPrimitiveProcessor & gp)157         void setData(const GrGLSLProgramDataManager& pdman,
158                      const GrPrimitiveProcessor& gp) override {
159             const DefaultGeoProc& dgp = gp.cast<DefaultGeoProc>();
160 
161             this->setTransform(pdman, fViewMatrixUniform, dgp.viewMatrix(), &fViewMatrix);
162             this->setTransform(pdman, fLocalMatrixUniform, dgp.localMatrix(), &fLocalMatrix);
163 
164             if (!dgp.hasVertexColor() && dgp.color() != fColor) {
165                 pdman.set4fv(fColorUniform, 1, dgp.color().vec());
166                 fColor = dgp.color();
167             }
168 
169             if (dgp.coverage() != fCoverage && !dgp.hasVertexCoverage()) {
170                 pdman.set1f(fCoverageUniform, GrNormalizeByteToFloat(dgp.coverage()));
171                 fCoverage = dgp.coverage();
172             }
173         }
174 
175     private:
176         SkMatrix fViewMatrix;
177         SkMatrix fLocalMatrix;
178         SkPMColor4f fColor;
179         uint8_t fCoverage;
180         UniformHandle fViewMatrixUniform;
181         UniformHandle fLocalMatrixUniform;
182         UniformHandle fColorUniform;
183         UniformHandle fCoverageUniform;
184 
185         using INHERITED = GrGLSLGeometryProcessor;
186     };
187 
getGLSLProcessorKey(const GrShaderCaps & caps,GrProcessorKeyBuilder * b) const188     void getGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override {
189         GLSLProcessor::GenKey(*this, caps, b);
190     }
191 
createGLSLInstance(const GrShaderCaps &) const192     GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps&) const override {
193         return new GLSLProcessor();
194     }
195 
196 private:
197     friend class ::SkArenaAlloc; // for access to ctor
198 
DefaultGeoProc(uint32_t gpTypeFlags,const SkPMColor4f & color,const SkMatrix & viewMatrix,const SkMatrix & localMatrix,uint8_t coverage,bool localCoordsWillBeRead)199     DefaultGeoProc(uint32_t gpTypeFlags,
200                    const SkPMColor4f& color,
201                    const SkMatrix& viewMatrix,
202                    const SkMatrix& localMatrix,
203                    uint8_t coverage,
204                    bool localCoordsWillBeRead)
205             : INHERITED(kDefaultGeoProc_ClassID)
206             , fColor(color)
207             , fViewMatrix(viewMatrix)
208             , fLocalMatrix(localMatrix)
209             , fCoverage(coverage)
210             , fFlags(gpTypeFlags)
211             , fLocalCoordsWillBeRead(localCoordsWillBeRead) {
212         fInPosition = {"inPosition", kFloat2_GrVertexAttribType, kFloat2_GrSLType};
213         if (fFlags & kColorAttribute_GPFlag) {
214             fInColor = MakeColorAttribute("inColor",
215                                           SkToBool(fFlags & kColorAttributeIsWide_GPFlag));
216         }
217         if (fFlags & kLocalCoordAttribute_GPFlag) {
218             fInLocalCoords = {"inLocalCoord", kFloat2_GrVertexAttribType,
219                                               kFloat2_GrSLType};
220         }
221         if (fFlags & kCoverageAttribute_GPFlag) {
222             fInCoverage = {"inCoverage", kFloat_GrVertexAttribType, kHalf_GrSLType};
223         }
224         this->setVertexAttributes(&fInPosition, 4);
225     }
226 
227     Attribute fInPosition;
228     Attribute fInColor;
229     Attribute fInLocalCoords;
230     Attribute fInCoverage;
231     SkPMColor4f fColor;
232     SkMatrix fViewMatrix;
233     SkMatrix fLocalMatrix;
234     uint8_t fCoverage;
235     uint32_t fFlags;
236     bool fLocalCoordsWillBeRead;
237 
238     GR_DECLARE_GEOMETRY_PROCESSOR_TEST
239 
240     using INHERITED = GrGeometryProcessor;
241 };
242 
243 GR_DEFINE_GEOMETRY_PROCESSOR_TEST(DefaultGeoProc);
244 
245 #if GR_TEST_UTILS
TestCreate(GrProcessorTestData * d)246 GrGeometryProcessor* DefaultGeoProc::TestCreate(GrProcessorTestData* d) {
247     uint32_t flags = 0;
248     if (d->fRandom->nextBool()) {
249         flags |= kColorAttribute_GPFlag;
250     }
251     if (d->fRandom->nextBool()) {
252         flags |= kColorAttributeIsWide_GPFlag;
253     }
254     if (d->fRandom->nextBool()) {
255         flags |= kCoverageAttribute_GPFlag;
256         if (d->fRandom->nextBool()) {
257             flags |= kCoverageAttributeTweak_GPFlag;
258         }
259     }
260     if (d->fRandom->nextBool()) {
261         flags |= kLocalCoordAttribute_GPFlag;
262     }
263 
264     return DefaultGeoProc::Make(d->allocator(),
265                                 flags,
266                                 SkPMColor4f::FromBytes_RGBA(GrRandomColor(d->fRandom)),
267                                 GrTest::TestMatrix(d->fRandom),
268                                 GrTest::TestMatrix(d->fRandom),
269                                 d->fRandom->nextBool(),
270                                 GrRandomCoverage(d->fRandom));
271 }
272 #endif
273 
Make(SkArenaAlloc * arena,const Color & color,const Coverage & coverage,const LocalCoords & localCoords,const SkMatrix & viewMatrix)274 GrGeometryProcessor* GrDefaultGeoProcFactory::Make(SkArenaAlloc* arena,
275                                                    const Color& color,
276                                                    const Coverage& coverage,
277                                                    const LocalCoords& localCoords,
278                                                    const SkMatrix& viewMatrix) {
279     uint32_t flags = 0;
280     if (Color::kPremulGrColorAttribute_Type == color.fType) {
281         flags |= kColorAttribute_GPFlag;
282     } else if (Color::kPremulWideColorAttribute_Type == color.fType) {
283         flags |= kColorAttribute_GPFlag | kColorAttributeIsWide_GPFlag;
284     }
285     if (Coverage::kAttribute_Type == coverage.fType) {
286         flags |= kCoverageAttribute_GPFlag;
287     } else if (Coverage::kAttributeTweakAlpha_Type == coverage.fType) {
288         flags |= kCoverageAttribute_GPFlag | kCoverageAttributeTweak_GPFlag;
289     }
290     flags |= localCoords.fType == LocalCoords::kHasExplicit_Type ? kLocalCoordAttribute_GPFlag : 0;
291 
292     uint8_t inCoverage = coverage.fCoverage;
293     bool localCoordsWillBeRead = localCoords.fType != LocalCoords::kUnused_Type;
294 
295     return DefaultGeoProc::Make(arena,
296                                 flags,
297                                 color.fColor,
298                                 viewMatrix,
299                                 localCoords.fMatrix ? *localCoords.fMatrix : SkMatrix::I(),
300                                 localCoordsWillBeRead,
301                                 inCoverage);
302 }
303 
MakeForDeviceSpace(SkArenaAlloc * arena,const Color & color,const Coverage & coverage,const LocalCoords & localCoords,const SkMatrix & viewMatrix)304 GrGeometryProcessor* GrDefaultGeoProcFactory::MakeForDeviceSpace(SkArenaAlloc* arena,
305                                                                  const Color& color,
306                                                                  const Coverage& coverage,
307                                                                  const LocalCoords& localCoords,
308                                                                  const SkMatrix& viewMatrix) {
309     SkMatrix invert = SkMatrix::I();
310     if (LocalCoords::kUnused_Type != localCoords.fType) {
311         SkASSERT(LocalCoords::kUsePosition_Type == localCoords.fType);
312         if (!viewMatrix.isIdentity() && !viewMatrix.invert(&invert)) {
313             return nullptr;
314         }
315 
316         if (localCoords.hasLocalMatrix()) {
317             invert.postConcat(*localCoords.fMatrix);
318         }
319     }
320 
321     LocalCoords inverted(LocalCoords::kUsePosition_Type, &invert);
322     return Make(arena, color, coverage, inverted, SkMatrix::I());
323 }
324