1 /* 2 * Copyright (c) 2025 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16 #include <unordered_map> 17 #include <string> 18 19 static std::unordered_map<std::string, std::string> extModuleData = { 20 {"sksl_frag.sksl", R"( 21 // defines built-in interfaces supported by SkSL fragment shaders 22 23 // See "enum SpvBuiltIn_" in ./spirv.h 24 layout(builtin=15) in float4 sk_FragCoord; 25 layout(builtin=17) in bool sk_Clockwise; // Similar to gl_FrontFacing, but defined in device space. 26 layout(builtin=20) in uint sk_SampleMaskIn; 27 layout(builtin=10020) out uint sk_SampleMask; 28 29 layout(location=0,index=0,builtin=10001) out half4 sk_FragColor; 30 layout(builtin=10008) in half4 sk_LastFragColor; 31 layout(location=0,index=1,builtin=10012) out half4 sk_SecondaryFragColor; 32 )"}, 33 {"sksl_vert.sksl", R"( 34 // defines built-in interfaces supported by SkSL vertex shaders 35 36 out sk_PerVertex { 37 layout(builtin=0) float4 sk_Position; 38 layout(builtin=1) float sk_PointSize; 39 }; 40 41 layout(builtin=42) in int sk_VertexID; 42 layout(builtin=43) in int sk_InstanceID; 43 )"}, 44 {"sksl_gpu.sksl", R"( 45 // Not exposed in shared module 46 47 $pure $genIType mix($genIType x, $genIType y, $genBType a); 48 $pure $genBType mix($genBType x, $genBType y, $genBType a); 49 $pure $genType fma($genType a, $genType b, $genType c); 50 $pure $genHType fma($genHType a, $genHType b, $genHType c); 51 $genType frexp($genType x, out $genIType exp); 52 $genHType frexp($genHType x, out $genIType exp); 53 $pure $genType ldexp($genType x, in $genIType exp); 54 $pure $genHType ldexp($genHType x, in $genIType exp); 55 56 $pure uint packSnorm2x16(float2 v); 57 $pure uint packUnorm4x8(float4 v); 58 $pure uint packSnorm4x8(float4 v); 59 $pure float2 unpackSnorm2x16(uint p); 60 $pure float4 unpackUnorm4x8(uint p); 61 $pure float4 unpackSnorm4x8(uint p); 62 $pure uint packHalf2x16(float2 v); 63 $pure float2 unpackHalf2x16(uint v); 64 65 $pure $genIType bitCount($genIType value); 66 $pure $genIType bitCount($genUType value); 67 $pure $genIType findLSB($genIType value); 68 $pure $genIType findLSB($genUType value); 69 $pure $genIType findMSB($genIType value); 70 $pure $genIType findMSB($genUType value); 71 72 $pure half4 sample(sampler2D s, float2 P); 73 $pure half4 sample(sampler2D s, float3 P); 74 $pure half4 sample(sampler2D s, float3 P, float bias); 75 76 $pure half4 sample(samplerExternalOES s, float2 P); 77 $pure half4 sample(samplerExternalOES s, float2 P, float bias); 78 79 $pure half4 sample(sampler2DRect s, float2 P); 80 $pure half4 sample(sampler2DRect s, float3 P); 81 82 $pure half4 sampleLod(sampler2D s, float2 P, float lod); 83 $pure half4 sampleLod(sampler2D s, float3 P, float lod); 84 85 $pure half4 sampleGrad(sampler2D s, float2, float2 dPdx, float2 dPdy); 86 87 // Currently we do not support the generic types of loading subpassInput so we have some explicit 88 // versions that we currently use 89 $pure half4 subpassLoad(subpassInput subpass); 90 $pure half4 subpassLoad(subpassInputMS subpass, int sample); 91 92 /** Atomically loads the value from `a` and returns it. */ 93 $pure uint atomicLoad(atomicUint a); 94 95 /** Atomically stores the value of `value` to `a` */ 96 void atomicStore(atomicUint a, uint value); 97 98 /** 99 * Performs an atomic addition of `value` to the contents of `a` and returns the original contents 100 * of `a` from before the addition occurred. 101 */ 102 uint atomicAdd(atomicUint a, uint value); 103 104 // Definitions of functions implementing all of the SkBlendMode blends. 105 106 $pure half4 blend_clear(half4 src, half4 dst) { return half4(0); } 107 108 $pure half4 blend_src(half4 src, half4 dst) { return src; } 109 110 $pure half4 blend_dst(half4 src, half4 dst) { return dst; } 111 112 $pure half4 blend_src_over(half4 src, half4 dst) { return src + (1 - src.a)*dst; } 113 114 $pure half4 blend_dst_over(half4 src, half4 dst) { return (1 - dst.a)*src + dst; } 115 116 $pure half4 blend_src_in(half4 src, half4 dst) { return src*dst.a; } 117 118 $pure half4 blend_dst_in(half4 src, half4 dst) { return dst*src.a; } 119 120 $pure half4 blend_src_out(half4 src, half4 dst) { return (1 - dst.a)*src; } 121 122 $pure half4 blend_dst_out(half4 src, half4 dst) { return (1 - src.a)*dst; } 123 124 $pure half4 blend_src_atop(half4 src, half4 dst) { return dst.a*src + (1 - src.a)*dst; } 125 126 $pure half4 blend_dst_atop(half4 src, half4 dst) { return (1 - dst.a) * src + src.a*dst; } 127 128 $pure half4 blend_xor(half4 src, half4 dst) { return (1 - dst.a)*src + (1 - src.a)*dst; } 129 130 // This multi-purpose Porter-Duff blend function can perform any of the twelve blends above, 131 // when passed one of the following values for BlendOp: 132 // - Clear: 0*src + 0*dst = (0 + 0*dstA)*src + (0 + 0*srcA)*dst = (0, 0, 0, 0) 133 // - Src: 1*src + 0*dst = (1 + 0*dstA)*src + (0 + 0*srcA)*dst = (1, 0, 0, 0) 134 // - Dst: 0*src + 1*dst = (0 + 0*dstA)*src + (1 + 0*srcA)*dst = (0, 1, 0, 0) 135 // - SrcOver: 1*src + (1-srcA)*dst = (1 + 0*dstA)*src + (1 + -1*srcA)*dst = (1, 1, 0, -1) 136 // - DstOver: (1-dstA)*src + 1*dst = (1 + -1*dstA)*src + (1 + 0*srcA)*dst = (1, 1, -1, 0) 137 // - SrcIn: dstA*src + 0*dst = (0 + 1*dstA)*src + (0 + 0*srcA)*dst = (0, 0, 1, 0) 138 // - DstIn: 0*src + srcA*dst = (0 + 0*dstA)*src + (0 + 1*srcA)*dst = (0, 0, 0, 1) 139 // - SrcOut: (1-dstA)*src + 0*dst = (1 + -1*dstA)*src + (0 + 0*srcA)*dst = (1, 0, -1, 0) 140 // - DstOut: 0*src + (1-srcA)*dst = (0 + 0*dstA)*src + (1 + -1*srcA)*dst = (0, 1, 0, -1) 141 // - SrcATop: dstA*src + (1-srcA)*dst = (0 + 1*dstA)*src + (1 + -1*srcA)*dst = (0, 1, 1, -1) 142 // - DstATop: (1-dstA)*src + srcA*dst = (1 + -1*dstA)*src + (0 + 1*srcA)*dst = (1, 0, -1, 1) 143 // - Xor: (1-dstA)*src + (1-srcA)*dst = (1 + -1*dstA)*src + (1 + -1*srcA)*dst = (1, 1, -1, -1) 144 $pure half4 blend_porter_duff(half4 blendOp, half4 src, half4 dst) { 145 // The supported blend modes all have coefficients that are of the form (C + S*alpha), where 146 // alpha is the other color's alpha channel. C can be 0 or 1, S can be -1, 0, or 1. 147 half2 coeff = blendOp.xy + blendOp.zw * half2(dst.a, src.a); 148 return src * coeff.x + dst * coeff.y; 149 } 150 151 $pure half4 blend_plus(half4 src, half4 dst) { return min(src + dst, 1); } 152 153 $pure half4 blend_modulate(half4 src, half4 dst) { return src*dst; } 154 155 $pure half4 blend_screen(half4 src, half4 dst) { return src + (1 - src)*dst; } 156 157 $pure half $blend_overlay_component(half2 s, half2 d) { 158 return (2*d.x <= d.y) ? 2*s.x*d.x 159 : s.y*d.y - 2*(d.y - d.x)*(s.y - s.x); 160 } 161 162 $pure half4 blend_overlay(half4 src, half4 dst) { 163 half4 result = half4($blend_overlay_component(src.ra, dst.ra), 164 $blend_overlay_component(src.ga, dst.ga), 165 $blend_overlay_component(src.ba, dst.ba), 166 src.a + (1 - src.a)*dst.a); 167 result.rgb += dst.rgb*(1 - src.a) + src.rgb*(1 - dst.a); 168 return result; 169 } 170 171 $pure half4 blend_overlay(half flip, half4 a, half4 b) { 172 return blend_overlay(bool(flip) ? b : a, bool(flip) ? a : b); 173 } 174 175 $pure half4 blend_lighten(half4 src, half4 dst) { 176 half4 result = blend_src_over(src, dst); 177 result.rgb = max(result.rgb, (1 - dst.a)*src.rgb + dst.rgb); 178 return result; 179 } 180 181 $pure half4 blend_darken(half mode /* darken: 1, lighten: -1 */, half4 src, half4 dst) { 182 half4 a = blend_src_over(src, dst); 183 half3 b = (1 - dst.a) * src.rgb + dst.rgb; // DstOver.rgb 184 a.rgb = mode * min(a.rgb * mode, b.rgb * mode); 185 return a; 186 } 187 188 $pure half4 blend_darken(half4 src, half4 dst) { 189 return blend_darken(1, src, dst); 190 } 191 192 // A useful constant to check against when dividing a half-precision denominator. 193 // Denormal half floats (values less than this) will compare not-equal to 0 but can easily cause the 194 // division to overflow to infinity. Even regular values can overflow given the low maximum value. 195 // For instance, any value x > ~3.998 will overflow when divided by $kMinNormalHalf. This is a 196 // reasonable value even for wide gamut colors being input to these blend functions, but the 197 // most correct denominator check is to treat anything with `denom < x/F16_MAX` as division by 0. 198 const half $kMinNormalHalf = 1.0 / (1 << 14); 199 200 const half $kGuardedDivideEpsilon = sk_Caps.mustGuardDivisionEvenAfterExplicitZeroCheck 201 ? 0.00000001 202 : 0.0; 203 204 $pure inline half $guarded_divide(half n, half d) { 205 return n / (d + $kGuardedDivideEpsilon); 206 } 207 208 $pure inline half3 $guarded_divide(half3 n, half d) { 209 return n / (d + $kGuardedDivideEpsilon); 210 } 211 212 $pure half $color_dodge_component(half2 s, half2 d) { 213 // The following is a single flow of control implementation of: 214 // if (d.x == 0) { 215 // return s.x*(1 - d.y); 216 // } else { 217 // half delta = s.y - s.x; 218 // if (delta == 0) { 219 // return s.y*d.y + s.x*(1 - d.y) + d.x*(1 - s.y); 220 // } else { 221 // delta = min(d.y, $guarded_divide(d.x*s.y, delta)); 222 // return delta*s.y + s.x*(1 - d.y) + d.x*(1 - s.y); 223 // } 224 // } 225 // 226 // When d.x == 0, then dxScale forces delta to 0 and simplifying the return value to s.x*(1-d.y) 227 // When s.y-s.x == 0, the mix selects d.y and min(d.y, d.y) leaves delta = d.y 228 // Otherwise the mix selects the delta expression in the final else branch. 229 half dxScale = d.x == 0 ? 0 : 1; 230 half delta = dxScale * min(d.y, abs(s.y-s.x) >= $kMinNormalHalf 231 ? $guarded_divide(d.x*s.y, s.y-s.x) 232 : d.y); 233 return delta*s.y + s.x*(1 - d.y) + d.x*(1 - s.y); 234 } 235 236 $pure half4 blend_color_dodge(half4 src, half4 dst) { 237 return half4($color_dodge_component(src.ra, dst.ra), 238 $color_dodge_component(src.ga, dst.ga), 239 $color_dodge_component(src.ba, dst.ba), 240 src.a + (1 - src.a)*dst.a); 241 } 242 243 $pure half $color_burn_component(half2 s, half2 d) { 244 half dyTerm = d.y == d.x ? d.y : 0; 245 half delta = abs(s.x) >= $kMinNormalHalf 246 ? d.y - min(d.y, $guarded_divide((d.y - d.x)*s.y, s.x)) 247 : dyTerm; 248 return delta*s.y + s.x*(1 - d.y) + d.x*(1 - s.y); 249 } 250 251 $pure half4 blend_color_burn(half4 src, half4 dst) { 252 return half4($color_burn_component(src.ra, dst.ra), 253 $color_burn_component(src.ga, dst.ga), 254 $color_burn_component(src.ba, dst.ba), 255 src.a + (1 - src.a)*dst.a); 256 } 257 258 $pure half4 blend_hard_light(half4 src, half4 dst) { 259 return blend_overlay(dst, src); 260 } 261 262 $pure half $soft_light_component(half2 s, half2 d) { 263 if (2*s.x <= s.y) { 264 return $guarded_divide(d.x*d.x*(s.y - 2*s.x), d.y) + (1 - d.y)*s.x + d.x*(-s.y + 2*s.x + 1); 265 } else if (4.0 * d.x <= d.y) { 266 half DSqd = d.x*d.x; 267 half DCub = DSqd*d.x; 268 half DaSqd = d.y*d.y; 269 half DaCub = DaSqd*d.y; 270 return $guarded_divide(DaSqd*(s.x - d.x*(3*s.y - 6*s.x - 1)) + 12*d.y*DSqd*(s.y - 2*s.x) 271 - 16*DCub * (s.y - 2*s.x) - DaCub*s.x, DaSqd); 272 } else { 273 return d.x*(s.y - 2*s.x + 1) + s.x - sqrt(d.y*d.x)*(s.y - 2*s.x) - d.y*s.x; 274 } 275 } 276 277 $pure half4 blend_soft_light(half4 src, half4 dst) { 278 return (dst.a == 0) ? src : half4($soft_light_component(src.ra, dst.ra), 279 $soft_light_component(src.ga, dst.ga), 280 $soft_light_component(src.ba, dst.ba), 281 src.a + (1 - src.a)*dst.a); 282 } 283 284 $pure half4 blend_difference(half4 src, half4 dst) { 285 return half4(src.rgb + dst.rgb - 2*min(src.rgb*dst.a, dst.rgb*src.a), 286 src.a + (1 - src.a)*dst.a); 287 } 288 289 $pure half4 blend_exclusion(half4 src, half4 dst) { 290 return half4(dst.rgb + src.rgb - 2*dst.rgb*src.rgb, src.a + (1 - src.a)*dst.a); 291 } 292 293 $pure half4 blend_multiply(half4 src, half4 dst) { 294 return half4((1 - src.a)*dst.rgb + (1 - dst.a)*src.rgb + src.rgb*dst.rgb, 295 src.a + (1 - src.a)*dst.a); 296 } 297 298 $pure half $blend_color_luminance(half3 color) { return dot(half3(0.3, 0.59, 0.11), color); } 299 300 $pure half3 $blend_set_color_luminance(half3 hueSatColor, half alpha, half3 lumColor) { 301 half lum = $blend_color_luminance(lumColor); 302 half3 result = lum - $blend_color_luminance(hueSatColor) + hueSatColor; 303 half minComp = min(min(result.r, result.g), result.b); 304 half maxComp = max(max(result.r, result.g), result.b); 305 if (minComp < 0 && lum != minComp) { 306 result = lum + (result - lum) * $guarded_divide(lum, (lum - minComp) + $kMinNormalHalf); 307 } 308 if (maxComp > alpha && maxComp != lum) { 309 result = lum + 310 $guarded_divide((result - lum) * (alpha - lum), (maxComp - lum) + $kMinNormalHalf); 311 } 312 return result; 313 } 314 315 $pure half $blend_color_saturation(half3 color) { 316 return max(max(color.r, color.g), color.b) - min(min(color.r, color.g), color.b); 317 } 318 319 $pure half3 $blend_set_color_saturation(half3 color, half3 satColor) { 320 half mn = min(min(color.r, color.g), color.b); 321 half mx = max(max(color.r, color.g), color.b); 322 323 return (mx > mn) ? ((color - mn) * $blend_color_saturation(satColor)) / (mx - mn) 324 : half3(0); 325 } 326 327 $pure half4 blend_hslc(half2 flipSat, half4 src, half4 dst) { 328 half alpha = dst.a * src.a; 329 half3 sda = src.rgb * dst.a; 330 half3 dsa = dst.rgb * src.a; 331 half3 l = bool(flipSat.x) ? dsa : sda; 332 half3 r = bool(flipSat.x) ? sda : dsa; 333 if (bool(flipSat.y)) { 334 l = $blend_set_color_saturation(l, r); 335 r = dsa; 336 } 337 return half4($blend_set_color_luminance(l, alpha, r) + dst.rgb - dsa + src.rgb - sda, 338 src.a + dst.a - alpha); 339 } 340 341 $pure half4 blend_hue(half4 src, half4 dst) { 342 return blend_hslc(half2(0, 1), src, dst); 343 } 344 345 $pure half4 blend_saturation(half4 src, half4 dst) { 346 return blend_hslc(half2(1), src, dst); 347 } 348 349 $pure half4 blend_color(half4 src, half4 dst) { 350 return blend_hslc(half2(0), src, dst); 351 } 352 353 $pure half4 blend_luminosity(half4 src, half4 dst) { 354 return blend_hslc(half2(1, 0), src, dst); 355 } 356 357 $pure float2 proj(float3 p) { return p.xy / p.z; } 358 359 // Implement cross() as a determinant to communicate our intent more clearly to the compiler. 360 // NOTE: Due to precision issues, it might be the case that cross(a, a) != 0. 361 $pure float cross_length_2d(float2 a, float2 b) { 362 return determinant(float2x2(a, b)); 363 } 364 365 $pure half cross_length_2d(half2 a, half2 b) { 366 return determinant(half2x2(a, b)); 367 } 368 369 $pure float2 perp(float2 v) { 370 return float2(-v.y, v.x); 371 } 372 373 $pure half2 perp(half2 v) { 374 return half2(-v.y, v.x); 375 } 376 377 // Returns a bias given a scale factor, such that 'scale * (dist + bias)' converts the distance to 378 // a per-pixel coverage value, automatically widening the visible coverage ramp for subpixel 379 // dimensions. The 'scale' must already be equal to the narrowest dimension of the shape and clamped 380 // to [0, 1.0]. 381 $pure float coverage_bias(float scale) { 382 return 1.0 - 0.5 * scale; 383 } 384 385 // add the support of textureSize 386 int2 textureSize(sampler2D x, int y); 387 388 // add the support of textureGather 389 half4 sampleGather(sampler2D s, float2 p); 390 half4 sampleGather(sampler2D s, float2 p, int comp); 391 392 // add the support of nonuniformEXT 393 uint nonuniformEXT(uint x); 394 )"}, 395 {"sksl_public.sksl", R"( 396 // SkSL intrinsics that are not part of GLSL 397 398 // Color space transformation, between the working (destination) space and fixed (known) spaces: 399 $pure half3 toLinearSrgb(half3 color); 400 $pure half3 fromLinearSrgb(half3 color); 401 402 // SkSL intrinsics that reflect Skia's C++ object model: 403 half4 $eval(float2 coords, shader s); 404 half4 $eval(half4 color, colorFilter f); 405 half4 $eval(half4 src, half4 dst, blender b); 406 )"}, 407 {"sksl_rt_shader.sksl", R"( 408 layout(builtin=15) float4 sk_FragCoord; 409 410 //--- Luma ------------------------------------------------------------------------ 411 412 half4 sk_luma(half3 color) { 413 return saturate(dot(half3(0.2126, 0.7152, 0.0722), color)).000r; 414 } 415 416 //--- Decal ------------------------------------------------------------------------ 417 418 half4 sk_decal(shader image, float2 coord, float4 decalBounds) { 419 half4 d = half4(decalBounds - coord.xyxy) * half4(-1, -1, 1, 1); 420 d = saturate(d + 0.5); 421 return (d.x * d.y * d.z * d.w) * image.eval(coord); 422 } 423 424 //--- Displacement ----------------------------------------------------------------- 425 426 half4 sk_displacement(shader displMap, 427 shader colorMap, 428 float2 coord, 429 half2 scale, 430 half4 xSelect, // Only one of RGBA will be 1, the rest are 0 431 half4 ySelect) { 432 half4 displColor = unpremul(displMap.eval(coord)); 433 half2 displ = half2(dot(displColor, xSelect), dot(displColor, ySelect)); 434 displ = scale * (displ - 0.5); 435 return colorMap.eval(coord + displ); 436 } 437 438 //--- Magnifier -------------------------------------------------------------------- 439 440 half4 sk_magnifier(shader src, float2 coord, float4 lensBounds, float4 zoomXform, 441 float2 invInset) { 442 float2 zoomCoord = zoomXform.xy + zoomXform.zw*coord; 443 // edgeInset is the smallest distance to the lens bounds edges, in units of "insets". 444 float2 edgeInset = min(coord - lensBounds.xy, lensBounds.zw - coord) * invInset; 445 446 // The equations for 'weight' ensure that it is 0 along the outside of 447 // lensBounds so it seams with any un-zoomed, un-filtered content. The zoomed 448 // content fills a rounded rectangle that is 1 "inset" in from lensBounds with 449 // circular corners with radii equal to the inset distance. Outside of this 450 // region, there is a non-linear weighting to compress the un-zoomed content 451 // to the zoomed content. The critical zone about each corner is limited 452 // to 2x"inset" square. 453 float weight = all(lessThan(edgeInset, float2(2.0))) 454 // Circular distortion weighted by distance to inset corner 455 ? (2.0 - length(2.0 - edgeInset)) 456 // Linear zoom, or single-axis compression outside of the inset 457 // area (if delta < 1) 458 : min(edgeInset.x, edgeInset.y); 459 460 // Saturate before squaring so that negative weights are clamped to 0 461 // before squaring 462 weight = saturate(weight); 463 return src.eval(mix(coord, zoomCoord, weight*weight)); 464 } 465 466 //--- High Contrast ---------------------------------------------------------------- 467 468 $pure half3 $high_contrast_rgb_to_hsl(half3 c) { 469 half mx = max(max(c.r,c.g),c.b), 470 mn = min(min(c.r,c.g),c.b), 471 d = mx-mn, 472 invd = 1.0 / d, 473 g_lt_b = c.g < c.b ? 6.0 : 0.0; 474 475 // We'd prefer to write these tests like `mx == c.r`, but on some GPUs, max(x,y) is 476 // not always equal to either x or y. So we use long form, c.r >= c.g && c.r >= c.b. 477 half h = (1/6.0) * (mx == mn ? 0.0 : 478 /*mx==c.r*/ c.r >= c.g && c.r >= c.b ? invd * (c.g - c.b) + g_lt_b : 479 /*mx==c.g*/ c.g >= c.b ? invd * (c.b - c.r) + 2.0 480 /*mx==c.b*/ : invd * (c.r - c.g) + 4.0); 481 half sum = mx+mn, 482 l = sum * 0.5, 483 s = mx == mn ? 0.0 484 : d / (l > 0.5 ? 2.0 - sum : sum); 485 return half3(h,s,l); 486 } 487 488 half3 sk_high_contrast(half3 color, half grayscale, half invertStyle, half contrast) { 489 if (grayscale == 1) { 490 color = dot(half3(0.2126, 0.7152, 0.0722), color).rrr; 491 } 492 if (invertStyle == 1) { // brightness 493 color = 1.0 - color; 494 } else if (invertStyle == 2) { // lightness 495 color = $high_contrast_rgb_to_hsl(color); 496 color.b = 1 - color.b; 497 color = $hsl_to_rgb(color); 498 } 499 return saturate(mix(half3(0.5), color, contrast)); 500 } 501 502 //--- Normal ----------------------------------------------------------------------- 503 504 $pure half3 $normal_filter(half3 alphaC0, half3 alphaC1, half3 alphaC2, half negSurfaceDepth) { 505 // The right column (or bottom row) terms of the Sobel filter. The left/top is just the 506 // negative, and the middle row/column is all 0s so those instructions are skipped. 507 const half3 kSobel = 0.25 * half3(1,2,1); 508 half3 alphaR0 = half3(alphaC0.x, alphaC1.x, alphaC2.x); 509 half3 alphaR2 = half3(alphaC0.z, alphaC1.z, alphaC2.z); 510 half nx = dot(kSobel, alphaC2) - dot(kSobel, alphaC0); 511 half ny = dot(kSobel, alphaR2) - dot(kSobel, alphaR0); 512 return normalize(half3(negSurfaceDepth * half2(nx, ny), 1)); 513 } 514 515 half4 sk_normal(shader alphaMap, float2 coord, float4 edgeBounds, half negSurfaceDepth) { 516 half3 alphaC0 = half3( 517 alphaMap.eval(clamp(coord + float2(-1,-1), edgeBounds.LT, edgeBounds.RB)).a, 518 alphaMap.eval(clamp(coord + float2(-1, 0), edgeBounds.LT, edgeBounds.RB)).a, 519 alphaMap.eval(clamp(coord + float2(-1, 1), edgeBounds.LT, edgeBounds.RB)).a); 520 half3 alphaC1 = half3( 521 alphaMap.eval(clamp(coord + float2( 0,-1), edgeBounds.LT, edgeBounds.RB)).a, 522 alphaMap.eval(clamp(coord + float2( 0, 0), edgeBounds.LT, edgeBounds.RB)).a, 523 alphaMap.eval(clamp(coord + float2( 0, 1), edgeBounds.LT, edgeBounds.RB)).a); 524 half3 alphaC2 = half3( 525 alphaMap.eval(clamp(coord + float2( 1,-1), edgeBounds.LT, edgeBounds.RB)).a, 526 alphaMap.eval(clamp(coord + float2( 1, 0), edgeBounds.LT, edgeBounds.RB)).a, 527 alphaMap.eval(clamp(coord + float2( 1, 1), edgeBounds.LT, edgeBounds.RB)).a); 528 529 half mainAlpha = alphaC1.y; // offset = (0,0) 530 return half4($normal_filter(alphaC0, alphaC1, alphaC2, negSurfaceDepth), mainAlpha); 531 } 532 533 //--- Lighting --------------------------------------------------------------------- 534 535 $pure half3 $surface_to_light(half lightType, half3 lightPos, half3 lightDir, half3 coord) { 536 // Spot (> 0) and point (== 0) have the same equation 537 return lightType >= 0 ? normalize(lightPos - coord) 538 : lightDir; 539 } 540 541 $pure half $spotlight_scale(half3 lightDir, half3 surfaceToLight, half cosCutoffAngle, 542 half spotFalloff) { 543 const half kConeAAThreshold = 0.016; 544 const half kConeScale = 1.0 / kConeAAThreshold; 545 546 half cosAngle = -dot(surfaceToLight, lightDir); 547 if (cosAngle < cosCutoffAngle) { 548 return 0.0; 549 } else { 550 half scale = pow(cosAngle, spotFalloff); 551 return (cosAngle < cosCutoffAngle + kConeAAThreshold) 552 ? scale * (cosAngle - cosCutoffAngle) * kConeScale 553 : scale; 554 } 555 } 556 557 $pure half4 $compute_lighting(half3 color, half shininess, half materialType, half lightType, 558 half3 normal, half3 lightDir, half3 surfaceToLight, 559 half cosCutoffAngle, half spotFalloff) { 560 // Point and distant light color contributions are constant, but 561 // spotlights fade based on the angle away from its direction. 562 if (lightType > 0) { 563 color *= $spotlight_scale(lightDir, surfaceToLight, cosCutoffAngle, spotFalloff); 564 } 565 566 // Diffuse and specular reflections scale the light's color differently 567 if (materialType == 0) { 568 half coeff = dot(normal, surfaceToLight); 569 color = saturate(coeff * color); 570 return half4(color, 1.0); 571 } else { 572 half3 halfDir = normalize(surfaceToLight + half3(0, 0, 1)); 573 half coeff = pow(dot(normal, halfDir), shininess); 574 color = saturate(coeff * color); 575 return half4(color, max(max(color.r, color.g), color.b)); 576 } 577 } 578 579 half4 sk_lighting(shader normalMap, float2 coord, 580 half depth, half shininess, half materialType, half lightType, 581 half3 lightPos, half spotFalloff, 582 half3 lightDir, half cosCutoffAngle, 583 half3 lightColor) { 584 half4 normalAndA = normalMap.eval(coord); 585 half3 surfaceToLight = $surface_to_light(lightType, lightPos, lightDir, 586 half3(coord, depth * normalAndA.a)); 587 return $compute_lighting(lightColor, shininess, materialType, lightType, normalAndA.xyz, 588 lightDir, surfaceToLight, cosCutoffAngle, spotFalloff); 589 } 590 591 //--- Arithmetic Blend ------------------------------------------------------------- 592 593 half4 sk_arithmetic_blend(half4 src, half4 dst, half4 k, half pmClamp) { 594 half4 color = saturate(k.x * src * dst + k.y * src + k.z * dst + k.w); 595 color.rgb = min(color.rgb, max(color.a, pmClamp)); 596 return color; 597 } 598 599 //--- Sparse Morphology ------------------------------------------------------------ 600 601 half4 sk_sparse_morphology(shader child, float2 coord, half2 offset, half flip) { 602 half4 aggregate = max(flip * child.eval(coord + offset), 603 flip * child.eval(coord - offset)); 604 return flip * aggregate; 605 } 606 607 //--- Linear Morphology ------------------------------------------------------------ 608 609 half4 sk_linear_morphology(shader child, float2 coord, half2 offset, half flip, int radius) { 610 611 // KEEP IN SYNC WITH CONSTANT IN `SkMorphologyImageFilter.cpp` 612 const int kMaxLinearRadius = 14; 613 614 half4 aggregate = flip * child.eval(coord); // case 0 only needs a single sample 615 half2 delta = offset; 616 for (int i = 1; i <= kMaxLinearRadius; ++i) { 617 if (i > radius) break; 618 aggregate = max(aggregate, max(flip * child.eval(coord + delta), 619 flip * child.eval(coord - delta))); 620 delta += offset; 621 } 622 return flip * aggregate; 623 } 624 625 //--- Overdraw --------------------------------------------------------------------- 626 627 half4 sk_overdraw(half alpha, half4 color0, half4 color1, half4 color2, 628 half4 color3, half4 color4, half4 color5) { 629 return alpha < (0.5 / 255.) ? color0 630 : alpha < (1.5 / 255.) ? color1 631 : alpha < (2.5 / 255.) ? color2 632 : alpha < (3.5 / 255.) ? color3 633 : alpha < (4.5 / 255.) ? color4 634 : color5; 635 } 636 )"}, 637 {"sksl_shared.sksl", R"( 638 // Intrinsics that are available to public SkSL (SkRuntimeEffect) 639 640 // See "The OpenGL ES Shading Language, Section 8" 641 642 // 8.1 : Angle and Trigonometry Functions 643 $pure $genType radians($genType degrees); 644 $pure $genHType radians($genHType degrees); 645 $pure $genType degrees($genType radians); 646 $pure $genHType degrees($genHType radians); 647 648 $pure $genType sin($genType angle); 649 $pure $genHType sin($genHType angle); 650 $pure $genType cos($genType angle); 651 $pure $genHType cos($genHType angle); 652 $pure $genType tan($genType angle); 653 $pure $genHType tan($genHType angle); 654 655 $pure $genType asin($genType x); 656 $pure $genHType asin($genHType x); 657 $pure $genType acos($genType x); 658 $pure $genHType acos($genHType x); 659 $pure $genType atan($genType y, $genType x); 660 $pure $genHType atan($genHType y, $genHType x); 661 $pure $genType atan($genType y_over_x); 662 $pure $genHType atan($genHType y_over_x); 663 664 // 8.1 : Angle and Trigonometry Functions (GLSL ES 3.0) 665 $pure $es3 $genType sinh($genType x); 666 $pure $es3 $genHType sinh($genHType x); 667 $pure $es3 $genType cosh($genType x); 668 $pure $es3 $genHType cosh($genHType x); 669 $pure $es3 $genType tanh($genType x); 670 $pure $es3 $genHType tanh($genHType x); 671 $pure $es3 $genType asinh($genType x); 672 $pure $es3 $genHType asinh($genHType x); 673 $pure $es3 $genType acosh($genType x); 674 $pure $es3 $genHType acosh($genHType x); 675 $pure $es3 $genType atanh($genType x); 676 $pure $es3 $genHType atanh($genHType x); 677 678 // 8.2 : Exponential Functions 679 $pure $genType pow($genType x, $genType y); 680 $pure $genHType pow($genHType x, $genHType y); 681 $pure $genType exp($genType x); 682 $pure $genHType exp($genHType x); 683 $pure $genType log($genType x); 684 $pure $genHType log($genHType x); 685 $pure $genType exp2($genType x); 686 $pure $genHType exp2($genHType x); 687 $pure $genType log2($genType x); 688 $pure $genHType log2($genHType x); 689 690 $pure $genType sqrt($genType x); 691 $pure $genHType sqrt($genHType x); 692 $pure $genType inversesqrt($genType x); 693 $pure $genHType inversesqrt($genHType x); 694 695 // 8.3 : Common Functions 696 $pure $genType abs($genType x); 697 $pure $genHType abs($genHType x); 698 $pure $genType sign($genType x); 699 $pure $genHType sign($genHType x); 700 $pure $genType floor($genType x); 701 $pure $genHType floor($genHType x); 702 $pure $genType ceil($genType x); 703 $pure $genHType ceil($genHType x); 704 $pure $genType fract($genType x); 705 $pure $genHType fract($genHType x); 706 $pure $genType mod($genType x, float y); 707 $pure $genType mod($genType x, $genType y); 708 $pure $genHType mod($genHType x, half y); 709 $pure $genHType mod($genHType x, $genHType y); 710 711 $pure $genType min($genType x, $genType y); 712 $pure $genType min($genType x, float y); 713 $pure $genHType min($genHType x, $genHType y); 714 $pure $genHType min($genHType x, half y); 715 $pure $genType max($genType x, $genType y); 716 $pure $genType max($genType x, float y); 717 $pure $genHType max($genHType x, $genHType y); 718 $pure $genHType max($genHType x, half y); 719 $pure $genType clamp($genType x, $genType minVal, $genType maxVal); 720 $pure $genType clamp($genType x, float minVal, float maxVal); 721 $pure $genHType clamp($genHType x, $genHType minVal, $genHType maxVal); 722 $pure $genHType clamp($genHType x, half minVal, half maxVal); 723 $pure $genType saturate($genType x); // SkSL extension 724 $pure $genHType saturate($genHType x); // SkSL extension 725 $pure $genType mix($genType x, $genType y, $genType a); 726 $pure $genType mix($genType x, $genType y, float a); 727 $pure $genHType mix($genHType x, $genHType y, $genHType a); 728 $pure $genHType mix($genHType x, $genHType y, half a); 729 $pure $genType step($genType edge, $genType x); 730 $pure $genType step(float edge, $genType x); 731 $pure $genHType step($genHType edge, $genHType x); 732 $pure $genHType step(half edge, $genHType x); 733 $pure $genType smoothstep($genType edge0, $genType edge1, $genType x); 734 $pure $genType smoothstep(float edge0, float edge1, $genType x); 735 $pure $genHType smoothstep($genHType edge0, $genHType edge1, $genHType x); 736 $pure $genHType smoothstep(half edge0, half edge1, $genHType x); 737 738 // 8.3 : Common Functions (GLSL ES 3.0) 739 $pure $es3 $genIType abs($genIType x); 740 $pure $es3 $genIType sign($genIType x); 741 $pure $es3 $genIType floatBitsToInt ($genType value); 742 $pure $es3 $genUType floatBitsToUint($genType value); 743 $pure $es3 $genType intBitsToFloat ($genIType value); 744 $pure $es3 $genType uintBitsToFloat($genUType value); 745 $pure $es3 $genType trunc($genType x); 746 $pure $es3 $genHType trunc($genHType x); 747 $pure $es3 $genType round($genType x); 748 $pure $es3 $genHType round($genHType x); 749 $pure $es3 $genType roundEven($genType x); 750 $pure $es3 $genHType roundEven($genHType x); 751 $pure $es3 $genIType min($genIType x, $genIType y); 752 $pure $es3 $genIType min($genIType x, int y); 753 $pure $es3 $genUType min($genUType x, $genUType y); 754 $pure $es3 $genUType min($genUType x, uint y); 755 $pure $es3 $genIType max($genIType x, $genIType y); 756 $pure $es3 $genIType max($genIType x, int y); 757 $pure $es3 $genUType max($genUType x, $genUType y); 758 $pure $es3 $genUType max($genUType x, uint y); 759 $pure $es3 $genIType clamp($genIType x, $genIType minVal, $genIType maxVal); 760 $pure $es3 $genIType clamp($genIType x, int minVal, int maxVal); 761 $pure $es3 $genUType clamp($genUType x, $genUType minVal, $genUType maxVal); 762 $pure $es3 $genUType clamp($genUType x, uint minVal, uint maxVal); 763 $pure $es3 $genType mix($genType x, $genType y, $genBType a); 764 $pure $es3 $genHType mix($genHType x, $genHType y, $genBType a); 765 766 // 8.3 : Common Functions (GLSL ES 3.0) -- cannot be used in constant-expressions 767 $pure $es3 $genBType isnan($genType x); 768 $pure $es3 $genBType isnan($genHType x); 769 $pure $es3 $genBType isinf($genType x); 770 $pure $es3 $genBType isinf($genHType x); 771 $es3 $genType modf($genType x, out $genType i); 772 $es3 $genHType modf($genHType x, out $genHType i); 773 774 // 8.4 : Floating-Point Pack and Unpack Functions (GLSL ES 3.0) 775 $pure $es3 uint packUnorm2x16(float2 v); 776 $pure $es3 float2 unpackUnorm2x16(uint p); 777 778 // 8.5 : Geometric Functions 779 $pure float length($genType x); 780 $pure half length($genHType x); 781 $pure float distance($genType p0, $genType p1); 782 $pure half distance($genHType p0, $genHType p1); 783 $pure float dot($genType x, $genType y); 784 $pure half dot($genHType x, $genHType y); 785 $pure float3 cross(float3 x, float3 y); 786 $pure half3 cross(half3 x, half3 y); 787 $pure $genType normalize($genType x); 788 $pure $genHType normalize($genHType x); 789 $pure $genType faceforward($genType N, $genType I, $genType Nref); 790 $pure $genHType faceforward($genHType N, $genHType I, $genHType Nref); 791 $pure $genType reflect($genType I, $genType N); 792 $pure $genHType reflect($genHType I, $genHType N); 793 $pure $genType refract($genType I, $genType N, float eta); 794 $pure $genHType refract($genHType I, $genHType N, half eta); 795 796 // 8.6 : Matrix Functions 797 $pure $squareMat matrixCompMult($squareMat x, $squareMat y); 798 $pure $squareHMat matrixCompMult($squareHMat x, $squareHMat y); 799 $pure $es3 $mat matrixCompMult($mat x, $mat y); 800 $pure $es3 $hmat matrixCompMult($hmat x, $hmat y); 801 802 // 8.6 : Matrix Functions (GLSL 1.4, poly-filled by SkSL as needed) 803 $pure $squareMat inverse($squareMat m); 804 $pure $squareHMat inverse($squareHMat m); 805 806 // 8.6 : Matrix Functions (GLSL ES 3.0) 807 $pure $es3 float determinant($squareMat m); 808 $pure $es3 half determinant($squareHMat m); 809 $pure $es3 $squareMat transpose($squareMat m); 810 $pure $es3 $squareHMat transpose($squareHMat m); 811 $pure $es3 float2x3 transpose(float3x2 m); 812 $pure $es3 half2x3 transpose(half3x2 m); 813 $pure $es3 float2x4 transpose(float4x2 m); 814 $pure $es3 half2x4 transpose(half4x2 m); 815 $pure $es3 float3x2 transpose(float2x3 m); 816 $pure $es3 half3x2 transpose(half2x3 m); 817 $pure $es3 float3x4 transpose(float4x3 m); 818 $pure $es3 half3x4 transpose(half4x3 m); 819 $pure $es3 float4x2 transpose(float2x4 m); 820 $pure $es3 half4x2 transpose(half2x4 m); 821 $pure $es3 float4x3 transpose(float3x4 m); 822 $pure $es3 half4x3 transpose(half3x4 m); 823 $pure $es3 $squareMat outerProduct($vec c, $vec r); 824 $pure $es3 $squareHMat outerProduct($hvec c, $hvec r); 825 $pure $es3 float2x3 outerProduct(float3 c, float2 r); 826 $pure $es3 half2x3 outerProduct(half3 c, half2 r); 827 $pure $es3 float3x2 outerProduct(float2 c, float3 r); 828 $pure $es3 half3x2 outerProduct(half2 c, half3 r); 829 $pure $es3 float2x4 outerProduct(float4 c, float2 r); 830 $pure $es3 half2x4 outerProduct(half4 c, half2 r); 831 $pure $es3 float4x2 outerProduct(float2 c, float4 r); 832 $pure $es3 half4x2 outerProduct(half2 c, half4 r); 833 $pure $es3 float3x4 outerProduct(float4 c, float3 r); 834 $pure $es3 half3x4 outerProduct(half4 c, half3 r); 835 $pure $es3 float4x3 outerProduct(float3 c, float4 r); 836 $pure $es3 half4x3 outerProduct(half3 c, half4 r); 837 838 // 8.7 : Vector Relational Functions 839 $pure $bvec lessThan($vec x, $vec y); 840 $pure $bvec lessThan($hvec x, $hvec y); 841 $pure $bvec lessThan($ivec x, $ivec y); 842 $pure $bvec lessThan($svec x, $svec y); 843 $pure $bvec lessThanEqual($vec x, $vec y); 844 $pure $bvec lessThanEqual($hvec x, $hvec y); 845 $pure $bvec lessThanEqual($ivec x, $ivec y); 846 $pure $bvec lessThanEqual($svec x, $svec y); 847 $pure $bvec greaterThan($vec x, $vec y); 848 $pure $bvec greaterThan($hvec x, $hvec y); 849 $pure $bvec greaterThan($ivec x, $ivec y); 850 $pure $bvec greaterThan($svec x, $svec y); 851 $pure $bvec greaterThanEqual($vec x, $vec y); 852 $pure $bvec greaterThanEqual($hvec x, $hvec y); 853 $pure $bvec greaterThanEqual($ivec x, $ivec y); 854 $pure $bvec greaterThanEqual($svec x, $svec y); 855 $pure $bvec equal($vec x, $vec y); 856 $pure $bvec equal($hvec x, $hvec y); 857 $pure $bvec equal($ivec x, $ivec y); 858 $pure $bvec equal($svec x, $svec y); 859 $pure $bvec equal($bvec x, $bvec y); 860 $pure $bvec notEqual($vec x, $vec y); 861 $pure $bvec notEqual($hvec x, $hvec y); 862 $pure $bvec notEqual($ivec x, $ivec y); 863 $pure $bvec notEqual($svec x, $svec y); 864 $pure $bvec notEqual($bvec x, $bvec y); 865 866 $pure $es3 $bvec lessThan($usvec x, $usvec y); 867 $pure $es3 $bvec lessThan($uvec x, $uvec y); 868 $pure $es3 $bvec lessThanEqual($uvec x, $uvec y); 869 $pure $es3 $bvec lessThanEqual($usvec x, $usvec y); 870 $pure $es3 $bvec greaterThan($uvec x, $uvec y); 871 $pure $es3 $bvec greaterThan($usvec x, $usvec y); 872 $pure $es3 $bvec greaterThanEqual($uvec x, $uvec y); 873 $pure $es3 $bvec greaterThanEqual($usvec x, $usvec y); 874 $pure $es3 $bvec equal($uvec x, $uvec y); 875 $pure $es3 $bvec equal($usvec x, $usvec y); 876 $pure $es3 $bvec notEqual($uvec x, $uvec y); 877 $pure $es3 $bvec notEqual($usvec x, $usvec y); 878 879 $pure bool any($bvec x); 880 $pure bool all($bvec x); 881 $pure $bvec not($bvec x); 882 883 // 8.9 : Fragment Processing Functions (GLSL ES 3.0) 884 $pure $es3 $genType dFdx($genType p); 885 $pure $es3 $genType dFdy($genType p); 886 $pure $es3 $genHType dFdx($genHType p); 887 $pure $es3 $genHType dFdy($genHType p); 888 $pure $es3 $genType fwidth($genType p); 889 $pure $es3 $genHType fwidth($genHType p); 890 891 892 // SkSL utility functions 893 894 // The max() guards against division by zero when the incoming color is transparent black 895 $pure half4 unpremul(half4 color) { return half4 (color.rgb / max(color.a, 0.0001), color.a); } 896 $pure float4 unpremul(float4 color) { return float4(color.rgb / max(color.a, 0.0001), color.a); } 897 898 // Similar, but used for polar-space CSS colors 899 $export $pure half4 $unpremul_polar(half4 color) { 900 return half4(color.r, color.gb / max(color.a, 0.0001), color.a); 901 } 902 903 // Convert RGBA -> HSLA (including unpremul). 904 // 905 // Based on work by Sam Hocevar, Emil Persson, and Ian Taylor [1][2][3]. High-level ideas: 906 // 907 // - minimize the number of branches by sorting and computing the hue phase in parallel (vec4s) 908 // 909 // - trade the third sorting branch for a potentially faster std::min and leaving 2nd/3rd 910 // channels unsorted (based on the observation that swapping both the channels and the bias sign 911 // has no effect under abs) 912 // 913 // - use epsilon offsets for denominators, to avoid explicit zero-checks 914 // 915 // An additional trick we employ is deferring premul->unpremul conversion until the very end: the 916 // alpha factor gets naturally simplified for H and S, and only L requires a dedicated unpremul 917 // division (so we trade three divs for one). 918 // 919 // [1] http://lolengine.net/blog/2013/01/13/fast-rgb-to-hsv 920 // [2] http://lolengine.net/blog/2013/07/27/rgb-to-hsv-in-glsl 921 // [3] http://www.chilliant.com/rgb2hsv.html 922 923 $export $pure half4 $rgb_to_hsl(half3 c, half a) { 924 half4 p = (c.g < c.b) ? half4(c.bg, -1, 2/3.0) 925 : half4(c.gb, 0, -1/3.0); 926 half4 q = (c.r < p.x) ? half4(p.x, c.r, p.yw) 927 : half4(c.r, p.x, p.yz); 928 929 // q.x -> max channel value 930 // q.yz -> 2nd/3rd channel values (unsorted) 931 // q.w -> bias value dependent on max channel selection 932 933 const half kEps = 0.0001; 934 half pmV = q.x; 935 half pmC = pmV - min(q.y, q.z); 936 half pmL = pmV - pmC * 0.5; 937 half H = abs(q.w + (q.y - q.z) / (pmC * 6 + kEps)); 938 half S = pmC / (a + kEps - abs(pmL * 2 - a)); 939 half L = pmL / (a + kEps); 940 941 return half4(H, S, L, a); 942 } 943 944 // Convert HSLA -> RGBA (including clamp and premul). 945 // 946 // Based on work by Sam Hocevar, Emil Persson, and Ian Taylor [1][2][3]. 947 // 948 // [1] http://lolengine.net/blog/2013/01/13/fast-rgb-to-hsv 949 // [2] http://lolengine.net/blog/2013/07/27/rgb-to-hsv-in-glsl 950 // [3] http://www.chilliant.com/rgb2hsv.html 951 952 $export $pure half3 $hsl_to_rgb(half3 hsl) { 953 half C = (1 - abs(2 * hsl.z - 1)) * hsl.y; 954 half3 p = hsl.xxx + half3(0, 2/3.0, 1/3.0); 955 half3 q = saturate(abs(fract(p) * 6 - 3) - 1); 956 957 return (q - 0.5) * C + hsl.z; 958 } 959 960 $export $pure half4 $hsl_to_rgb(half3 hsl, half a) { 961 return saturate(half4($hsl_to_rgb(hsl) * a, a)); 962 } 963 964 // Color conversion functions used in gradient interpolation, based on 965 // https://www.w3.org/TR/css-color-4/#color-conversion-code 966 // TODO(skia:13108): For all of these, we can eliminate any linear math at the beginning 967 // (by removing the corresponding linear math at the end of the CPU code). 968 $export $pure half3 $css_lab_to_xyz(half3 lab) { 969 const half k = 24389 / 27.0; 970 const half e = 216 / 24389.0; 971 972 half3 f; 973 f[1] = (lab[0] + 16) / 116; 974 f[0] = (lab[1] / 500) + f[1]; 975 f[2] = f[1] - (lab[2] / 200); 976 977 half3 f_cubed = pow(f, half3(3)); 978 979 half3 xyz = half3( 980 f_cubed[0] > e ? f_cubed[0] : (116 * f[0] - 16) / k, 981 lab[0] > k * e ? f_cubed[1] : lab[0] / k, 982 f_cubed[2] > e ? f_cubed[2] : (116 * f[2] - 16) / k 983 ); 984 985 const half3 D50 = half3(0.3457 / 0.3585, 1.0, (1.0 - 0.3457 - 0.3585) / 0.3585); 986 return xyz * D50; 987 } 988 989 // Skia stores all polar colors with hue in the first component, so this "LCH -> Lab" transform 990 // actually takes "HCL". This is also used to do the same polar transform for OkHCL to OkLAB. 991 // See similar comments & logic in SkGradientShaderBase.cpp. 992 $pure half3 $css_hcl_to_lab(half3 hcl) { 993 return half3( 994 hcl[2], 995 hcl[1] * cos(radians(hcl[0])), 996 hcl[1] * sin(radians(hcl[0])) 997 ); 998 } 999 1000 $export $pure half3 $css_hcl_to_xyz(half3 hcl) { 1001 return $css_lab_to_xyz($css_hcl_to_lab(hcl)); 1002 } 1003 1004 $export $pure half3 $css_oklab_to_linear_srgb(half3 oklab) { 1005 half l_ = oklab.x + 0.3963377774 * oklab.y + 0.2158037573 * oklab.z, 1006 m_ = oklab.x - 0.1055613458 * oklab.y - 0.0638541728 * oklab.z, 1007 s_ = oklab.x - 0.0894841775 * oklab.y - 1.2914855480 * oklab.z; 1008 1009 half l = l_*l_*l_, 1010 m = m_*m_*m_, 1011 s = s_*s_*s_; 1012 1013 return half3( 1014 +4.0767416621 * l - 3.3077115913 * m + 0.2309699292 * s, 1015 -1.2684380046 * l + 2.6097574011 * m - 0.3413193965 * s, 1016 -0.0041960863 * l - 0.7034186147 * m + 1.7076147010 * s 1017 ); 1018 } 1019 1020 $export $pure half3 $css_okhcl_to_linear_srgb(half3 okhcl) { 1021 return $css_oklab_to_linear_srgb($css_hcl_to_lab(okhcl)); 1022 } 1023 1024 $export $pure half3 $css_oklab_gamut_map_to_linear_srgb(half3 oklab) { 1025 // Constants for the normal vector of the plane formed by white, black, and 1026 // the specified vertex of the gamut. 1027 const half2 normal_R = half2(0.409702, -0.912219); 1028 const half2 normal_M = half2(-0.397919, -0.917421); 1029 const half2 normal_B = half2(-0.906800, 0.421562); 1030 const half2 normal_C = half2(-0.171122, 0.985250); 1031 const half2 normal_G = half2(0.460276, 0.887776); 1032 const half2 normal_Y = half2(0.947925, 0.318495); 1033 )" 1034 R"( 1035 // For the triangles formed by white (W) or black (K) with the vertices 1036 // of Yellow and Red (YR), Red and Magenta (RM), etc, the constants to be 1037 // used to compute the intersection of a line of constant hue and luminance 1038 // with that plane. 1039 const half c0_YR = 0.091132; 1040 const half2 cW_YR = half2(0.070370, 0.034139); 1041 const half2 cK_YR = half2(0.018170, 0.378550); 1042 const half c0_RM = 0.113902; 1043 const half2 cW_RM = half2(0.090836, 0.036251); 1044 const half2 cK_RM = half2(0.226781, 0.018764); 1045 const half c0_MB = 0.161739; 1046 const half2 cW_MB = half2(-0.008202, -0.264819); 1047 const half2 cK_MB = half2( 0.187156, -0.284304); 1048 const half c0_BC = 0.102047; 1049 const half2 cW_BC = half2(-0.014804, -0.162608); 1050 const half2 cK_BC = half2(-0.276786, 0.004193); 1051 const half c0_CG = 0.092029; 1052 const half2 cW_CG = half2(-0.038533, -0.001650); 1053 const half2 cK_CG = half2(-0.232572, -0.094331); 1054 const half c0_GY = 0.081709; 1055 const half2 cW_GY = half2(-0.034601, -0.002215); 1056 const half2 cK_GY = half2( 0.012185, 0.338031); 1057 1058 half2 ab = oklab.yz; 1059 1060 // Find the planes to intersect with and set the constants based on those 1061 // planes. 1062 half c0; 1063 half2 cW; 1064 half2 cK; 1065 if (dot(ab, normal_R) < 0.0) { 1066 if (dot(ab, normal_G) < 0.0) { 1067 if (dot(ab, normal_C) < 0.0) { 1068 c0 = c0_BC; cW = cW_BC; cK = cK_BC; 1069 } else { 1070 c0 = c0_CG; cW = cW_CG; cK = cK_CG; 1071 } 1072 } else { 1073 if (dot(ab, normal_Y) < 0.0) { 1074 c0 = c0_GY; cW = cW_GY; cK = cK_GY; 1075 } else { 1076 c0 = c0_YR; cW = cW_YR; cK = cK_YR; 1077 } 1078 } 1079 } else { 1080 if (dot(ab, normal_B) < 0.0) { 1081 if (dot(ab, normal_M) < 0.0) { 1082 c0 = c0_RM; cW = cW_RM; cK = cK_RM; 1083 } else { 1084 c0 = c0_MB; cW = cW_MB; cK = cK_MB; 1085 } 1086 } else { 1087 c0 = c0_BC; cW = cW_BC; cK = cK_BC; 1088 } 1089 } 1090 1091 // Perform the intersection. 1092 half alpha = 1.0; 1093 1094 // Intersect with the plane with white. 1095 half w_denom = dot(cW, ab); 1096 if (w_denom > 0.0) { 1097 half one_minus_L = 1.0 - oklab.r; 1098 half w_num = c0*one_minus_L; 1099 if (w_num < w_denom) { 1100 alpha = min(alpha, w_num / w_denom); 1101 } 1102 } 1103 1104 // Intersect with the plane with black. 1105 half k_denom = dot(cK, ab); 1106 if (k_denom > 0.0) { 1107 half L = oklab.r; 1108 half k_num = c0*L; 1109 if (k_num < k_denom) { 1110 alpha = min(alpha, k_num / k_denom); 1111 } 1112 } 1113 1114 // Attenuate the ab coordinate by alpha. 1115 oklab.yz *= alpha; 1116 1117 return $css_oklab_to_linear_srgb(oklab); 1118 } 1119 1120 $export $pure half3 $css_okhcl_gamut_map_to_linear_srgb(half3 okhcl) { 1121 return $css_oklab_gamut_map_to_linear_srgb($css_hcl_to_lab(okhcl)); 1122 } 1123 1124 // TODO(skia:13108): Use our optimized version (though it has different range) 1125 // Doing so might require fixing (re-deriving?) the math for the HWB version below 1126 $export $pure half3 $css_hsl_to_srgb(half3 hsl) { 1127 hsl.x = mod(hsl.x, 360); 1128 if (hsl.x < 0) { 1129 hsl.x += 360; 1130 } 1131 1132 hsl.yz /= 100; 1133 1134 half3 k = mod(half3(0, 8, 4) + hsl.x/30, 12); 1135 half a = hsl.y * min(hsl.z, 1 - hsl.z); 1136 return hsl.z - a * clamp(min(k - 3, 9 - k), -1, 1); 1137 } 1138 1139 $export $pure half3 $css_hwb_to_srgb(half3 hwb) { 1140 half3 rgb; 1141 hwb.yz /= 100; 1142 if (hwb.y + hwb.z >= 1) { 1143 // Emit grayscale 1144 rgb = half3(hwb.y / (hwb.y + hwb.z)); 1145 } else { 1146 rgb = $css_hsl_to_srgb(half3(hwb.x, 100, 50)); 1147 rgb *= (1 - hwb.y - hwb.z); 1148 rgb += hwb.y; 1149 } 1150 return rgb; 1151 } 1152 1153 /* 1154 * The actual output color space of this function depends on the input color space 1155 * (it might be sRGB, linear sRGB, or linear XYZ). The actual space is what's stored 1156 * in the gradient/SkColor4fXformer's fIntermediateColorSpace. 1157 */ 1158 $export $pure half4 $interpolated_to_rgb_unpremul(half4 color, int colorSpace, int doUnpremul) { 1159 const int kDestination = 0; 1160 const int kSRGBLinear = 1; 1161 const int kLab = 2; 1162 const int kOKLab = 3; 1163 const int kOKLabGamutMap = 4; 1164 const int kLCH = 5; 1165 const int kOKLCH = 6; 1166 const int kOKLCHGamutMap = 7; 1167 const int kSRGB = 8; 1168 const int kHSL = 9; 1169 const int kHWB = 10; 1170 1171 if (bool(doUnpremul)) { 1172 switch (colorSpace) { 1173 case kLab: 1174 case kOKLab: 1175 case kOKLabGamutMap: color = unpremul(color); break; 1176 case kLCH: 1177 case kOKLCH: 1178 case kOKLCHGamutMap: 1179 case kHSL: 1180 case kHWB: color = $unpremul_polar(color); break; 1181 } 1182 } 1183 switch (colorSpace) { 1184 case kLab: color.rgb = $css_lab_to_xyz(color.rgb); break; 1185 case kOKLab: color.rgb = $css_oklab_to_linear_srgb(color.rgb); break; 1186 case kOKLabGamutMap: color.rgb = $css_oklab_gamut_map_to_linear_srgb(color.rgb); break; 1187 case kLCH: color.rgb = $css_hcl_to_xyz(color.rgb); break; 1188 case kOKLCH: color.rgb = $css_okhcl_to_linear_srgb(color.rgb); break; 1189 case kOKLCHGamutMap: color.rgb = $css_okhcl_gamut_map_to_linear_srgb(color.rgb); break; 1190 case kHSL: color.rgb = $css_hsl_to_srgb(color.rgb); break; 1191 case kHWB: color.rgb = $css_hwb_to_srgb(color.rgb); break; 1192 } 1193 return color; 1194 } 1195 )"} 1196 }; 1197