/src/skia/src/core/SkKnownRuntimeEffects.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright 2024 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/core/SkKnownRuntimeEffects.h" |
9 | | |
10 | | #include "include/core/SkString.h" |
11 | | #include "include/effects/SkRuntimeEffect.h" |
12 | | #include "src/core/SkRuntimeEffectPriv.h" |
13 | | #include "src/effects/imagefilters/SkMatrixConvolutionImageFilter.h" |
14 | | |
15 | | namespace SkKnownRuntimeEffects { |
16 | | |
17 | | namespace { |
18 | | |
19 | | // This must be kept in sync w/ the version in BlurUtils.h |
20 | | static constexpr int kMaxBlurSamples = 28; |
21 | | |
22 | 12 | SkRuntimeEffect* make_blur_1D_effect(int kernelWidth, const SkRuntimeEffect::Options& options) { |
23 | 12 | SkASSERT(kernelWidth <= kMaxBlurSamples); |
24 | | // The SkSL structure performs two kernel taps; if the kernel has an odd width the last |
25 | | // sample will be skipped with the current loop limit calculation. |
26 | 12 | SkASSERT(kernelWidth % 2 == 0); |
27 | 12 | return SkMakeRuntimeEffect(SkRuntimeEffect::MakeForShader, |
28 | 12 | SkStringPrintf( |
29 | | // The coefficients are always stored for the max radius to keep the |
30 | | // uniform block consistent across all effects. |
31 | 12 | "const int kMaxUniformKernelSize = %d / 2;" |
32 | | // But we generate an exact loop over the kernel size. Note that this |
33 | | // program can be used for kernels smaller than the constructed max as long |
34 | | // as the kernel weights for excess entries are set to 0. |
35 | 12 | "const int kMaxLoopLimit = %d / 2;" |
36 | | |
37 | 12 | "uniform half4 offsetsAndKernel[kMaxUniformKernelSize];" |
38 | 12 | "uniform half2 dir;" |
39 | | |
40 | 12 | "uniform shader child;" |
41 | | |
42 | 12 | "half4 main(float2 coord) {" |
43 | 12 | "half4 sum = half4(0);" |
44 | 12 | "for (int i = 0; i < kMaxLoopLimit; ++i) {" |
45 | 12 | "half4 s = offsetsAndKernel[i];" |
46 | 12 | "sum += s.y * child.eval(coord + s.x*dir);" |
47 | 12 | "sum += s.w * child.eval(coord + s.z*dir);" |
48 | 12 | "}" |
49 | 12 | "return sum;" |
50 | 12 | "}", kMaxBlurSamples, kernelWidth).c_str(), |
51 | 12 | options); |
52 | 12 | } |
53 | | |
54 | 13 | SkRuntimeEffect* make_blur_2D_effect(int maxKernelSize, const SkRuntimeEffect::Options& options) { |
55 | 13 | SkASSERT(maxKernelSize % 4 == 0); |
56 | 13 | return SkMakeRuntimeEffect(SkRuntimeEffect::MakeForShader, |
57 | 13 | SkStringPrintf( |
58 | | // The coefficients are always stored for the max radius to keep the |
59 | | // uniform block consistent across all effects. |
60 | 13 | "const int kMaxUniformKernelSize = %d / 4;" |
61 | 13 | "const int kMaxUniformOffsetsSize = 2*kMaxUniformKernelSize;" |
62 | | // But we generate an exact loop over the kernel size. Note that this |
63 | | // program can be used for kernels smaller than the constructed max as long |
64 | | // as the kernel weights for excess entries are set to 0. |
65 | 13 | "const int kMaxLoopLimit = %d / 4;" |
66 | | |
67 | | // Pack scalar coefficients into half4 for better packing on std140, and |
68 | | // upload offsets to avoid having to transform the 1D index into a 2D coord |
69 | 13 | "uniform half4 kernel[kMaxUniformKernelSize];" |
70 | 13 | "uniform half4 offsets[kMaxUniformOffsetsSize];" |
71 | | |
72 | 13 | "uniform shader child;" |
73 | | |
74 | 13 | "half4 main(float2 coord) {" |
75 | 13 | "half4 sum = half4(0);" |
76 | | |
77 | 13 | "for (int i = 0; i < kMaxLoopLimit; ++i) {" |
78 | 13 | "half4 k = kernel[i];" |
79 | 13 | "half4 o = offsets[2*i];" |
80 | 13 | "sum += k.x * child.eval(coord + o.xy);" |
81 | 13 | "sum += k.y * child.eval(coord + o.zw);" |
82 | 13 | "o = offsets[2*i + 1];" |
83 | 13 | "sum += k.z * child.eval(coord + o.xy);" |
84 | 13 | "sum += k.w * child.eval(coord + o.zw);" |
85 | 13 | "}" |
86 | 13 | "return sum;" |
87 | 13 | "}", kMaxBlurSamples, maxKernelSize).c_str(), |
88 | 13 | options); |
89 | 13 | } |
90 | | |
91 | | enum class MatrixConvolutionImpl { |
92 | | kUniformBased, |
93 | | kTextureBasedSm, |
94 | | kTextureBasedLg, |
95 | | }; |
96 | | |
97 | | // There are three shader variants: |
98 | | // a smaller kernel version that stores the matrix in uniforms and iterates in 1D |
99 | | // a larger kernel version that stores the matrix in a 1D texture. The texture version has small |
100 | | // and large variants w/ the actual kernel size uploaded as a uniform. |
101 | | SkRuntimeEffect* make_matrix_conv_effect(MatrixConvolutionImpl impl, |
102 | 6 | const SkRuntimeEffect::Options& options) { |
103 | | // While the uniforms and kernel access are different, pieces of the algorithm are common and |
104 | | // defined statically for re-use in the two shaders: |
105 | 6 | static const char* kHeaderAndBeginLoopSkSL = |
106 | 6 | "uniform int2 size;" |
107 | 6 | "uniform int2 offset;" |
108 | 6 | "uniform half2 gainAndBias;" |
109 | 6 | "uniform int convolveAlpha;" // FIXME not a full int? Put in a half3 w/ gainAndBias? |
110 | | |
111 | 6 | "uniform shader child;" |
112 | | |
113 | 6 | "half4 main(float2 coord) {" |
114 | 6 | "half4 sum = half4(0);" |
115 | 6 | "half origAlpha = 0;" |
116 | 6 | "int2 kernelPos = int2(0);" |
117 | 6 | "for (int i = 0; i < kMaxKernelSize; ++i) {" |
118 | 6 | "if (kernelPos.y >= size.y) { break; }"; |
119 | | |
120 | | // Used in the inner loop to accumulate convolution sum and increment the kernel position |
121 | 6 | static const char* kAccumulateAndIncrementSkSL = |
122 | 6 | "half4 c = child.eval(coord + half2(kernelPos) - half2(offset));" |
123 | 6 | "if (convolveAlpha == 0) {" |
124 | | // When not convolving alpha, remember the original alpha for actual sample |
125 | | // coord, and perform accumulation on unpremul colors. |
126 | 6 | "if (kernelPos == offset) {" |
127 | 6 | "origAlpha = c.a;" |
128 | 6 | "}" |
129 | 6 | "c = unpremul(c);" |
130 | 6 | "}" |
131 | 6 | "sum += c*k;" |
132 | 6 | "kernelPos.x += 1;" |
133 | 6 | "if (kernelPos.x >= size.x) {" |
134 | 6 | "kernelPos.x = 0;" |
135 | 6 | "kernelPos.y += 1;" |
136 | 6 | "}"; |
137 | | |
138 | | // Closes the loop and calculates final color |
139 | 6 | static const char* kCloseLoopAndFooterSkSL = |
140 | 6 | "}" |
141 | 6 | "half4 color = sum*gainAndBias.x + gainAndBias.y;" |
142 | 6 | "if (convolveAlpha == 0) {" |
143 | | // Reset the alpha to the original and convert to premul RGB |
144 | 6 | "color = half4(color.rgb*origAlpha, origAlpha);" |
145 | 6 | "} else {" |
146 | | // Ensure convolved alpha is within [0, 1] |
147 | 6 | "color.a = saturate(color.a);" |
148 | 6 | "}" |
149 | | // Make RGB valid premul w/ respect to the alpha (either original or convolved) |
150 | 6 | "color.rgb = clamp(color.rgb, 0, color.a);" |
151 | 6 | "return color;" |
152 | 6 | "}"; |
153 | | |
154 | 6 | static const auto makeTextureEffect = [](int maxTextureKernelSize, |
155 | 6 | const SkRuntimeEffect::Options& options) { |
156 | 1 | return SkMakeRuntimeEffect( |
157 | 1 | SkRuntimeEffect::MakeForShader, |
158 | 1 | SkStringPrintf("const int kMaxKernelSize = %d;" |
159 | 1 | "uniform shader kernel;" |
160 | 1 | "uniform half2 innerGainAndBias;" |
161 | 1 | "%s" // kHeaderAndBeginLoopSkSL |
162 | 1 | "half k = kernel.eval(half2(half(i) + 0.5, 0.5)).a;" |
163 | 1 | "k = k * innerGainAndBias.x + innerGainAndBias.y;" |
164 | 1 | "%s" // kAccumulateAndIncrementSkSL |
165 | 1 | "%s", // kCloseLoopAndFooterSkSL |
166 | 1 | maxTextureKernelSize, |
167 | 1 | kHeaderAndBeginLoopSkSL, |
168 | 1 | kAccumulateAndIncrementSkSL, |
169 | 1 | kCloseLoopAndFooterSkSL).c_str(), |
170 | 1 | options); |
171 | 1 | }; |
172 | | |
173 | 6 | switch (impl) { |
174 | 5 | case MatrixConvolutionImpl::kUniformBased: { |
175 | 5 | return SkMakeRuntimeEffect( |
176 | 5 | SkRuntimeEffect::MakeForShader, |
177 | 5 | SkStringPrintf("const int kMaxKernelSize = %d / 4;" |
178 | 5 | "uniform half4 kernel[kMaxKernelSize];" |
179 | 5 | "%s" // kHeaderAndBeginLoopSkSL |
180 | 5 | "half4 k4 = kernel[i];" |
181 | 5 | "for (int j = 0; j < 4; ++j) {" |
182 | 5 | "if (kernelPos.y >= size.y) { break; }" |
183 | 5 | "half k = k4[j];" |
184 | 5 | "%s" // kAccumulateAndIncrementSkSL |
185 | 5 | "}" |
186 | 5 | "%s", // kCloseLoopAndFooterSkSL |
187 | 5 | MatrixConvolutionImageFilter::kMaxUniformKernelSize, |
188 | 5 | kHeaderAndBeginLoopSkSL, |
189 | 5 | kAccumulateAndIncrementSkSL, |
190 | 5 | kCloseLoopAndFooterSkSL).c_str(), |
191 | 5 | options); |
192 | 0 | } |
193 | 0 | case MatrixConvolutionImpl::kTextureBasedSm: |
194 | 0 | return makeTextureEffect(MatrixConvolutionImageFilter::kSmallKernelSize, options); |
195 | 1 | case MatrixConvolutionImpl::kTextureBasedLg: |
196 | 1 | return makeTextureEffect(MatrixConvolutionImageFilter::kLargeKernelSize, options); |
197 | 6 | } |
198 | | |
199 | 6 | SkUNREACHABLE; |
200 | 6 | } |
201 | | |
202 | | } // anonymous namespace |
203 | | |
204 | 65.8k | const SkRuntimeEffect* GetKnownRuntimeEffect(StableKey stableKey) { |
205 | 65.8k | SkRuntimeEffect::Options options; |
206 | 65.8k | SkRuntimeEffectPriv::SetStableKey(&options, static_cast<uint32_t>(stableKey)); |
207 | 65.8k | SkRuntimeEffectPriv::AllowPrivateAccess(&options); |
208 | | |
209 | 65.8k | switch (stableKey) { |
210 | 0 | case StableKey::kInvalid: |
211 | 0 | return nullptr; |
212 | | |
213 | | // Shaders |
214 | 647 | case StableKey::k1DBlur4: { |
215 | 647 | static SkRuntimeEffect* s1DBlurEffect = make_blur_1D_effect(4, options); |
216 | 647 | return s1DBlurEffect; |
217 | 0 | } |
218 | 1.10k | case StableKey::k1DBlur8: { |
219 | 1.10k | static SkRuntimeEffect* s1DBlurEffect = make_blur_1D_effect(8, options); |
220 | 1.10k | return s1DBlurEffect; |
221 | 0 | } |
222 | 393 | case StableKey::k1DBlur12: { |
223 | 393 | static SkRuntimeEffect* s1DBlurEffect = make_blur_1D_effect(12, options); |
224 | 393 | return s1DBlurEffect; |
225 | 0 | } |
226 | 16.5k | case StableKey::k1DBlur16: { |
227 | 16.5k | static SkRuntimeEffect* s1DBlurEffect = make_blur_1D_effect(16, options); |
228 | 16.5k | return s1DBlurEffect; |
229 | 0 | } |
230 | 0 | case StableKey::k1DBlur20: { |
231 | 0 | static SkRuntimeEffect* s1DBlurEffect = make_blur_1D_effect(20, options); |
232 | 0 | return s1DBlurEffect; |
233 | 0 | } |
234 | 0 | case StableKey::k1DBlur28: { |
235 | 0 | static SkRuntimeEffect* s1DBlurEffect = make_blur_1D_effect(28, options); |
236 | 0 | return s1DBlurEffect; |
237 | 0 | } |
238 | 0 | case StableKey::k2DBlur4: { |
239 | 0 | static SkRuntimeEffect* s2DBlurEffect = make_blur_2D_effect(4, options); |
240 | 0 | return s2DBlurEffect; |
241 | 0 | } |
242 | 0 | case StableKey::k2DBlur8: { |
243 | 0 | static SkRuntimeEffect* s2DBlurEffect = make_blur_2D_effect(8, options); |
244 | 0 | return s2DBlurEffect; |
245 | 0 | } |
246 | 282 | case StableKey::k2DBlur12: { |
247 | 282 | static SkRuntimeEffect* s2DBlurEffect = make_blur_2D_effect(12, options); |
248 | 282 | return s2DBlurEffect; |
249 | 0 | } |
250 | 20 | case StableKey::k2DBlur16: { |
251 | 20 | static SkRuntimeEffect* s2DBlurEffect = make_blur_2D_effect(16, options); |
252 | 20 | return s2DBlurEffect; |
253 | 0 | } |
254 | 0 | case StableKey::k2DBlur20: { |
255 | 0 | static SkRuntimeEffect* s2DBlurEffect = make_blur_2D_effect(20, options); |
256 | 0 | return s2DBlurEffect; |
257 | 0 | } |
258 | 87 | case StableKey::k2DBlur28: { |
259 | 87 | static SkRuntimeEffect* s2DBlurEffect = make_blur_2D_effect(28, options); |
260 | 87 | return s2DBlurEffect; |
261 | 0 | } |
262 | 1.27k | case StableKey::kBlend: { |
263 | 1.27k | static constexpr char kBlendShaderCode[] = |
264 | 1.27k | "uniform shader s, d;" |
265 | 1.27k | "uniform blender b;" |
266 | 1.27k | "half4 main(float2 xy) {" |
267 | 1.27k | "return b.eval(s.eval(xy), d.eval(xy));" |
268 | 1.27k | "}"; |
269 | | |
270 | 1.27k | static const SkRuntimeEffect* sBlendEffect = |
271 | 1.27k | SkMakeRuntimeEffect(SkRuntimeEffect::MakeForShader, |
272 | 1.27k | kBlendShaderCode, |
273 | 1.27k | options); |
274 | 1.27k | return sBlendEffect; |
275 | 0 | } |
276 | 7.23k | case StableKey::kLerp: { |
277 | 7.23k | static constexpr char kLerpFilterCode[] = |
278 | 7.23k | "uniform colorFilter cf0;" |
279 | 7.23k | "uniform colorFilter cf1;" |
280 | 7.23k | "uniform half weight;" |
281 | | |
282 | 7.23k | "half4 main(half4 color) {" |
283 | 7.23k | "return mix(cf0.eval(color), cf1.eval(color), weight);" |
284 | 7.23k | "}"; |
285 | | |
286 | 7.23k | static const SkRuntimeEffect* sLerpEffect = |
287 | 7.23k | SkMakeRuntimeEffect(SkRuntimeEffect::MakeForColorFilter, |
288 | 7.23k | kLerpFilterCode, |
289 | 7.23k | options); |
290 | 7.23k | return sLerpEffect; |
291 | 0 | } |
292 | 2.61k | case StableKey::kMatrixConvUniforms: { |
293 | 2.61k | static const SkRuntimeEffect* sMatrixConvUniformsEffect = |
294 | 2.61k | make_matrix_conv_effect(MatrixConvolutionImpl::kUniformBased, options); |
295 | 2.61k | return sMatrixConvUniformsEffect; |
296 | 0 | } |
297 | | |
298 | 0 | case StableKey::kMatrixConvTexSm: { |
299 | 0 | static const SkRuntimeEffect* sMatrixConvTexSmEffect = |
300 | 0 | make_matrix_conv_effect(MatrixConvolutionImpl::kTextureBasedSm, options); |
301 | 0 | return sMatrixConvTexSmEffect; |
302 | 0 | } |
303 | | |
304 | 24 | case StableKey::kMatrixConvTexLg: { |
305 | 24 | static const SkRuntimeEffect* sMatrixConvTexMaxEffect = |
306 | 24 | make_matrix_conv_effect(MatrixConvolutionImpl::kTextureBasedLg, options); |
307 | 24 | return sMatrixConvTexMaxEffect; |
308 | 0 | } |
309 | 1.28k | case StableKey::kDecal: { |
310 | 1.28k | static constexpr char kDecalShaderCode[] = |
311 | 1.28k | "uniform shader image;" |
312 | 1.28k | "uniform float4 decalBounds;" |
313 | | |
314 | 1.28k | "half4 main(float2 coord) {" |
315 | 1.28k | "return sk_decal(image, coord, decalBounds);" |
316 | 1.28k | "}"; |
317 | | |
318 | 1.28k | static const SkRuntimeEffect* sDecalEffect = |
319 | 1.28k | SkMakeRuntimeEffect(SkRuntimeEffect::MakeForShader, |
320 | 1.28k | kDecalShaderCode, |
321 | 1.28k | options); |
322 | 1.28k | return sDecalEffect; |
323 | 0 | } |
324 | 4.49k | case StableKey::kDisplacement: { |
325 | | // NOTE: This uses dot product selection to work on all GLES2 hardware (enforced by |
326 | | // public runtime effect restrictions). Otherwise, this would use a "uniform ivec2" |
327 | | // and component indexing to convert the displacement color into a vector. |
328 | 4.49k | static constexpr char kDisplacementShaderCode[] = |
329 | 4.49k | "uniform shader displMap;" |
330 | 4.49k | "uniform shader colorMap;" |
331 | 4.49k | "uniform half2 scale;" |
332 | 4.49k | "uniform half4 xSelect;" // Only one of RGBA will be 1, the rest are 0 |
333 | 4.49k | "uniform half4 ySelect;" |
334 | | |
335 | 4.49k | "half4 main(float2 coord) {" |
336 | 4.49k | "return sk_displacement(displMap, colorMap, coord, scale, xSelect, ySelect);" |
337 | 4.49k | "}"; |
338 | | |
339 | 4.49k | static const SkRuntimeEffect* sDisplacementEffect = |
340 | 4.49k | SkMakeRuntimeEffect(SkRuntimeEffect::MakeForShader, |
341 | 4.49k | kDisplacementShaderCode, |
342 | 4.49k | options); |
343 | 4.49k | return sDisplacementEffect; |
344 | 0 | } |
345 | 2.92k | case StableKey::kLighting: { |
346 | 2.92k | static constexpr char kLightingShaderCode[] = |
347 | 2.92k | "uniform shader normalMap;" |
348 | | |
349 | | // Packs surface depth, shininess, material type (0 == diffuse) and light type |
350 | | // (< 0 = distant, 0 = point, > 0 = spot) |
351 | 2.92k | "uniform half4 materialAndLightType;" |
352 | | |
353 | 2.92k | "uniform half4 lightPosAndSpotFalloff;" // (x,y,z) are lightPos, w is spot falloff |
354 | | // exponent |
355 | 2.92k | "uniform half4 lightDirAndSpotCutoff;" // (x,y,z) are lightDir, |
356 | | // w is spot cos(cutoffAngle) |
357 | 2.92k | "uniform half3 lightColor;" // Material's k has already been multiplied in |
358 | | |
359 | 2.92k | "half4 main(float2 coord) {" |
360 | 2.92k | "return sk_lighting(normalMap, coord," |
361 | 2.92k | /*depth=*/"materialAndLightType.x," |
362 | 2.92k | /*shininess=*/"materialAndLightType.y," |
363 | 2.92k | /*materialType=*/"materialAndLightType.z," |
364 | 2.92k | /*lightType=*/"materialAndLightType.w," |
365 | 2.92k | /*lightPos=*/"lightPosAndSpotFalloff.xyz," |
366 | 2.92k | /*spotFalloff=*/"lightPosAndSpotFalloff.w," |
367 | 2.92k | /*lightDir=*/"lightDirAndSpotCutoff.xyz," |
368 | 2.92k | /*cosCutoffAngle=*/"lightDirAndSpotCutoff.w," |
369 | 2.92k | "lightColor);" |
370 | 2.92k | "}"; |
371 | | |
372 | 2.92k | static const SkRuntimeEffect* sLightingEffect = |
373 | 2.92k | SkMakeRuntimeEffect(SkRuntimeEffect::MakeForShader, |
374 | 2.92k | kLightingShaderCode, |
375 | 2.92k | options); |
376 | 2.92k | return sLightingEffect; |
377 | 0 | } |
378 | 3.00k | case StableKey::kLinearMorphology: { |
379 | 3.00k | static constexpr char kLinearMorphologyShaderCode[] = |
380 | 3.00k | "uniform shader child;" |
381 | 3.00k | "uniform half2 offset;" |
382 | 3.00k | "uniform half flip;" // -1 converts the max() calls to min() |
383 | 3.00k | "uniform int radius;" |
384 | | |
385 | 3.00k | "half4 main(float2 coord) {" |
386 | 3.00k | "return sk_linear_morphology(child, coord, offset, flip, radius);" |
387 | 3.00k | "}"; |
388 | | |
389 | 3.00k | static const SkRuntimeEffect* sLinearMorphologyEffect = |
390 | 3.00k | SkMakeRuntimeEffect(SkRuntimeEffect::MakeForShader, |
391 | 3.00k | kLinearMorphologyShaderCode, |
392 | 3.00k | options); |
393 | 3.00k | return sLinearMorphologyEffect; |
394 | 0 | } |
395 | | |
396 | 223 | case StableKey::kMagnifier: { |
397 | 223 | static constexpr char kMagnifierShaderCode[] = |
398 | 223 | "uniform shader src;" |
399 | 223 | "uniform float4 lensBounds;" |
400 | 223 | "uniform float4 zoomXform;" |
401 | 223 | "uniform float2 invInset;" |
402 | | |
403 | 223 | "half4 main(float2 coord) {" |
404 | 223 | "return sk_magnifier(src, coord, lensBounds, zoomXform, invInset);" |
405 | 223 | "}"; |
406 | | |
407 | 223 | static const SkRuntimeEffect* sMagnifierEffect = |
408 | 223 | SkMakeRuntimeEffect(SkRuntimeEffect::MakeForShader, |
409 | 223 | kMagnifierShaderCode, |
410 | 223 | options); |
411 | 223 | return sMagnifierEffect; |
412 | 0 | } |
413 | 2.92k | case StableKey::kNormal: { |
414 | 2.92k | static constexpr char kNormalShaderCode[] = |
415 | 2.92k | "uniform shader alphaMap;" |
416 | 2.92k | "uniform float4 edgeBounds;" |
417 | 2.92k | "uniform half negSurfaceDepth;" |
418 | | |
419 | 2.92k | "half4 main(float2 coord) {" |
420 | 2.92k | "return sk_normal(alphaMap, coord, edgeBounds, negSurfaceDepth);" |
421 | 2.92k | "}"; |
422 | | |
423 | 2.92k | static const SkRuntimeEffect* sNormalEffect = |
424 | 2.92k | SkMakeRuntimeEffect(SkRuntimeEffect::MakeForShader, |
425 | 2.92k | kNormalShaderCode, |
426 | 2.92k | options); |
427 | 2.92k | return sNormalEffect; |
428 | 0 | } |
429 | 8.76k | case StableKey::kSparseMorphology: { |
430 | 8.76k | static constexpr char kSparseMorphologyShaderCode[] = |
431 | 8.76k | "uniform shader child;" |
432 | 8.76k | "uniform half2 offset;" |
433 | 8.76k | "uniform half flip;" |
434 | | |
435 | 8.76k | "half4 main(float2 coord) {" |
436 | 8.76k | "return sk_sparse_morphology(child, coord, offset, flip);" |
437 | 8.76k | "}"; |
438 | | |
439 | 8.76k | static const SkRuntimeEffect* sSparseMorphologyEffect = |
440 | 8.76k | SkMakeRuntimeEffect(SkRuntimeEffect::MakeForShader, |
441 | 8.76k | kSparseMorphologyShaderCode, |
442 | 8.76k | options); |
443 | 8.76k | return sSparseMorphologyEffect; |
444 | 0 | } |
445 | | |
446 | | // Blenders |
447 | 2.49k | case StableKey::kArithmetic: { |
448 | 2.49k | static constexpr char kArithmeticBlenderCode[] = |
449 | 2.49k | "uniform half4 k;" |
450 | 2.49k | "uniform half pmClamp;" |
451 | | |
452 | 2.49k | "half4 main(half4 src, half4 dst) {" |
453 | 2.49k | "return sk_arithmetic_blend(src, dst, k, pmClamp);" |
454 | 2.49k | "}"; |
455 | | |
456 | 2.49k | static const SkRuntimeEffect* sArithmeticEffect = |
457 | 2.49k | SkMakeRuntimeEffect(SkRuntimeEffect::MakeForBlender, |
458 | 2.49k | kArithmeticBlenderCode, |
459 | 2.49k | options); |
460 | 2.49k | return sArithmeticEffect; |
461 | 0 | } |
462 | | |
463 | | // Color Filters |
464 | 2.62k | case StableKey::kHighContrast: { |
465 | 2.62k | static constexpr char kHighContrastFilterCode[] = |
466 | 2.62k | "uniform half grayscale, invertStyle, contrast;" |
467 | 2.62k | "half4 main(half4 color) {" |
468 | 2.62k | "return half4(sk_high_contrast(color.rgb, grayscale, invertStyle, contrast)," |
469 | 2.62k | "color.a);" |
470 | 2.62k | "}"; |
471 | | |
472 | 2.62k | static const SkRuntimeEffect* sHighContrastEffect = |
473 | 2.62k | SkMakeRuntimeEffect(SkRuntimeEffect::MakeForColorFilter, |
474 | 2.62k | kHighContrastFilterCode, |
475 | 2.62k | options); |
476 | 2.62k | return sHighContrastEffect; |
477 | 0 | } |
478 | | |
479 | 6.81k | case StableKey::kLuma: { |
480 | 6.81k | static constexpr char kLumaFilterCode[] = |
481 | 6.81k | "half4 main(half4 color) {" |
482 | 6.81k | "return sk_luma(color.rgb);" |
483 | 6.81k | "}"; |
484 | | |
485 | 6.81k | static const SkRuntimeEffect* sLumaEffect = |
486 | 6.81k | SkMakeRuntimeEffect(SkRuntimeEffect::MakeForColorFilter, |
487 | 6.81k | kLumaFilterCode, |
488 | 6.81k | options); |
489 | 6.81k | return sLumaEffect; |
490 | 0 | } |
491 | | |
492 | 0 | case StableKey::kOverdraw: { |
493 | 0 | static constexpr char kOverdrawFilterCode[] = |
494 | 0 | "uniform half4 color0, color1, color2, color3, color4, color5;" |
495 | |
|
496 | 0 | "half4 main(half4 color) {" |
497 | 0 | "return sk_overdraw(color.a, color0, color1, color2, color3, color4, color5);" |
498 | 0 | "}"; |
499 | |
|
500 | 0 | static const SkRuntimeEffect* sOverdrawEffect = |
501 | 0 | SkMakeRuntimeEffect(SkRuntimeEffect::MakeForColorFilter, |
502 | 0 | kOverdrawFilterCode, |
503 | 0 | options); |
504 | 0 | return sOverdrawEffect; |
505 | 0 | } |
506 | 65.8k | } |
507 | | |
508 | 0 | SkUNREACHABLE; |
509 | 65.8k | } |
510 | | |
511 | | } // namespace SkKnownRuntimeEffects |