31 "const int kMaxUniformKernelSize = %d / 2;"
35 "const int kMaxLoopLimit = %d / 2;"
37 "uniform half4 offsetsAndKernel[kMaxUniformKernelSize];"
40 "uniform shader child;"
42 "half4 main(float2 coord) {"
43 "half4 sum = half4(0);"
44 "for (int i = 0; i < kMaxLoopLimit; ++i) {"
45 "half4 s = offsetsAndKernel[i];"
46 "sum += s.y * child.eval(coord + s.x*dir);"
47 "sum += s.w * child.eval(coord + s.z*dir);"
60 "const int kMaxUniformKernelSize = %d / 4;"
61 "const int kMaxUniformOffsetsSize = 2*kMaxUniformKernelSize;"
65 "const int kMaxLoopLimit = %d / 4;"
69 "uniform half4 kernel[kMaxUniformKernelSize];"
70 "uniform half4 offsets[kMaxUniformOffsetsSize];"
72 "uniform shader child;"
74 "half4 main(float2 coord) {"
75 "half4 sum = half4(0);"
77 "for (int i = 0; i < kMaxLoopLimit; ++i) {"
78 "half4 k = kernel[i];"
79 "half4 o = offsets[2*i];"
80 "sum += k.x * child.eval(coord + o.xy);"
81 "sum += k.y * child.eval(coord + o.zw);"
82 "o = offsets[2*i + 1];"
83 "sum += k.z * child.eval(coord + o.xy);"
84 "sum += k.w * child.eval(coord + o.zw);"
91enum class MatrixConvolutionImpl {
105 static const char* kHeaderAndBeginLoopSkSL =
107 "uniform int2 offset;"
108 "uniform half2 gainAndBias;"
109 "uniform int convolveAlpha;"
111 "uniform shader child;"
113 "half4 main(float2 coord) {"
114 "half4 sum = half4(0);"
115 "half origAlpha = 0;"
116 "int2 kernelPos = int2(0);"
117 "for (int i = 0; i < kMaxKernelSize; ++i) {"
118 "if (kernelPos.y >= size.y) { break; }";
121 static const char* kAccumulateAndIncrementSkSL =
122 "half4 c = child.eval(coord + half2(kernelPos) - half2(offset));"
123 "if (convolveAlpha == 0) {"
126 "if (kernelPos == offset) {"
133 "if (kernelPos.x >= size.x) {"
139 static const char* kCloseLoopAndFooterSkSL =
141 "half4 color = sum*gainAndBias.x + gainAndBias.y;"
142 "if (convolveAlpha == 0) {"
144 "color = half4(color.rgb*origAlpha, origAlpha);"
147 "color.a = saturate(color.a);"
150 "color.rgb = clamp(color.rgb, 0, color.a);"
154 static const auto makeTextureEffect = [](
int maxTextureKernelSize,
159 "uniform shader kernel;"
160 "uniform half2 innerGainAndBias;"
162 "half k = kernel.eval(half2(half(i) + 0.5, 0.5)).a;"
163 "k = k * innerGainAndBias.x + innerGainAndBias.y;"
166 maxTextureKernelSize,
167 kHeaderAndBeginLoopSkSL,
168 kAccumulateAndIncrementSkSL,
169 kCloseLoopAndFooterSkSL).c_str(),
174 case MatrixConvolutionImpl::kUniformBased: {
178 "uniform half4 kernel[kMaxKernelSize];"
180 "half4 k4 = kernel[i];"
181 "for (int j = 0; j < 4; ++j) {"
182 "if (kernelPos.y >= size.y) { break; }"
188 kHeaderAndBeginLoopSkSL,
189 kAccumulateAndIncrementSkSL,
190 kCloseLoopAndFooterSkSL).c_str(),
193 case MatrixConvolutionImpl::kTextureBasedSm:
195 case MatrixConvolutionImpl::kTextureBasedLg:
213 case StableKey::k1DBlur4: {
215 return s1DBlurEffect;
217 case StableKey::k1DBlur8: {
219 return s1DBlurEffect;
221 case StableKey::k1DBlur12: {
223 return s1DBlurEffect;
225 case StableKey::k1DBlur16: {
227 return s1DBlurEffect;
229 case StableKey::k1DBlur20: {
231 return s1DBlurEffect;
233 case StableKey::k1DBlur28: {
235 return s1DBlurEffect;
237 case StableKey::k2DBlur4: {
239 return s2DBlurEffect;
241 case StableKey::k2DBlur8: {
243 return s2DBlurEffect;
245 case StableKey::k2DBlur12: {
247 return s2DBlurEffect;
249 case StableKey::k2DBlur16: {
251 return s2DBlurEffect;
253 case StableKey::k2DBlur20: {
255 return s2DBlurEffect;
257 case StableKey::k2DBlur28: {
259 return s2DBlurEffect;
261 case StableKey::kBlend: {
262 static constexpr char kBlendShaderCode[] =
263 "uniform shader s, d;"
265 "half4 main(float2 xy) {"
266 "return b.eval(s.eval(xy), d.eval(xy));"
275 case StableKey::kDecal: {
276 static constexpr char kDecalShaderCode[] =
277 "uniform shader image;"
278 "uniform float4 decalBounds;"
280 "half4 main(float2 coord) {"
281 "half4 d = half4(decalBounds - coord.xyxy) * half4(-1, -1, 1, 1);"
282 "d = saturate(d + 0.5);"
283 "return (d.x*d.y*d.z*d.w) * image.eval(coord);"
292 case StableKey::kDisplacement: {
296 static constexpr char kDisplacementShaderCode[] =
297 "uniform shader displMap;"
298 "uniform shader colorMap;"
299 "uniform half2 scale;"
300 "uniform half4 xSelect;"
301 "uniform half4 ySelect;"
303 "half4 main(float2 coord) {"
304 "half4 displColor = unpremul(displMap.eval(coord));"
305 "half2 displ = half2(dot(displColor, xSelect), dot(displColor, ySelect));"
306 "displ = scale * (displ - 0.5);"
307 "return colorMap.eval(coord + displ);"
312 kDisplacementShaderCode,
314 return sDisplacementEffect;
316 case StableKey::kLighting: {
317 static constexpr char kLightingShaderCode[] =
318 "const half kConeAAThreshold = 0.016;"
319 "const half kConeScale = 1.0 / kConeAAThreshold;"
321 "uniform shader normalMap;"
325 "uniform half4 materialAndLightType;"
327 "uniform half4 lightPosAndSpotFalloff;"
329 "uniform half4 lightDirAndSpotCutoff;"
331 "uniform half3 lightColor;"
333 "half3 surface_to_light(half3 coord) {"
334 "if (materialAndLightType.w < 0) {"
335 "return lightDirAndSpotCutoff.xyz;"
338 "return normalize(lightPosAndSpotFalloff.xyz - coord);"
342 "half spotlight_scale(half3 surfaceToLight) {"
343 "half cosCutoffAngle = lightDirAndSpotCutoff.w;"
344 "half cosAngle = -dot(surfaceToLight, lightDirAndSpotCutoff.xyz);"
345 "if (cosAngle < cosCutoffAngle) {"
348 "half scale = pow(cosAngle, lightPosAndSpotFalloff.w);"
349 "if (cosAngle < cosCutoffAngle + kConeAAThreshold) {"
350 "return scale * (cosAngle - cosCutoffAngle) * kConeScale;"
356 "half4 compute_lighting(half3 normal, half3 surfaceToLight) {"
358 "half3 color = lightColor;"
360 "if (materialAndLightType.w > 0) {"
361 "color *= spotlight_scale(surfaceToLight);"
365 "if (materialAndLightType.z == 0) {"
366 "half coeff = dot(normal, surfaceToLight);"
367 "color = saturate(coeff * color);"
368 "return half4(color, 1.0);"
370 "half3 halfDir = normalize(surfaceToLight + half3(0, 0, 1));"
371 "half shininess = materialAndLightType.y;"
372 "half coeff = pow(dot(normal, halfDir), shininess);"
373 "color = saturate(coeff * color);"
374 "return half4(color, max(max(color.r, color.g), color.b));"
378 "half4 main(float2 coord) {"
379 "half4 normalAndA = normalMap.eval(coord);"
380 "half depth = materialAndLightType.x;"
381 "half3 surfaceToLight = surface_to_light(half3(half2(coord),"
382 "depth*normalAndA.a));"
383 "return compute_lighting(normalAndA.xyz, surfaceToLight);"
390 return sLightingEffect;
392 case StableKey::kLinearMorphology: {
393 static constexpr char kLinearMorphologyShaderCode[] =
395 "const int kMaxLinearRadius = 14;"
397 "uniform shader child;"
398 "uniform half2 offset;"
400 "uniform int radius;"
402 "half4 main(float2 coord) {"
403 "half4 aggregate = flip*child.eval(coord);"
404 "for (int i = 1; i <= kMaxLinearRadius; ++i) {"
405 "if (i > radius) break;"
406 "half2 delta = half(i) * offset;"
407 "aggregate = max(aggregate, max(flip*child.eval(coord + delta),"
408 "flip*child.eval(coord - delta)));"
410 "return flip*aggregate;"
415 kLinearMorphologyShaderCode,
417 return sLinearMorphologyEffect;
420 case StableKey::kMagnifier: {
421 static constexpr char kMagnifierShaderCode[] =
422 "uniform shader src;"
423 "uniform float4 lensBounds;"
424 "uniform float4 zoomXform;"
425 "uniform float2 invInset;"
427 "half4 main(float2 coord) {"
428 "float2 zoomCoord = zoomXform.xy + zoomXform.zw*coord;"
431 "float2 edgeInset = min(coord - lensBounds.xy, lensBounds.zw - coord) *"
441 "float weight = (edgeInset.x < 2.0 && edgeInset.y < 2.0)"
443 "? (2.0 - length(2.0 - edgeInset))"
446 ": min(edgeInset.x, edgeInset.y);"
450 "weight = saturate(weight);"
451 "return src.eval(mix(coord, zoomCoord, weight*weight));"
456 kMagnifierShaderCode,
458 return sMagnifierEffect;
461 case StableKey::kMatrixConvUniforms: {
463 make_matrix_conv_effect(MatrixConvolutionImpl::kUniformBased,
options);
464 return sMatrixConvUniformsEffect;
467 case StableKey::kMatrixConvTexSm: {
469 make_matrix_conv_effect(MatrixConvolutionImpl::kTextureBasedSm,
options);
470 return sMatrixConvTexSmEffect;
473 case StableKey::kMatrixConvTexLg: {
475 make_matrix_conv_effect(MatrixConvolutionImpl::kTextureBasedLg,
options);
476 return sMatrixConvTexMaxEffect;
480 static constexpr char kNormalShaderCode[] =
481 "uniform shader alphaMap;"
482 "uniform float4 edgeBounds;"
483 "uniform half negSurfaceDepth;"
485 "half3 normal(half3 alphaC0, half3 alphaC1, half3 alphaC2) {"
489 "const half3 kSobel = 0.25 * half3(1,2,1);"
490 "half3 alphaR0 = half3(alphaC0.x, alphaC1.x, alphaC2.x);"
491 "half3 alphaR2 = half3(alphaC0.z, alphaC1.z, alphaC2.z);"
492 "half nx = dot(kSobel, alphaC2) - dot(kSobel, alphaC0);"
493 "half ny = dot(kSobel, alphaR2) - dot(kSobel, alphaR0);"
494 "return normalize(half3(negSurfaceDepth * half2(nx, ny), 1));"
497 "half4 main(float2 coord) {"
498 "half3 alphaC0 = half3("
499 "alphaMap.eval(clamp(coord + float2(-1,-1), edgeBounds.LT, edgeBounds.RB)).a,"
500 "alphaMap.eval(clamp(coord + float2(-1, 0), edgeBounds.LT, edgeBounds.RB)).a,"
501 "alphaMap.eval(clamp(coord + float2(-1, 1), edgeBounds.LT, edgeBounds.RB)).a);"
502 "half3 alphaC1 = half3("
503 "alphaMap.eval(clamp(coord + float2( 0,-1), edgeBounds.LT, edgeBounds.RB)).a,"
504 "alphaMap.eval(clamp(coord + float2( 0, 0), edgeBounds.LT, edgeBounds.RB)).a,"
505 "alphaMap.eval(clamp(coord + float2( 0, 1), edgeBounds.LT, edgeBounds.RB)).a);"
506 "half3 alphaC2 = half3("
507 "alphaMap.eval(clamp(coord + float2( 1,-1), edgeBounds.LT, edgeBounds.RB)).a,"
508 "alphaMap.eval(clamp(coord + float2( 1, 0), edgeBounds.LT, edgeBounds.RB)).a,"
509 "alphaMap.eval(clamp(coord + float2( 1, 1), edgeBounds.LT, edgeBounds.RB)).a);"
511 "half mainAlpha = alphaC1.y;"
512 "return half4(normal(alphaC0, alphaC1, alphaC2), mainAlpha);"
519 return sNormalEffect;
521 case StableKey::kSparseMorphology: {
522 static constexpr char kSparseMorphologyShaderCode[] =
523 "uniform shader child;"
524 "uniform half2 offset;"
527 "half4 main(float2 coord) {"
528 "half4 aggregate = max(flip*child.eval(coord + offset),"
529 "flip*child.eval(coord - offset));"
530 "return flip*aggregate;"
535 kSparseMorphologyShaderCode,
537 return sSparseMorphologyEffect;
541 case StableKey::kArithmetic: {
542 static constexpr char kArithmeticBlenderCode[] =
544 "uniform half pmClamp;"
546 "half4 main(half4 src, half4 dst) {"
547 "half4 c = saturate(k.x * src * dst + k.y * src + k.z * dst + k.w);"
548 "c.rgb = min(c.rgb, max(c.a, pmClamp));"
554 kArithmeticBlenderCode,
556 return sArithmeticEffect;
561 static constexpr char kHighContrastFilterCode[] =
562 "uniform half grayscale, invertStyle, contrast;"
564 "half3 rgb_to_hsl(half3 c) {"
565 "half mx = max(max(c.r,c.g),c.b),"
566 "mn = min(min(c.r,c.g),c.b),"
569 "g_lt_b = c.g < c.b ? 6.0 : 0.0;"
573 "half h = (1/6.0) * (mx == mn" "? 0.0 :"
574 "c.r >= c.g && c.r >= c.b ? invd * (c.g - c.b) + g_lt_b :"
575 "c.g >= c.b" "? invd * (c.b - c.r) + 2.0"
576 ": invd * (c.r - c.g) + 4.0);"
580 ": d / (l > 0.5 ? 2.0 - sum : sum);"
581 "return half3(h,s,l);"
583 "half4 main(half4 inColor) {"
584 "half3 c = inColor.rgb;"
585 "if (grayscale == 1) {"
586 "c = dot(half3(0.2126, 0.7152, 0.0722), c).rrr;"
588 "if (invertStyle == 1) {"
590 "} else if (invertStyle == 2) {"
593 "c = $hsl_to_rgb(c);"
595 "c = mix(half3(0.5), c, contrast);"
596 "return half4(saturate(c), inColor.a);"
601 kHighContrastFilterCode,
603 return sHighContrastEffect;
606 case StableKey::kLerp: {
607 static constexpr char kLerpFilterCode[] =
608 "uniform colorFilter cf0;"
609 "uniform colorFilter cf1;"
610 "uniform half weight;"
612 "half4 main(half4 color) {"
613 "return mix(cf0.eval(color), cf1.eval(color), weight);"
623 case StableKey::kLuma: {
624 static constexpr char kLumaFilterCode[] =
625 "half4 main(half4 inColor) {"
626 "return saturate(dot(half3(0.2126, 0.7152, 0.0722), inColor.rgb)).000r;"
636 case StableKey::kOverdraw: {
637 static constexpr char kOverdrawFilterCode[] =
638 "uniform half4 color0, color1, color2, color3, color4, color5;"
640 "half4 main(half4 color) {"
641 "half alpha = 255.0 * color.a;"
642 "return alpha < 0.5 ? color0"
643 ": alpha < 1.5 ? color1"
644 ": alpha < 2.5 ? color2"
645 ": alpha < 3.5 ? color3"
646 ": alpha < 4.5 ? color4 : color5;"
653 return sOverdrawEffect;
SkRuntimeEffect * SkMakeRuntimeEffect(SkRuntimeEffect::Result(*make)(SkString, const SkRuntimeEffect::Options &), const char *sksl, SkRuntimeEffect::Options options=SkRuntimeEffect::Options{})
SK_API SkString SkStringPrintf(const char *format,...) SK_PRINTF_LIKE(1
Creates a new string and writes into it using a printf()-style format.
static void SetStableKey(SkRuntimeEffect::Options *options, uint32_t stableKey)
static Result MakeForColorFilter(SkString sksl, const Options &)
static Result MakeForBlender(SkString sksl, const Options &)
static Result MakeForShader(SkString sksl, const Options &)
@ kNormal
Default priority level.
static const FlSetting kHighContrast
static constexpr int kSmallKernelSize
static constexpr int kLargeKernelSize
static constexpr int kMaxUniformKernelSize
const SkRuntimeEffect * GetKnownRuntimeEffect(StableKey stableKey)
static constexpr int kMaxBlurSamples