1 /*
2 * Copyright 2013 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/effects/GrBezierEffect.h"
9
10 #include "src/gpu/GrShaderCaps.h"
11 #include "src/gpu/KeyBuilder.h"
12 #include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
13 #include "src/gpu/glsl/GrGLSLProgramDataManager.h"
14 #include "src/gpu/glsl/GrGLSLUniformHandler.h"
15 #include "src/gpu/glsl/GrGLSLVarying.h"
16 #include "src/gpu/glsl/GrGLSLVertexGeoBuilder.h"
17
18 class GrConicEffect::Impl : public ProgramImpl {
19 public:
setData(const GrGLSLProgramDataManager & pdman,const GrShaderCaps & shaderCaps,const GrGeometryProcessor & geomProc)20 void setData(const GrGLSLProgramDataManager& pdman,
21 const GrShaderCaps& shaderCaps,
22 const GrGeometryProcessor& geomProc) override {
23 const GrConicEffect& ce = geomProc.cast<GrConicEffect>();
24
25 SetTransform(pdman, shaderCaps, fViewMatrixUniform, ce.fViewMatrix, &fViewMatrix);
26 SetTransform(pdman, shaderCaps, fLocalMatrixUniform, ce.fLocalMatrix, &fLocalMatrix);
27
28 if (fColor != ce.fColor) {
29 pdman.set4fv(fColorUniform, 1, ce.fColor.vec());
30 fColor = ce.fColor;
31 }
32
33 if (ce.fCoverageScale != 0xff && ce.fCoverageScale != fCoverageScale) {
34 pdman.set1f(fCoverageScaleUniform, GrNormalizeByteToFloat(ce.fCoverageScale));
35 fCoverageScale = ce.fCoverageScale;
36 }
37 }
38
39 private:
40 void onEmitCode(EmitArgs&, GrGPArgs*) override;
41
42 SkMatrix fViewMatrix = SkMatrix::InvalidMatrix();
43 SkMatrix fLocalMatrix = SkMatrix::InvalidMatrix();
44 SkPMColor4f fColor = SK_PMColor4fILLEGAL;
45 uint8_t fCoverageScale = 0xFF;
46
47 UniformHandle fColorUniform;
48 UniformHandle fCoverageScaleUniform;
49 UniformHandle fViewMatrixUniform;
50 UniformHandle fLocalMatrixUniform;
51 };
52
onEmitCode(EmitArgs & args,GrGPArgs * gpArgs)53 void GrConicEffect::Impl::onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) {
54 GrGLSLVertexBuilder* vertBuilder = args.fVertBuilder;
55 const GrConicEffect& gp = args.fGeomProc.cast<GrConicEffect>();
56 GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler;
57 GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
58
59 // emit attributes
60 varyingHandler->emitAttributes(gp);
61
62 GrGLSLVarying v(SkSLType::kFloat4);
63 varyingHandler->addVarying("ConicCoeffs", &v);
64 vertBuilder->codeAppendf("%s = %s;", v.vsOut(), gp.inConicCoeffs().name());
65
66 GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
67 // Setup pass through color
68 fragBuilder->codeAppendf("half4 %s;", args.fOutputColor);
69 this->setupUniformColor(fragBuilder, uniformHandler, args.fOutputColor, &fColorUniform);
70
71 // Setup position
72 WriteOutputPosition(vertBuilder,
73 uniformHandler,
74 *args.fShaderCaps,
75 gpArgs,
76 gp.inPosition().name(),
77 gp.fViewMatrix,
78 &fViewMatrixUniform);
79 if (gp.fUsesLocalCoords) {
80 WriteLocalCoord(vertBuilder,
81 uniformHandler,
82 *args.fShaderCaps,
83 gpArgs,
84 gp.inPosition().asShaderVar(),
85 gp.fLocalMatrix,
86 &fLocalMatrixUniform);
87 }
88
89 // TODO: we should check on the number of bits float and half provide and use the smallest one
90 // that suffices. Additionally we should assert that the upstream code only lets us get here if
91 // either float or half provides the required number of bits.
92
93 GrShaderVar edgeAlpha("edgeAlpha", SkSLType::kHalf, 0);
94 GrShaderVar dklmdx("dklmdx", SkSLType::kFloat3, 0);
95 GrShaderVar dklmdy("dklmdy", SkSLType::kFloat3, 0);
96 GrShaderVar dfdx("dfdx", SkSLType::kFloat, 0);
97 GrShaderVar dfdy("dfdy", SkSLType::kFloat, 0);
98 GrShaderVar gF("gF", SkSLType::kFloat2, 0);
99 GrShaderVar gFM("gFM", SkSLType::kFloat, 0);
100 GrShaderVar func("func", SkSLType::kFloat, 0);
101
102 fragBuilder->declAppend(edgeAlpha);
103 fragBuilder->declAppend(dklmdx);
104 fragBuilder->declAppend(dklmdy);
105 fragBuilder->declAppend(dfdx);
106 fragBuilder->declAppend(dfdy);
107 fragBuilder->declAppend(gF);
108 fragBuilder->declAppend(gFM);
109 fragBuilder->declAppend(func);
110
111 fragBuilder->codeAppendf("%s = dFdx(%s.xyz);", dklmdx.c_str(), v.fsIn());
112 fragBuilder->codeAppendf("%s = dFdy(%s.xyz);", dklmdy.c_str(), v.fsIn());
113 fragBuilder->codeAppendf("%s = 2.0 * %s.x * %s.x - %s.y * %s.z - %s.z * %s.y;",
114 dfdx.c_str(),
115 v.fsIn(), dklmdx.c_str(),
116 v.fsIn(), dklmdx.c_str(),
117 v.fsIn(), dklmdx.c_str());
118 fragBuilder->codeAppendf("%s = 2.0 * %s.x * %s.x - %s.y * %s.z - %s.z * %s.y;",
119 dfdy.c_str(),
120 v.fsIn(), dklmdy.c_str(),
121 v.fsIn(), dklmdy.c_str(),
122 v.fsIn(), dklmdy.c_str());
123 fragBuilder->codeAppendf("%s = float2(%s, %s);", gF.c_str(), dfdx.c_str(),
124 dfdy.c_str());
125 fragBuilder->codeAppendf("%s = sqrt(dot(%s, %s));",
126 gFM.c_str(), gF.c_str(), gF.c_str());
127 fragBuilder->codeAppendf("%s = %s.x*%s.x - %s.y*%s.z;",
128 func.c_str(), v.fsIn(), v.fsIn(), v.fsIn(), v.fsIn());
129 fragBuilder->codeAppendf("%s = abs(%s);", func.c_str(), func.c_str());
130 fragBuilder->codeAppendf("%s = half(%s / %s);",
131 edgeAlpha.c_str(), func.c_str(), gFM.c_str());
132 fragBuilder->codeAppendf("%s = max(1.0 - %s, 0.0);",
133 edgeAlpha.c_str(), edgeAlpha.c_str());
134 // Add line below for smooth cubic ramp
135 // fragBuilder->codeAppend("edgeAlpha = edgeAlpha*edgeAlpha*(3.0-2.0*edgeAlpha);");
136
137 // TODO should we really be doing this?
138 if (gp.fCoverageScale != 0xff) {
139 const char* coverageScale;
140 fCoverageScaleUniform = uniformHandler->addUniform(nullptr,
141 kFragment_GrShaderFlag,
142 SkSLType::kFloat,
143 "Coverage",
144 &coverageScale);
145 fragBuilder->codeAppendf("half4 %s = half4(half(%s) * %s);",
146 args.fOutputCoverage, coverageScale, edgeAlpha.c_str());
147 } else {
148 fragBuilder->codeAppendf("half4 %s = half4(%s);", args.fOutputCoverage, edgeAlpha.c_str());
149 }
150 }
151
152 //////////////////////////////////////////////////////////////////////////////
153
154 GrConicEffect::~GrConicEffect() = default;
155
addToKey(const GrShaderCaps & caps,skgpu::KeyBuilder * b) const156 void GrConicEffect::addToKey(const GrShaderCaps& caps, skgpu::KeyBuilder* b) const {
157 uint32_t key = 0;
158 key |= fCoverageScale == 0xff ? 0x8 : 0x0;
159 key |= fUsesLocalCoords ? 0x10 : 0x0;
160 key = ProgramImpl::AddMatrixKeys(caps,
161 key,
162 fViewMatrix,
163 fUsesLocalCoords ? fLocalMatrix : SkMatrix::I());
164 b->add32(key);
165 }
166
makeProgramImpl(const GrShaderCaps &) const167 std::unique_ptr<GrGeometryProcessor::ProgramImpl> GrConicEffect::makeProgramImpl(
168 const GrShaderCaps&) const {
169 return std::make_unique<Impl>();
170 }
171
GrConicEffect(const SkPMColor4f & color,const SkMatrix & viewMatrix,uint8_t coverage,const SkMatrix & localMatrix,bool usesLocalCoords)172 GrConicEffect::GrConicEffect(const SkPMColor4f& color, const SkMatrix& viewMatrix, uint8_t coverage,
173 const SkMatrix& localMatrix, bool usesLocalCoords)
174 : INHERITED(kGrConicEffect_ClassID)
175 , fColor(color)
176 , fViewMatrix(viewMatrix)
177 , fLocalMatrix(viewMatrix)
178 , fUsesLocalCoords(usesLocalCoords)
179 , fCoverageScale(coverage) {
180 this->setVertexAttributesWithImplicitOffsets(kAttributes, SK_ARRAY_COUNT(kAttributes));
181 }
182
183 //////////////////////////////////////////////////////////////////////////////
184
185 GR_DEFINE_GEOMETRY_PROCESSOR_TEST(GrConicEffect);
186
187 #if GR_TEST_UTILS
TestCreate(GrProcessorTestData * d)188 GrGeometryProcessor* GrConicEffect::TestCreate(GrProcessorTestData* d) {
189 GrColor color = GrTest::RandomColor(d->fRandom);
190 SkMatrix viewMatrix = GrTest::TestMatrix(d->fRandom);
191 SkMatrix localMatrix = GrTest::TestMatrix(d->fRandom);
192 bool usesLocalCoords = d->fRandom->nextBool();
193 return GrConicEffect::Make(d->allocator(),
194 SkPMColor4f::FromBytes_RGBA(color),
195 viewMatrix,
196 *d->caps(),
197 localMatrix,
198 usesLocalCoords);
199 }
200 #endif
201
202 //////////////////////////////////////////////////////////////////////////////
203 // Quad
204 //////////////////////////////////////////////////////////////////////////////
205
206 class GrQuadEffect::Impl : public ProgramImpl {
207 public:
setData(const GrGLSLProgramDataManager & pdman,const GrShaderCaps & shaderCaps,const GrGeometryProcessor & geomProc)208 void setData(const GrGLSLProgramDataManager& pdman,
209 const GrShaderCaps& shaderCaps,
210 const GrGeometryProcessor& geomProc) override {
211 const GrQuadEffect& qe = geomProc.cast<GrQuadEffect>();
212
213 SetTransform(pdman, shaderCaps, fViewMatrixUniform, qe.fViewMatrix, &fViewMatrix);
214 SetTransform(pdman, shaderCaps, fLocalMatrixUniform, qe.fLocalMatrix, &fLocalMatrix);
215
216 if (qe.fColor != fColor) {
217 pdman.set4fv(fColorUniform, 1, qe.fColor.vec());
218 fColor = qe.fColor;
219 }
220
221 if (qe.fCoverageScale != 0xff && qe.fCoverageScale != fCoverageScale) {
222 pdman.set1f(fCoverageScaleUniform, GrNormalizeByteToFloat(qe.fCoverageScale));
223 fCoverageScale = qe.fCoverageScale;
224 }
225 }
226
227 private:
228 void onEmitCode(EmitArgs&, GrGPArgs*) override;
229
230 SkMatrix fViewMatrix = SkMatrix::InvalidMatrix();
231 SkMatrix fLocalMatrix = SkMatrix::InvalidMatrix();
232 SkPMColor4f fColor = SK_PMColor4fILLEGAL;
233 uint8_t fCoverageScale = 0xFF;
234
235 UniformHandle fColorUniform;
236 UniformHandle fCoverageScaleUniform;
237 UniformHandle fViewMatrixUniform;
238 UniformHandle fLocalMatrixUniform;
239 };
240
onEmitCode(EmitArgs & args,GrGPArgs * gpArgs)241 void GrQuadEffect::Impl::onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) {
242 GrGLSLVertexBuilder* vertBuilder = args.fVertBuilder;
243 const GrQuadEffect& gp = args.fGeomProc.cast<GrQuadEffect>();
244 GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler;
245 GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
246
247 // emit attributes
248 varyingHandler->emitAttributes(gp);
249
250 GrGLSLVarying v(SkSLType::kHalf4);
251 varyingHandler->addVarying("HairQuadEdge", &v);
252 vertBuilder->codeAppendf("%s = %s;", v.vsOut(), gp.inHairQuadEdge().name());
253
254 GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
255 // Setup pass through color
256 fragBuilder->codeAppendf("half4 %s;", args.fOutputColor);
257 this->setupUniformColor(fragBuilder, uniformHandler, args.fOutputColor, &fColorUniform);
258
259 // Setup position
260 WriteOutputPosition(vertBuilder,
261 uniformHandler,
262 *args.fShaderCaps,
263 gpArgs,
264 gp.inPosition().name(),
265 gp.fViewMatrix,
266 &fViewMatrixUniform);
267 if (gp.fUsesLocalCoords) {
268 WriteLocalCoord(vertBuilder,
269 uniformHandler,
270 *args.fShaderCaps,
271 gpArgs,
272 gp.inPosition().asShaderVar(),
273 gp.fLocalMatrix,
274 &fLocalMatrixUniform);
275 }
276
277 fragBuilder->codeAppendf("half edgeAlpha;");
278
279 fragBuilder->codeAppendf("half2 duvdx = half2(dFdx(%s.xy));", v.fsIn());
280 fragBuilder->codeAppendf("half2 duvdy = half2(dFdy(%s.xy));", v.fsIn());
281 fragBuilder->codeAppendf("half2 gF = half2(2.0 * %s.x * duvdx.x - duvdx.y,"
282 " 2.0 * %s.x * duvdy.x - duvdy.y);",
283 v.fsIn(), v.fsIn());
284 fragBuilder->codeAppendf("edgeAlpha = half(%s.x * %s.x - %s.y);",
285 v.fsIn(), v.fsIn(), v.fsIn());
286 fragBuilder->codeAppend("edgeAlpha = sqrt(edgeAlpha * edgeAlpha / dot(gF, gF));");
287 fragBuilder->codeAppend("edgeAlpha = max(1.0 - edgeAlpha, 0.0);");
288 // Add line below for smooth cubic ramp
289 // fragBuilder->codeAppend("edgeAlpha = edgeAlpha*edgeAlpha*(3.0-2.0*edgeAlpha);");
290
291 if (gp.fCoverageScale != 0xFF) {
292 const char* coverageScale;
293 fCoverageScaleUniform = uniformHandler->addUniform(nullptr,
294 kFragment_GrShaderFlag,
295 SkSLType::kHalf,
296 "Coverage",
297 &coverageScale);
298 fragBuilder->codeAppendf("half4 %s = half4(%s * edgeAlpha);", args.fOutputCoverage,
299 coverageScale);
300 } else {
301 fragBuilder->codeAppendf("half4 %s = half4(edgeAlpha);", args.fOutputCoverage);
302 }
303 }
304
305 //////////////////////////////////////////////////////////////////////////////
306
307 GrQuadEffect::~GrQuadEffect() = default;
308
addToKey(const GrShaderCaps & caps,skgpu::KeyBuilder * b) const309 void GrQuadEffect::addToKey(const GrShaderCaps& caps, skgpu::KeyBuilder* b) const {
310 uint32_t key = 0;
311 key |= fCoverageScale != 0xff ? 0x8 : 0x0;
312 key |= fUsesLocalCoords ? 0x10 : 0x0;
313 key = ProgramImpl::AddMatrixKeys(caps,
314 key,
315 fViewMatrix,
316 fUsesLocalCoords ? fLocalMatrix : SkMatrix::I());
317 b->add32(key);
318 }
319
makeProgramImpl(const GrShaderCaps &) const320 std::unique_ptr<GrGeometryProcessor::ProgramImpl> GrQuadEffect::makeProgramImpl(
321 const GrShaderCaps&) const {
322 return std::make_unique<Impl>();
323 }
324
GrQuadEffect(const SkPMColor4f & color,const SkMatrix & viewMatrix,uint8_t coverage,const SkMatrix & localMatrix,bool usesLocalCoords)325 GrQuadEffect::GrQuadEffect(const SkPMColor4f& color, const SkMatrix& viewMatrix, uint8_t coverage,
326 const SkMatrix& localMatrix, bool usesLocalCoords)
327 : INHERITED(kGrQuadEffect_ClassID)
328 , fColor(color)
329 , fViewMatrix(viewMatrix)
330 , fLocalMatrix(localMatrix)
331 , fUsesLocalCoords(usesLocalCoords)
332 , fCoverageScale(coverage) {
333 this->setVertexAttributesWithImplicitOffsets(kAttributes, SK_ARRAY_COUNT(kAttributes));
334 }
335
336 //////////////////////////////////////////////////////////////////////////////
337
338 GR_DEFINE_GEOMETRY_PROCESSOR_TEST(GrQuadEffect);
339
340 #if GR_TEST_UTILS
TestCreate(GrProcessorTestData * d)341 GrGeometryProcessor* GrQuadEffect::TestCreate(GrProcessorTestData* d) {
342 GrColor color = GrTest::RandomColor(d->fRandom);
343 SkMatrix viewMatrix = GrTest::TestMatrix(d->fRandom);
344 SkMatrix localMatrix = GrTest::TestMatrix(d->fRandom);
345 bool usesLocalCoords = d->fRandom->nextBool();
346 return GrQuadEffect::Make(d->allocator(),
347 SkPMColor4f::FromBytes_RGBA(color),
348 viewMatrix,
349 *d->caps(),
350 localMatrix,
351 usesLocalCoords);
352 }
353 #endif
354