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