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