1 | /* |
2 | * Copyright 2018 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 | /************************************************************************************************** |
9 | *** This file was autogenerated from GrTwoPointConicalGradientLayout.fp; do not modify. |
10 | **************************************************************************************************/ |
11 | #include "GrTwoPointConicalGradientLayout.h" |
12 | |
13 | #include "src/gpu/GrTexture.h" |
14 | #include "src/gpu/glsl/GrGLSLFragmentProcessor.h" |
15 | #include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h" |
16 | #include "src/gpu/glsl/GrGLSLProgramBuilder.h" |
17 | #include "src/sksl/SkSLCPP.h" |
18 | #include "src/sksl/SkSLUtil.h" |
19 | class GrGLSLTwoPointConicalGradientLayout : public GrGLSLFragmentProcessor { |
20 | public: |
21 | GrGLSLTwoPointConicalGradientLayout() {} |
22 | void emitCode(EmitArgs& args) override { |
23 | GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; |
24 | const GrTwoPointConicalGradientLayout& _outer = |
25 | args.fFp.cast<GrTwoPointConicalGradientLayout>(); |
26 | (void)_outer; |
27 | auto gradientMatrix = _outer.gradientMatrix; |
28 | (void)gradientMatrix; |
29 | auto type = _outer.type; |
30 | (void)type; |
31 | auto isRadiusIncreasing = _outer.isRadiusIncreasing; |
32 | (void)isRadiusIncreasing; |
33 | auto isFocalOnCircle = _outer.isFocalOnCircle; |
34 | (void)isFocalOnCircle; |
35 | auto isWellBehaved = _outer.isWellBehaved; |
36 | (void)isWellBehaved; |
37 | auto isSwapped = _outer.isSwapped; |
38 | (void)isSwapped; |
39 | auto isNativelyFocal = _outer.isNativelyFocal; |
40 | (void)isNativelyFocal; |
41 | auto focalParams = _outer.focalParams; |
42 | (void)focalParams; |
43 | focalParamsVar = args.fUniformHandler->addUniform(&_outer, kFragment_GrShaderFlag, |
44 | kHalf2_GrSLType, "focalParams" ); |
45 | SkString sk_TransformedCoords2D_0 = |
46 | fragBuilder->ensureCoords2D(args.fTransformedCoords[0].fVaryingPoint); |
47 | fragBuilder->codeAppendf( |
48 | "float2 p = %s;\nfloat t = -1.0;\nhalf v = 1.0;\n@switch (%d) {\n case 1:\n " |
49 | " {\n half r0_2 = %s.y;\n t = float(r0_2) - p.y * p.y;\n " |
50 | " if (t >= 0.0) {\n t = p.x + sqrt(t);\n } else " |
51 | "{\n v = -1.0;\n }\n }\n break;\n case " |
52 | "0:\n {\n half r0 = %s.x;\n @if (%s) {\n " |
53 | " t = length(p) - float(r0);\n } else {\n t = " |
54 | "-length(p) - float(r0);\n " , |
55 | sk_TransformedCoords2D_0.c_str(), (int)_outer.type, |
56 | args.fUniformHandler->getUniformCStr(focalParamsVar), |
57 | args.fUniformHandler->getUniformCStr(focalParamsVar), |
58 | (_outer.isRadiusIncreasing ? "true" : "false" )); |
59 | fragBuilder->codeAppendf( |
60 | " }\n }\n break;\n case 2:\n {\n half invR1 " |
61 | "= %s.x;\n half fx = %s.y;\n float x_t = -1.0;\n " |
62 | "@if (%s) {\n x_t = dot(p, p) / p.x;\n } else if (%s) " |
63 | "{\n x_t = length(p) - p.x * float(invR1);\n } else {\n " |
64 | " float temp = p.x * p.x - p.y * p.y;\n if (temp >= " |
65 | "0.0) {\n @if (%s || !%s) {\n x_t = " |
66 | "-sqrt(temp) - p.x * float(invR1)" , |
67 | args.fUniformHandler->getUniformCStr(focalParamsVar), |
68 | args.fUniformHandler->getUniformCStr(focalParamsVar), |
69 | (_outer.isFocalOnCircle ? "true" : "false" ), |
70 | (_outer.isWellBehaved ? "true" : "false" ), (_outer.isSwapped ? "true" : "false" ), |
71 | (_outer.isRadiusIncreasing ? "true" : "false" )); |
72 | fragBuilder->codeAppendf( |
73 | ";\n } else {\n x_t = sqrt(temp) - p.x * " |
74 | "float(invR1);\n }\n }\n }\n " |
75 | " @if (!%s) {\n if (x_t <= 0.0) {\n v = -1.0;\n " |
76 | " }\n }\n @if (%s) {\n @if (%s) " |
77 | "{\n t = x_t;\n } else {\n t " |
78 | "= x_t + float(fx);\n }\n } else {\n @if " |
79 | "(%s) {\n " , |
80 | (_outer.isWellBehaved ? "true" : "false" ), |
81 | (_outer.isRadiusIncreasing ? "true" : "false" ), |
82 | (_outer.isNativelyFocal ? "true" : "false" ), |
83 | (_outer.isNativelyFocal ? "true" : "false" )); |
84 | fragBuilder->codeAppendf( |
85 | " t = -x_t;\n } else {\n t = -x_t + " |
86 | "float(fx);\n }\n }\n @if (%s) {\n " |
87 | " t = 1.0 - t;\n }\n }\n break;\n}\n%s = " |
88 | "half4(half(t), v, 0.0, 0.0);\n" , |
89 | (_outer.isSwapped ? "true" : "false" ), args.fOutputColor); |
90 | } |
91 | |
92 | private: |
93 | void onSetData(const GrGLSLProgramDataManager& pdman, |
94 | const GrFragmentProcessor& _proc) override { |
95 | const GrTwoPointConicalGradientLayout& _outer = |
96 | _proc.cast<GrTwoPointConicalGradientLayout>(); |
97 | { |
98 | const SkPoint& focalParamsValue = _outer.focalParams; |
99 | if (focalParamsPrev != focalParamsValue) { |
100 | focalParamsPrev = focalParamsValue; |
101 | pdman.set2f(focalParamsVar, focalParamsValue.fX, focalParamsValue.fY); |
102 | } |
103 | } |
104 | } |
105 | SkPoint focalParamsPrev = SkPoint::Make(SK_FloatNaN, SK_FloatNaN); |
106 | UniformHandle focalParamsVar; |
107 | }; |
108 | GrGLSLFragmentProcessor* GrTwoPointConicalGradientLayout::onCreateGLSLInstance() const { |
109 | return new GrGLSLTwoPointConicalGradientLayout(); |
110 | } |
111 | void GrTwoPointConicalGradientLayout::onGetGLSLProcessorKey(const GrShaderCaps& caps, |
112 | GrProcessorKeyBuilder* b) const { |
113 | b->add32((int32_t)type); |
114 | b->add32((int32_t)isRadiusIncreasing); |
115 | b->add32((int32_t)isFocalOnCircle); |
116 | b->add32((int32_t)isWellBehaved); |
117 | b->add32((int32_t)isSwapped); |
118 | b->add32((int32_t)isNativelyFocal); |
119 | } |
120 | bool GrTwoPointConicalGradientLayout::onIsEqual(const GrFragmentProcessor& other) const { |
121 | const GrTwoPointConicalGradientLayout& that = other.cast<GrTwoPointConicalGradientLayout>(); |
122 | (void)that; |
123 | if (gradientMatrix != that.gradientMatrix) return false; |
124 | if (type != that.type) return false; |
125 | if (isRadiusIncreasing != that.isRadiusIncreasing) return false; |
126 | if (isFocalOnCircle != that.isFocalOnCircle) return false; |
127 | if (isWellBehaved != that.isWellBehaved) return false; |
128 | if (isSwapped != that.isSwapped) return false; |
129 | if (isNativelyFocal != that.isNativelyFocal) return false; |
130 | if (focalParams != that.focalParams) return false; |
131 | return true; |
132 | } |
133 | GrTwoPointConicalGradientLayout::GrTwoPointConicalGradientLayout( |
134 | const GrTwoPointConicalGradientLayout& src) |
135 | : INHERITED(kGrTwoPointConicalGradientLayout_ClassID, src.optimizationFlags()) |
136 | , fCoordTransform0(src.fCoordTransform0) |
137 | , gradientMatrix(src.gradientMatrix) |
138 | , type(src.type) |
139 | , isRadiusIncreasing(src.isRadiusIncreasing) |
140 | , isFocalOnCircle(src.isFocalOnCircle) |
141 | , isWellBehaved(src.isWellBehaved) |
142 | , isSwapped(src.isSwapped) |
143 | , isNativelyFocal(src.isNativelyFocal) |
144 | , focalParams(src.focalParams) { |
145 | this->addCoordTransform(&fCoordTransform0); |
146 | } |
147 | std::unique_ptr<GrFragmentProcessor> GrTwoPointConicalGradientLayout::clone() const { |
148 | return std::unique_ptr<GrFragmentProcessor>(new GrTwoPointConicalGradientLayout(*this)); |
149 | } |
150 | GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrTwoPointConicalGradientLayout); |
151 | #if GR_TEST_UTILS |
152 | std::unique_ptr<GrFragmentProcessor> GrTwoPointConicalGradientLayout::TestCreate( |
153 | GrProcessorTestData* d) { |
154 | SkScalar scale = GrGradientShader::RandomParams::kGradientScale; |
155 | SkScalar offset = scale / 32.0f; |
156 | |
157 | SkPoint center1 = {d->fRandom->nextRangeScalar(0.0f, scale), |
158 | d->fRandom->nextRangeScalar(0.0f, scale)}; |
159 | SkPoint center2 = {d->fRandom->nextRangeScalar(0.0f, scale), |
160 | d->fRandom->nextRangeScalar(0.0f, scale)}; |
161 | SkScalar radius1 = d->fRandom->nextRangeScalar(0.0f, scale); |
162 | SkScalar radius2 = d->fRandom->nextRangeScalar(0.0f, scale); |
163 | |
164 | constexpr int kTestTypeMask = (1 << 2) - 1, kTestNativelyFocalBit = (1 << 2), |
165 | kTestFocalOnCircleBit = (1 << 3), kTestSwappedBit = (1 << 4); |
166 | // We won't treat isWellDefined and isRadiusIncreasing specially because they |
167 | // should have high probability to be turned on and off as we're getting random |
168 | // radii and centers. |
169 | |
170 | int mask = d->fRandom->nextU(); |
171 | int type = mask & kTestTypeMask; |
172 | if (type == static_cast<int>(Type::kRadial)) { |
173 | center2 = center1; |
174 | // Make sure that the radii are different |
175 | if (SkScalarNearlyZero(radius1 - radius2)) { |
176 | radius2 += offset; |
177 | } |
178 | } else if (type == static_cast<int>(Type::kStrip)) { |
179 | radius1 = std::max(radius1, .1f); // Make sure that the radius is non-zero |
180 | radius2 = radius1; |
181 | // Make sure that the centers are different |
182 | if (SkScalarNearlyZero(SkPoint::Distance(center1, center2))) { |
183 | center2.fX += offset; |
184 | } |
185 | } else { // kFocal_Type |
186 | // Make sure that the centers are different |
187 | if (SkScalarNearlyZero(SkPoint::Distance(center1, center2))) { |
188 | center2.fX += offset; |
189 | } |
190 | |
191 | if (kTestNativelyFocalBit & mask) { |
192 | radius1 = 0; |
193 | } |
194 | if (kTestFocalOnCircleBit & mask) { |
195 | radius2 = radius1 + SkPoint::Distance(center1, center2); |
196 | } |
197 | if (kTestSwappedBit & mask) { |
198 | std::swap(radius1, radius2); |
199 | radius2 = 0; |
200 | } |
201 | |
202 | // Make sure that the radii are different |
203 | if (SkScalarNearlyZero(radius1 - radius2)) { |
204 | radius2 += offset; |
205 | } |
206 | } |
207 | |
208 | if (SkScalarNearlyZero(radius1 - radius2) && |
209 | SkScalarNearlyZero(SkPoint::Distance(center1, center2))) { |
210 | radius2 += offset; // make sure that we're not degenerated |
211 | } |
212 | |
213 | GrGradientShader::RandomParams params(d->fRandom); |
214 | auto shader = params.fUseColors4f |
215 | ? SkGradientShader::MakeTwoPointConical( |
216 | center1, radius1, center2, radius2, params.fColors4f, |
217 | params.fColorSpace, params.fStops, params.fColorCount, |
218 | params.fTileMode) |
219 | : SkGradientShader::MakeTwoPointConical( |
220 | center1, radius1, center2, radius2, params.fColors, |
221 | params.fStops, params.fColorCount, params.fTileMode); |
222 | GrTest::TestAsFPArgs asFPArgs(d); |
223 | std::unique_ptr<GrFragmentProcessor> fp = as_SB(shader)->asFragmentProcessor(asFPArgs.args()); |
224 | |
225 | SkASSERT_RELEASE(fp); |
226 | return fp; |
227 | } |
228 | #endif |
229 | |
230 | // .fp files do not let you reference outside enum definitions, so we have to explicitly map |
231 | // between the two compatible enum defs |
232 | GrTwoPointConicalGradientLayout::Type convert_type(SkTwoPointConicalGradient::Type type) { |
233 | switch (type) { |
234 | case SkTwoPointConicalGradient::Type::kRadial: |
235 | return GrTwoPointConicalGradientLayout::Type::kRadial; |
236 | case SkTwoPointConicalGradient::Type::kStrip: |
237 | return GrTwoPointConicalGradientLayout::Type::kStrip; |
238 | case SkTwoPointConicalGradient::Type::kFocal: |
239 | return GrTwoPointConicalGradientLayout::Type::kFocal; |
240 | } |
241 | SkDEBUGFAIL("Should not be reachable" ); |
242 | return GrTwoPointConicalGradientLayout::Type::kRadial; |
243 | } |
244 | |
245 | std::unique_ptr<GrFragmentProcessor> GrTwoPointConicalGradientLayout::Make( |
246 | const SkTwoPointConicalGradient& grad, const GrFPArgs& args) { |
247 | GrTwoPointConicalGradientLayout::Type grType = convert_type(grad.getType()); |
248 | |
249 | // The focalData struct is only valid if isFocal is true |
250 | const SkTwoPointConicalGradient::FocalData& focalData = grad.getFocalData(); |
251 | bool isFocal = grType == Type::kFocal; |
252 | |
253 | // Calculate optimization switches from gradient specification |
254 | bool isFocalOnCircle = isFocal && focalData.isFocalOnCircle(); |
255 | bool isWellBehaved = isFocal && focalData.isWellBehaved(); |
256 | bool isSwapped = isFocal && focalData.isSwapped(); |
257 | bool isNativelyFocal = isFocal && focalData.isNativelyFocal(); |
258 | |
259 | // Type-specific calculations: isRadiusIncreasing, focalParams, and the gradient matrix. |
260 | // However, all types start with the total inverse local matrix calculated from the shader |
261 | // and args |
262 | bool isRadiusIncreasing; |
263 | SkPoint focalParams; // really just a 2D tuple |
264 | SkMatrix matrix; |
265 | |
266 | // Initialize the base matrix |
267 | if (!grad.totalLocalMatrix(args.fPreLocalMatrix)->invert(&matrix)) { |
268 | return nullptr; |
269 | } |
270 | |
271 | if (isFocal) { |
272 | isRadiusIncreasing = (1 - focalData.fFocalX) > 0; |
273 | |
274 | focalParams.set(1.0 / focalData.fR1, focalData.fFocalX); |
275 | |
276 | matrix.postConcat(grad.getGradientMatrix()); |
277 | } else if (grType == Type::kRadial) { |
278 | SkScalar dr = grad.getDiffRadius(); |
279 | isRadiusIncreasing = dr >= 0; |
280 | |
281 | SkScalar r0 = grad.getStartRadius() / dr; |
282 | focalParams.set(r0, r0 * r0); |
283 | |
284 | // GPU radial matrix is different from the original matrix, since we map the diff radius |
285 | // to have |dr| = 1, so manually compute the final gradient matrix here. |
286 | |
287 | // Map center to (0, 0) |
288 | matrix.postTranslate(-grad.getStartCenter().fX, -grad.getStartCenter().fY); |
289 | |
290 | // scale |diffRadius| to 1 |
291 | matrix.postScale(1 / dr, 1 / dr); |
292 | } else { // kStrip |
293 | isRadiusIncreasing = false; // kStrip doesn't use this flag |
294 | |
295 | SkScalar r0 = grad.getStartRadius() / grad.getCenterX1(); |
296 | focalParams.set(r0, r0 * r0); |
297 | |
298 | matrix.postConcat(grad.getGradientMatrix()); |
299 | } |
300 | |
301 | return std::unique_ptr<GrFragmentProcessor>(new GrTwoPointConicalGradientLayout( |
302 | matrix, grType, isRadiusIncreasing, isFocalOnCircle, isWellBehaved, isSwapped, |
303 | isNativelyFocal, focalParams)); |
304 | } |
305 | |