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