• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2019 Google LLC.
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/tessellate/shaders/GrPathTessellationShader.h"
9 
10 #include "src/gpu/effects/GrDisableColorXP.h"
11 #include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
12 #include "src/gpu/glsl/GrGLSLVarying.h"
13 #include "src/gpu/glsl/GrGLSLVertexGeoBuilder.h"
14 
15 using skgpu::PatchAttribs;
16 
17 namespace {
18 
19 // Draws a simple array of triangles.
20 class SimpleTriangleShader : public GrPathTessellationShader {
21 public:
SimpleTriangleShader(const SkMatrix & viewMatrix,SkPMColor4f color)22     SimpleTriangleShader(const SkMatrix& viewMatrix, SkPMColor4f color)
23             : GrPathTessellationShader(kTessellate_SimpleTriangleShader_ClassID,
24                                        GrPrimitiveType::kTriangles, 0, viewMatrix, color,
25                                        PatchAttribs::kNone) {
26         constexpr static Attribute kInputPointAttrib{"inputPoint", kFloat2_GrVertexAttribType,
27                                                      kFloat2_GrSLType};
28         this->setVertexAttributes(&kInputPointAttrib, 1);
29     }
30 
maxTessellationSegments(const GrShaderCaps &) const31     int maxTessellationSegments(const GrShaderCaps&) const override { SkUNREACHABLE; }
32 
getShaderDfxInfo() const33     SkString getShaderDfxInfo() const override { return SkString("ShaderDfx_SimpleTriangleShader"); }
34 
35 private:
name() const36     const char* name() const final { return "tessellate_SimpleTriangleShader"; }
addToKey(const GrShaderCaps &,GrProcessorKeyBuilder *) const37     void addToKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const final {}
38     std::unique_ptr<ProgramImpl> makeProgramImpl(const GrShaderCaps&) const final;
39 };
40 
makeProgramImpl(const GrShaderCaps &) const41 std::unique_ptr<GrGeometryProcessor::ProgramImpl> SimpleTriangleShader::makeProgramImpl(
42         const GrShaderCaps&) const {
43     class Impl : public GrPathTessellationShader::Impl {
44         void emitVertexCode(const GrShaderCaps&,
45                             const GrPathTessellationShader&,
46                             GrGLSLVertexBuilder* v,
47                             GrGLSLVaryingHandler*,
48                             GrGPArgs* gpArgs) override {
49             v->codeAppend(R"(
50             float2 localcoord = inputPoint;
51             float2 vertexpos = AFFINE_MATRIX * localcoord + TRANSLATE;)");
52             gpArgs->fLocalCoordVar.set(kFloat2_GrSLType, "localcoord");
53             gpArgs->fPositionVar.set(kFloat2_GrSLType, "vertexpos");
54         }
55     };
56     return std::make_unique<Impl>();
57 }
58 
59 }  // namespace
60 
Make(SkArenaAlloc * arena,const SkMatrix & viewMatrix,const SkPMColor4f & color,int totalCombinedPathVerbCnt,const GrPipeline & pipeline,skgpu::PatchAttribs attribs,const GrCaps & caps)61 GrPathTessellationShader* GrPathTessellationShader::Make(SkArenaAlloc* arena,
62                                                          const SkMatrix& viewMatrix,
63                                                          const SkPMColor4f& color,
64                                                          int totalCombinedPathVerbCnt,
65                                                          const GrPipeline& pipeline,
66                                                          skgpu::PatchAttribs attribs,
67                                                          const GrCaps& caps) {
68     if (caps.shaderCaps()->tessellationSupport() &&
69         totalCombinedPathVerbCnt >= caps.minPathVerbsForHwTessellation() &&
70         !pipeline.usesLocalCoords() &&  // Our tessellation back door doesn't handle varyings.
71         // Input color and explicit curve type workarounds aren't implemented yet for tessellation.
72         !(attribs & (PatchAttribs::kColor | PatchAttribs::kExplicitCurveType))) {
73         return GrPathTessellationShader::MakeHardwareTessellationShader(arena, viewMatrix, color,
74                                                                         attribs);
75     } else {
76         return GrPathTessellationShader::MakeMiddleOutFixedCountShader(*caps.shaderCaps(), arena,
77                                                                        viewMatrix, color,
78                                                                        attribs);
79     }
80 }
81 
MakeSimpleTriangleShader(SkArenaAlloc * arena,const SkMatrix & viewMatrix,const SkPMColor4f & color)82 GrPathTessellationShader* GrPathTessellationShader::MakeSimpleTriangleShader(
83         SkArenaAlloc* arena, const SkMatrix& viewMatrix, const SkPMColor4f& color) {
84     return arena->make<SimpleTriangleShader>(viewMatrix, color);
85 }
86 
MakeStencilOnlyPipeline(const ProgramArgs & args,GrAAType aaType,const GrAppliedHardClip & hardClip,GrPipeline::InputFlags pipelineFlags)87 const GrPipeline* GrPathTessellationShader::MakeStencilOnlyPipeline(
88         const ProgramArgs& args,
89         GrAAType aaType,
90         const GrAppliedHardClip& hardClip,
91         GrPipeline::InputFlags pipelineFlags) {
92     GrPipeline::InitArgs pipelineArgs;
93     pipelineArgs.fInputFlags = pipelineFlags;
94     pipelineArgs.fCaps = args.fCaps;
95     return args.fArena->make<GrPipeline>(pipelineArgs,
96                                          GrDisableColorXPFactory::MakeXferProcessor(),
97                                          hardClip);
98 }
99 
100 // Evaluate our point of interest using numerically stable linear interpolations. We add our own
101 // "safe_mix" method to guarantee we get exactly "b" when T=1. The builtin mix() function seems
102 // spec'd to behave this way, but empirical results results have shown it does not always.
103 const char* GrPathTessellationShader::Impl::kEvalRationalCubicFn = R"(
104 float3 safe_mix(float3 a, float3 b, float T, float one_minus_T) {
105     return a*one_minus_T + b*T;
106 }
107 float2 eval_rational_cubic(float4x3 P, float T) {
108     float one_minus_T = 1.0 - T;
109     float3 ab = safe_mix(P[0], P[1], T, one_minus_T);
110     float3 bc = safe_mix(P[1], P[2], T, one_minus_T);
111     float3 cd = safe_mix(P[2], P[3], T, one_minus_T);
112     float3 abc = safe_mix(ab, bc, T, one_minus_T);
113     float3 bcd = safe_mix(bc, cd, T, one_minus_T);
114     float3 abcd = safe_mix(abc, bcd, T, one_minus_T);
115     return abcd.xy / abcd.z;
116 })";
117 
onEmitCode(EmitArgs & args,GrGPArgs * gpArgs)118 void GrPathTessellationShader::Impl::onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) {
119     const auto& shader = args.fGeomProc.cast<GrPathTessellationShader>();
120     args.fVaryingHandler->emitAttributes(shader);
121 
122     // Vertex shader.
123     const char* affineMatrix, *translate;
124     fAffineMatrixUniform = args.fUniformHandler->addUniform(nullptr, kVertex_GrShaderFlag,
125                                                             kFloat4_GrSLType, "affineMatrix",
126                                                             &affineMatrix);
127     fTranslateUniform = args.fUniformHandler->addUniform(nullptr, kVertex_GrShaderFlag,
128                                                          kFloat2_GrSLType, "translate", &translate);
129     args.fVertBuilder->codeAppendf("float2x2 AFFINE_MATRIX = float2x2(%s);", affineMatrix);
130     args.fVertBuilder->codeAppendf("float2 TRANSLATE = %s;", translate);
131     this->emitVertexCode(*args.fShaderCaps,
132                          shader,
133                          args.fVertBuilder,
134                          args.fVaryingHandler,
135                          gpArgs);
136 
137     // Fragment shader.
138     if (!(shader.fAttribs & PatchAttribs::kColor)) {
139         const char* color;
140         fColorUniform = args.fUniformHandler->addUniform(nullptr, kFragment_GrShaderFlag,
141                                                          kHalf4_GrSLType, "color", &color);
142         args.fFragBuilder->codeAppendf("half4 %s = %s;", args.fOutputColor, color);
143     } else {
144         args.fFragBuilder->codeAppendf("half4 %s = %s;",
145                                        args.fOutputColor, fVaryingColorName.c_str());
146     }
147     args.fFragBuilder->codeAppendf("const half4 %s = half4(1);", args.fOutputCoverage);
148 }
149 
setData(const GrGLSLProgramDataManager & pdman,const GrShaderCaps &,const GrGeometryProcessor & geomProc)150 void GrPathTessellationShader::Impl::setData(const GrGLSLProgramDataManager& pdman, const
151                                              GrShaderCaps&, const GrGeometryProcessor& geomProc) {
152     const auto& shader = geomProc.cast<GrPathTessellationShader>();
153     const SkMatrix& m = shader.viewMatrix();
154     pdman.set4f(fAffineMatrixUniform, m.getScaleX(), m.getSkewY(), m.getSkewX(), m.getScaleY());
155     pdman.set2f(fTranslateUniform, m.getTranslateX(), m.getTranslateY());
156 
157     if (!(shader.fAttribs & PatchAttribs::kColor)) {
158         const SkPMColor4f& color = shader.color();
159         pdman.set4f(fColorUniform, color.fR, color.fG, color.fB, color.fA);
160     }
161 }
162