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