• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/ganesh/GrDefaultGeoProcFactory.h"
9 
10 #include "include/core/SkRefCnt.h"
11 #include "src/base/SkArenaAlloc.h"
12 #include "src/gpu/KeyBuilder.h"
13 #include "src/gpu/ganesh/GrCaps.h"
14 #include "src/gpu/ganesh/GrGeometryProcessor.h"
15 #include "src/gpu/ganesh/GrProcessorUnitTest.h"
16 #include "src/gpu/ganesh/glsl/GrGLSLFragmentShaderBuilder.h"
17 #include "src/gpu/ganesh/glsl/GrGLSLUniformHandler.h"
18 #include "src/gpu/ganesh/glsl/GrGLSLVarying.h"
19 #include "src/gpu/ganesh/glsl/GrGLSLVertexGeoBuilder.h"
20 
21 /*
22  * The default Geometry Processor simply takes position and multiplies it by the uniform view
23  * matrix. It also leaves coverage untouched.  Behind the scenes, we may add per vertex color or
24  * local coords.
25  */
26 
27 enum GPFlag {
28     kColorAttribute_GPFlag              = 0x1,
29     kColorAttributeIsWide_GPFlag        = 0x2,
30     kLocalCoordAttribute_GPFlag         = 0x4,
31     kCoverageAttribute_GPFlag           = 0x8,
32     kCoverageAttributeTweak_GPFlag      = 0x10,
33     kCoverageAttributeUnclamped_GPFlag  = 0x20,
34 };
35 
36 class DefaultGeoProc : public GrGeometryProcessor {
37 public:
Make(SkArenaAlloc * arena,uint32_t gpTypeFlags,const SkPMColor4f & color,const SkMatrix & viewMatrix,const SkMatrix & localMatrix,bool localCoordsWillBeRead,uint8_t coverage)38     static GrGeometryProcessor* Make(SkArenaAlloc* arena,
39                                      uint32_t gpTypeFlags,
40                                      const SkPMColor4f& color,
41                                      const SkMatrix& viewMatrix,
42                                      const SkMatrix& localMatrix,
43                                      bool localCoordsWillBeRead,
44                                      uint8_t coverage) {
45         return arena->make([&](void* ptr) {
46             return new (ptr) DefaultGeoProc(gpTypeFlags, color, viewMatrix, localMatrix, coverage,
47                                             localCoordsWillBeRead);
48         });
49     }
50 
name() const51     const char* name() const override { return "DefaultGeometryProcessor"; }
52 
addToKey(const GrShaderCaps & caps,skgpu::KeyBuilder * b) const53     void addToKey(const GrShaderCaps& caps, skgpu::KeyBuilder* b) const override {
54         uint32_t key = fFlags;
55         key |= fCoverage == 0xff      ?  0x80 : 0;
56         key |= fLocalCoordsWillBeRead ? 0x100 : 0;
57 
58         bool usesLocalMatrix = fLocalCoordsWillBeRead && !fInLocalCoords.isInitialized();
59         key = ProgramImpl::AddMatrixKeys(caps,
60                                          key,
61                                          fViewMatrix,
62                                          usesLocalMatrix ? fLocalMatrix : SkMatrix::I());
63         b->add32(key);
64     }
65 
makeProgramImpl(const GrShaderCaps &) const66     std::unique_ptr<ProgramImpl> makeProgramImpl(const GrShaderCaps&) const override {
67         return std::make_unique<Impl>();
68     }
69 
70 private:
71     class Impl : public ProgramImpl {
72     public:
setData(const GrGLSLProgramDataManager & pdman,const GrShaderCaps & shaderCaps,const GrGeometryProcessor & geomProc)73         void setData(const GrGLSLProgramDataManager& pdman,
74                      const GrShaderCaps& shaderCaps,
75                      const GrGeometryProcessor& geomProc) override {
76             const DefaultGeoProc& dgp = geomProc.cast<DefaultGeoProc>();
77 
78             SetTransform(pdman, shaderCaps, fViewMatrixUniform, dgp.fViewMatrix, &fViewMatrixPrev);
79             SetTransform(pdman,
80                          shaderCaps,
81                          fLocalMatrixUniform,
82                          dgp.fLocalMatrix,
83                          &fLocalMatrixPrev);
84 
85             if (!dgp.hasVertexColor() && dgp.fColor != fColor) {
86                 pdman.set4fv(fColorUniform, 1, dgp.fColor.vec());
87                 fColor = dgp.fColor;
88             }
89 
90             if (dgp.fCoverage != fCoverage && !dgp.hasVertexCoverage()) {
91                 pdman.set1f(fCoverageUniform, GrNormalizeByteToFloat(dgp.fCoverage));
92                 fCoverage = dgp.fCoverage;
93             }
94         }
95 
96     private:
onEmitCode(EmitArgs & args,GrGPArgs * gpArgs)97         void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override {
98             const DefaultGeoProc& gp = args.fGeomProc.cast<DefaultGeoProc>();
99             GrGLSLVertexBuilder* vertBuilder = args.fVertBuilder;
100             GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
101             GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler;
102             GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
103 
104             // emit attributes
105             varyingHandler->emitAttributes(gp);
106 
107             bool tweakAlpha = SkToBool(gp.fFlags & kCoverageAttributeTweak_GPFlag);
108             bool coverageNeedsSaturate = SkToBool(gp.fFlags & kCoverageAttributeUnclamped_GPFlag);
109             SkASSERT(!tweakAlpha || gp.hasVertexCoverage());
110             SkASSERT(!tweakAlpha || !coverageNeedsSaturate);
111 
112             // Setup pass through color
113             fragBuilder->codeAppendf("half4 %s;", args.fOutputColor);
114             if (gp.hasVertexColor() || tweakAlpha) {
115                 GrGLSLVarying varying(SkSLType::kHalf4);
116                 varyingHandler->addVarying("color", &varying);
117 
118                 // Start with the attribute or with uniform color
119                 if (gp.hasVertexColor()) {
120                     vertBuilder->codeAppendf("half4 color = %s;", gp.fInColor.name());
121                 } else {
122                     const char* colorUniformName;
123                     fColorUniform = uniformHandler->addUniform(nullptr,
124                                                                kVertex_GrShaderFlag,
125                                                                SkSLType::kHalf4,
126                                                                "Color",
127                                                                &colorUniformName);
128                     vertBuilder->codeAppendf("half4 color = %s;", colorUniformName);
129                 }
130 
131                 // Optionally fold coverage into alpha (color).
132                 if (tweakAlpha) {
133                     vertBuilder->codeAppendf("color = color * %s;", gp.fInCoverage.name());
134                 }
135                 vertBuilder->codeAppendf("%s = color;\n", varying.vsOut());
136                 fragBuilder->codeAppendf("%s = %s;", args.fOutputColor, varying.fsIn());
137             } else {
138                 this->setupUniformColor(fragBuilder, uniformHandler, args.fOutputColor,
139                                         &fColorUniform);
140             }
141 
142             // Setup position
143             WriteOutputPosition(vertBuilder,
144                                 uniformHandler,
145                                 *args.fShaderCaps,
146                                 gpArgs,
147                                 gp.fInPosition.name(),
148                                 gp.fViewMatrix,
149                                 &fViewMatrixUniform);
150 
151             // emit transforms using either explicit local coords or positions
152             if (gp.fInLocalCoords.isInitialized()) {
153                 SkASSERT(gp.fLocalMatrix.isIdentity());
154                 gpArgs->fLocalCoordVar = gp.fInLocalCoords.asShaderVar();
155             } else if (gp.fLocalCoordsWillBeRead) {
156                 WriteLocalCoord(vertBuilder,
157                                 uniformHandler,
158                                 *args.fShaderCaps,
159                                 gpArgs,
160                                 gp.fInPosition.asShaderVar(),
161                                 gp.fLocalMatrix,
162                                 &fLocalMatrixUniform);
163             }
164 
165             // Setup coverage as pass through
166             if (gp.hasVertexCoverage() && !tweakAlpha) {
167                 fragBuilder->codeAppendf("half alpha = 1.0;");
168                 varyingHandler->addPassThroughAttribute(gp.fInCoverage.asShaderVar(), "alpha");
169                 if (coverageNeedsSaturate) {
170                     fragBuilder->codeAppendf("half4 %s = half4(saturate(alpha));",
171                                              args.fOutputCoverage);
172                 } else {
173                     fragBuilder->codeAppendf("half4 %s = half4(alpha);", args.fOutputCoverage);
174                 }
175             } else if (gp.fCoverage == 0xff) {
176                 fragBuilder->codeAppendf("const half4 %s = half4(1);", args.fOutputCoverage);
177             } else {
178                 const char* fragCoverage;
179                 fCoverageUniform = uniformHandler->addUniform(nullptr,
180                                                               kFragment_GrShaderFlag,
181                                                               SkSLType::kHalf,
182                                                               "Coverage",
183                                                               &fragCoverage);
184                 fragBuilder->codeAppendf("half4 %s = half4(%s);",
185                                          args.fOutputCoverage, fragCoverage);
186             }
187         }
188 
189         SkMatrix    fViewMatrixPrev  = SkMatrix::InvalidMatrix();
190         SkMatrix    fLocalMatrixPrev = SkMatrix::InvalidMatrix();
191         SkPMColor4f fColor           = SK_PMColor4fILLEGAL;
192         uint8_t     fCoverage        = 0xFF;
193 
194         UniformHandle fViewMatrixUniform;
195         UniformHandle fLocalMatrixUniform;
196         UniformHandle fColorUniform;
197         UniformHandle fCoverageUniform;
198     };
199 
hasVertexColor() const200     bool hasVertexColor() const { return fInColor.isInitialized(); }
hasVertexCoverage() const201     bool hasVertexCoverage() const { return fInCoverage.isInitialized(); }
202 
DefaultGeoProc(uint32_t gpTypeFlags,const SkPMColor4f & color,const SkMatrix & viewMatrix,const SkMatrix & localMatrix,uint8_t coverage,bool localCoordsWillBeRead)203     DefaultGeoProc(uint32_t gpTypeFlags,
204                    const SkPMColor4f& color,
205                    const SkMatrix& viewMatrix,
206                    const SkMatrix& localMatrix,
207                    uint8_t coverage,
208                    bool localCoordsWillBeRead)
209             : INHERITED(kDefaultGeoProc_ClassID)
210             , fColor(color)
211             , fViewMatrix(viewMatrix)
212             , fLocalMatrix(localMatrix)
213             , fCoverage(coverage)
214             , fFlags(gpTypeFlags)
215             , fLocalCoordsWillBeRead(localCoordsWillBeRead) {
216         fInPosition = {"inPosition", kFloat2_GrVertexAttribType, SkSLType::kFloat2};
217         if (fFlags & kColorAttribute_GPFlag) {
218             fInColor = MakeColorAttribute("inColor",
219                                           SkToBool(fFlags & kColorAttributeIsWide_GPFlag));
220         }
221         if (fFlags & kLocalCoordAttribute_GPFlag) {
222             fInLocalCoords = {"inLocalCoord", kFloat2_GrVertexAttribType,
223                                               SkSLType::kFloat2};
224         }
225         if (fFlags & kCoverageAttribute_GPFlag) {
226             fInCoverage = {"inCoverage", kFloat_GrVertexAttribType, SkSLType::kHalf};
227         }
228         this->setVertexAttributesWithImplicitOffsets(&fInPosition, 4);
229     }
230 
231     Attribute fInPosition;
232     Attribute fInColor;
233     Attribute fInLocalCoords;
234     Attribute fInCoverage;
235     SkPMColor4f fColor;
236     SkMatrix fViewMatrix;
237     SkMatrix fLocalMatrix;
238     uint8_t fCoverage;
239     uint32_t fFlags;
240     bool fLocalCoordsWillBeRead;
241 
242     GR_DECLARE_GEOMETRY_PROCESSOR_TEST
243 
244     using INHERITED = GrGeometryProcessor;
245 };
246 
GR_DEFINE_GEOMETRY_PROCESSOR_TEST(DefaultGeoProc)247 GR_DEFINE_GEOMETRY_PROCESSOR_TEST(DefaultGeoProc)
248 
249 #if GR_TEST_UTILS
250 GrGeometryProcessor* DefaultGeoProc::TestCreate(GrProcessorTestData* d) {
251     uint32_t flags = 0;
252     if (d->fRandom->nextBool()) {
253         flags |= kColorAttribute_GPFlag;
254     }
255     if (d->fRandom->nextBool()) {
256         flags |= kColorAttributeIsWide_GPFlag;
257     }
258     if (d->fRandom->nextBool()) {
259         flags |= kCoverageAttribute_GPFlag;
260         if (d->fRandom->nextBool()) {
261             flags |= (d->fRandom->nextBool()) ? kCoverageAttributeTweak_GPFlag
262                                               : kCoverageAttributeUnclamped_GPFlag;
263         }
264     }
265     if (d->fRandom->nextBool()) {
266         flags |= kLocalCoordAttribute_GPFlag;
267     }
268 
269     GrColor color = GrTest::RandomColor(d->fRandom);
270     SkMatrix viewMtx = GrTest::TestMatrix(d->fRandom);
271     SkMatrix localMtx = GrTest::TestMatrix(d->fRandom);
272     bool readsLocalCoords = d->fRandom->nextBool();
273     uint8_t coverage = GrTest::RandomCoverage(d->fRandom);
274     return DefaultGeoProc::Make(d->allocator(),
275                                 flags,
276                                 SkPMColor4f::FromBytes_RGBA(color),
277                                 viewMtx,
278                                 localMtx,
279                                 readsLocalCoords,
280                                 coverage);
281 }
282 #endif
283 
Make(SkArenaAlloc * arena,const Color & color,const Coverage & coverage,const LocalCoords & localCoords,const SkMatrix & viewMatrix)284 GrGeometryProcessor* GrDefaultGeoProcFactory::Make(SkArenaAlloc* arena,
285                                                    const Color& color,
286                                                    const Coverage& coverage,
287                                                    const LocalCoords& localCoords,
288                                                    const SkMatrix& viewMatrix) {
289     uint32_t flags = 0;
290     if (Color::kPremulGrColorAttribute_Type == color.fType) {
291         flags |= kColorAttribute_GPFlag;
292     } else if (Color::kPremulWideColorAttribute_Type == color.fType) {
293         flags |= kColorAttribute_GPFlag | kColorAttributeIsWide_GPFlag;
294     }
295     if (Coverage::kAttribute_Type == coverage.fType) {
296         flags |= kCoverageAttribute_GPFlag;
297     } else if (Coverage::kAttributeTweakAlpha_Type == coverage.fType) {
298         flags |= kCoverageAttribute_GPFlag | kCoverageAttributeTweak_GPFlag;
299     } else if (Coverage::kAttributeUnclamped_Type == coverage.fType) {
300         flags |= kCoverageAttribute_GPFlag | kCoverageAttributeUnclamped_GPFlag;
301     }
302     flags |= localCoords.fType == LocalCoords::kHasExplicit_Type ? kLocalCoordAttribute_GPFlag : 0;
303 
304     uint8_t inCoverage = coverage.fCoverage;
305     bool localCoordsWillBeRead = localCoords.fType != LocalCoords::kUnused_Type;
306 
307     return DefaultGeoProc::Make(arena,
308                                 flags,
309                                 color.fColor,
310                                 viewMatrix,
311                                 localCoords.fMatrix ? *localCoords.fMatrix : SkMatrix::I(),
312                                 localCoordsWillBeRead,
313                                 inCoverage);
314 }
315 
MakeForDeviceSpace(SkArenaAlloc * arena,const Color & color,const Coverage & coverage,const LocalCoords & localCoords,const SkMatrix & viewMatrix)316 GrGeometryProcessor* GrDefaultGeoProcFactory::MakeForDeviceSpace(SkArenaAlloc* arena,
317                                                                  const Color& color,
318                                                                  const Coverage& coverage,
319                                                                  const LocalCoords& localCoords,
320                                                                  const SkMatrix& viewMatrix) {
321     SkMatrix invert = SkMatrix::I();
322     if (LocalCoords::kUnused_Type != localCoords.fType) {
323         SkASSERT(LocalCoords::kUsePosition_Type == localCoords.fType);
324         if (!viewMatrix.isIdentity() && !viewMatrix.invert(&invert)) {
325             return nullptr;
326         }
327 
328         if (localCoords.hasLocalMatrix()) {
329             invert.postConcat(*localCoords.fMatrix);
330         }
331     }
332 
333     LocalCoords inverted(LocalCoords::kUsePosition_Type, &invert);
334     return Make(arena, color, coverage, inverted, SkMatrix::I());
335 }
336