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/GrPathProcessor.h"
9
10#include "include/private/SkTo.h"
11#include "src/gpu/GrShaderCaps.h"
12#include "src/gpu/gl/GrGLGpu.h"
13#ifdef SK_GL
14#include "src/gpu/gl/GrGLVaryingHandler.h"
15#endif
16#include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
17#include "src/gpu/glsl/GrGLSLPrimitiveProcessor.h"
18#include "src/gpu/glsl/GrGLSLUniformHandler.h"
19#include "src/gpu/glsl/GrGLSLVarying.h"
20
21class GrGLPathProcessor : public GrGLSLPrimitiveProcessor {
22public:
23 GrGLPathProcessor() : fColor(SK_PMColor4fILLEGAL) {}
24
25 static void GenKey(const GrPathProcessor& pathProc,
26 const GrShaderCaps&,
27 GrProcessorKeyBuilder* b) {
28 b->add32(SkToInt(pathProc.viewMatrix().hasPerspective()));
29 }
30
31 void emitCode(EmitArgs& args) override {
32 GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
33 const GrPathProcessor& pathProc = args.fGP.cast<GrPathProcessor>();
34
35 if (!pathProc.viewMatrix().hasPerspective()) {
36 args.fVaryingHandler->setNoPerspective();
37 }
38
39 // emit transforms
40 this->emitTransforms(args.fVaryingHandler, args.fUniformHandler,
41 args.fFPCoordTransformHandler);
42
43 // Setup uniform color
44 const char* stagedLocalVarName;
45 fColorUniform = args.fUniformHandler->addUniform(nullptr,
46 kFragment_GrShaderFlag,
47 kHalf4_GrSLType,
48 "Color",
49 &stagedLocalVarName);
50 fragBuilder->codeAppendf("%s = %s;", args.fOutputColor, stagedLocalVarName);
51
52 // setup constant solid coverage
53 fragBuilder->codeAppendf("%s = half4(1);", args.fOutputCoverage);
54 }
55
56 SkString matrix_to_sksl(const SkMatrix& m) {
57 return SkStringPrintf("float3x3(%f, %f, %f, %f, %f, %f, %f, %f, %f)", m[0], m[1], m[2],
58 m[3], m[4], m[5], m[6], m[7], m[8]);
59 }
60
61 void emitTransforms(GrGLSLVaryingHandler* varyingHandler,
62 GrGLSLUniformHandler* uniformHandler,
63 FPCoordTransformHandler* transformHandler) {
64 for (int i = 0; *transformHandler; ++*transformHandler, ++i) {
65 auto [coordTransform, fp] = transformHandler->get();
66
67 SkString matrix;
68 GrShaderVar fragmentVar;
69 GrShaderVar transformVar;
70 if (fp.isSampledWithExplicitCoords()) {
71 if (coordTransform.isNoOp()) {
72 transformHandler->omitCoordsForCurrCoordTransform();
73 continue;
74 } else {
75 const char* name;
76 SkString strUniName;
77 strUniName.printf("CoordTransformMatrix_%d", i);
78 auto& uni = fUniformTransform.push_back();
79 if (coordTransform.matrix().isScaleTranslate()) {
80 uni.fType = kFloat4_GrSLType;
81 } else {
82 uni.fType = kFloat3x3_GrSLType;
83 }
84 uni.fHandle = uniformHandler
85 ->addUniform(nullptr,
86 kFragment_GrShaderFlag,
87 uni.fType,
88 strUniName.c_str(),
89 &name)
90 .toIndex();
91 transformVar = uniformHandler->getUniformVariable(uni.fHandle);
92 }
93 } else {
94 SkString strVaryingName;
95 strVaryingName.printf("TransformedCoord_%d", i);
96 GrSLType varyingType = coordTransform.matrix().hasPerspective() ? kHalf3_GrSLType
97 : kHalf2_GrSLType;
98 GrGLSLVarying v(varyingType);
99#ifdef SK_GL
100 GrGLVaryingHandler* glVaryingHandler = (GrGLVaryingHandler*)varyingHandler;
101 fVaryingTransform.push_back().fHandle =
102 glVaryingHandler->addPathProcessingVarying(strVaryingName.c_str(), &v)
103 .toIndex();
104#endif
105 fVaryingTransform.back().fType = varyingType;
106 matrix = matrix_to_sksl(coordTransform.matrix());
107 fragmentVar = {SkString(v.fsIn()), varyingType};
108 }
109 transformHandler->specifyCoordsForCurrCoordTransform(transformVar, fragmentVar);
110 }
111 }
112
113 void setData(const GrGLSLProgramDataManager& pd,
114 const GrPrimitiveProcessor& primProc,
115 const CoordTransformRange& transformRange) override {
116 const GrPathProcessor& pathProc = primProc.cast<GrPathProcessor>();
117 if (pathProc.color() != fColor) {
118 pd.set4fv(fColorUniform, 1, pathProc.color().vec());
119 fColor = pathProc.color();
120 }
121
122 int v = 0, u = 0;
123 for (auto [transform, fp] : transformRange) {
124 if (fp.isSampledWithExplicitCoords()) {
125 if (transform.isNoOp()) {
126 continue;
127 }
128 if (fUniformTransform[u].fHandle.isValid()) {
129 SkMatrix m = GetTransformMatrix(transform, SkMatrix::I());
130 if (!SkMatrixPriv::CheapEqual(fUniformTransform[u].fCurrentValue, m)) {
131 fUniformTransform[u].fCurrentValue = m;
132 if (fUniformTransform[u].fType == kFloat4_GrSLType) {
133 float values[4] = {m.getScaleX(), m.getTranslateX(),
134 m.getScaleY(), m.getTranslateY()};
135 pd.set4fv(fUniformTransform[u].fHandle.toIndex(), 1, values);
136 } else {
137 SkASSERT(fUniformTransform[u].fType == kFloat3x3_GrSLType);
138 pd.setSkMatrix(fUniformTransform[u].fHandle.toIndex(), m);
139 }
140 }
141 }
142 ++u;
143 } else {
144 SkASSERT(fVaryingTransform[v].fHandle.isValid());
145 SkMatrix m = GetTransformMatrix(transform, pathProc.localMatrix());
146 if (!SkMatrixPriv::CheapEqual(fVaryingTransform[v].fCurrentValue, m)) {
147 fVaryingTransform[v].fCurrentValue = m;
148 SkASSERT(fVaryingTransform[v].fType == kHalf2_GrSLType ||
149 fVaryingTransform[v].fType == kHalf3_GrSLType);
150 int components = fVaryingTransform[v].fType == kHalf2_GrSLType ? 2 : 3;
151 pd.setPathFragmentInputTransform(fVaryingTransform[v].fHandle, components, m);
152 }
153 ++v;
154 }
155 }
156 }
157
158private:
159 using VaryingHandle = GrGLSLProgramDataManager::VaryingHandle;
160
161 // Varying transforms are used for non-explicitly sampled FPs. We provide a matrix
162 // to GL as fixed function state and it uses it to compute a varying that we pick up
163 // in the FS as the output of the coord transform.
164 struct TransformVarying {
165 VaryingHandle fHandle;
166 SkMatrix fCurrentValue = SkMatrix::InvalidMatrix();
167 GrSLType fType = kVoid_GrSLType;
168 };
169 // For explicitly sampled FPs we stick a uniform in the FS and apply it to the explicit coords
170 // to implement the CoordTransform.
171 struct TransformUniform {
172 UniformHandle fHandle;
173 SkMatrix fCurrentValue = SkMatrix::InvalidMatrix();
174 GrSLType fType = kVoid_GrSLType;
175 };
176
177 SkTArray<TransformVarying, true> fVaryingTransform;
178 SkTArray<TransformUniform, true> fUniformTransform;
179
180 UniformHandle fColorUniform;
181 SkPMColor4f fColor;
182
183 typedef GrGLSLPrimitiveProcessor INHERITED;
184};
185
186GrPathProcessor::GrPathProcessor(const SkPMColor4f& color,
187 const SkMatrix& viewMatrix,
188 const SkMatrix& localMatrix)
189 : INHERITED(kGrPathProcessor_ClassID)
190 , fColor(color)
191 , fViewMatrix(viewMatrix)
192 , fLocalMatrix(localMatrix) {}
193
194void GrPathProcessor::getGLSLProcessorKey(const GrShaderCaps& caps,
195 GrProcessorKeyBuilder* b) const {
196 GrGLPathProcessor::GenKey(*this, caps, b);
197}
198
199GrGLSLPrimitiveProcessor* GrPathProcessor::createGLSLInstance(const GrShaderCaps& caps) const {
200 SkASSERT(caps.pathRenderingSupport());
201 return new GrGLPathProcessor();
202}
203