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