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