blob: d6a3ef376a27573cfa87b1e89c534bbae8614204 [file] [log] [blame]
layout(builtin=15) float4 sk_FragCoord;
// Color conversion functions used in gradient interpolation, based on
// https://www.w3.org/TR/css-color-4/#color-conversion-code
// TODO(skia:13108): For all of these, we can eliminate any linear math at the beginning
// (by removing the corresponding linear math at the end of the CPU code).
$pure half3 $css_Lab_to_XYZ(half3 Lab) {
const half k = 24389 / 27.0;
const half e = 216 / 24389.0;
half3 f;
f[1] = (Lab[0] + 16) / 116;
f[0] = (Lab[1] / 500) + f[1];
f[2] = f[1] - (Lab[2] / 200);
half3 f_cubed = pow(f, half3(3));
half3 xyz = half3(
f_cubed[0] > e ? f_cubed[0] : (116 * f[0] - 16) / k,
Lab[0] > k * e ? f_cubed[1] : Lab[0] / k,
f_cubed[2] > e ? f_cubed[2] : (116 * f[2] - 16) / k
);
const half3 D50 = half3(0.3457 / 0.3585, 1.0, (1.0 - 0.3457 - 0.3585) / 0.3585);
return xyz * D50;
}
// Also used by OKLCH -> OKLab
$pure half3 $css_LCH_to_Lab(half3 LCH) {
return half3(
LCH[0],
LCH[1] * cos(radians(LCH[2])),
LCH[1] * sin(radians(LCH[2]))
);
}
$pure half3 $css_LCH_to_XYZ(half3 LCH) {
return $css_Lab_to_XYZ($css_LCH_to_Lab(LCH));
}
$pure half3 $css_OKLab_to_XYZ(half3 OKLab) {
const half3x3 LMStoXYZ = half3x3(
1.2268798733741557, -0.5578149965554813, 0.28139105017721583,
-0.04057576262431372, 1.1122868293970594, -0.07171106666151701,
-0.07637294974672142, -0.4214933239627914, 1.5869240244272418
);
// TODO(skia:13794): Switch this back to half3x3 when it no longer triggers sk_Caps errors
const float3x3 OKLabToLMS = half3x3(
0.99999999845051981432, 0.39633779217376785678, 0.21580375806075880339,
1.0000000088817607767, -0.1055613423236563494, -0.063854174771705903402,
1.0000000546724109177, -0.089484182094965759684, -1.2914855378640917399
);
half3 LMSnl = half3(OKLabToLMS * OKLab);
return LMStoXYZ * pow(LMSnl, half3(3));
}
$pure half3 $css_OKLCH_to_XYZ(half3 OKLCH) {
return $css_OKLab_to_XYZ($css_LCH_to_Lab(OKLCH));
}
// TODO(skia:13108): Use our optimized version (though it has different range)
// Doing so might require fixing (re-deriving?) the math for the HWB version below
$pure half3 $css_hsl_to_sRGB(half3 hsl) {
hsl.x = mod(hsl.x, 360);
if (hsl.x < 0) {
hsl.x += 360;
}
hsl.yz /= 100;
half3 k = mod(half3(0, 8, 4) + hsl.x/30, 12);
half a = hsl.y * min(hsl.z, 1 - hsl.z);
return hsl.z - a * clamp(min(k - 3, 9 - k), -1, 1);
}
$pure half3 $css_hwb_to_sRGB(half3 hwb) {
hwb.yz /= 100;
if (hwb.y + hwb.z >= 1) {
half gray = hwb.y / (hwb.y + hwb.z);
return half3(gray);
}
half3 rgb = $css_hsl_to_sRGB(half3(hwb.x, 100, 50));
rgb *= (1 - hwb.y - hwb.z);
rgb += hwb.y;
return rgb;
}