wlroots/render/vulkan/shaders/texture.frag
llyyr 604fcdb1db render/vulkan: clip negative values before applying transfer function
Not all eotf or eotf inverse are well defined for values outside the
intended domain, so just ignore it and clamp it away.

An alternative solution would be to use sign preserving pow here (i.e.
sign(x) * pow(abs(x), p)), however I'm not sure that makes sense or is
defined anywhere. Negative values here are likely a result of colors
being outside the gamut range, so clipping them to 0 is more correct
than mirroring from 0.
2025-10-29 03:09:11 +05:30

90 lines
2.2 KiB
GLSL

#version 450
layout(set = 0, binding = 0) uniform sampler2D tex;
layout(location = 0) in vec2 uv;
layout(location = 0) out vec4 out_color;
// struct wlr_vk_frag_texture_pcr_data
layout(push_constant, row_major) uniform UBO {
layout(offset = 80) mat4 matrix;
float alpha;
float luminance_multiplier;
} data;
layout (constant_id = 0) const int TEXTURE_TRANSFORM = 0;
// Matches enum wlr_vk_texture_transform
#define TEXTURE_TRANSFORM_IDENTITY 0
#define TEXTURE_TRANSFORM_SRGB 1
#define TEXTURE_TRANSFORM_ST2084_PQ 2
#define TEXTURE_TRANSFORM_GAMMA22 3
#define TEXTURE_TRANSFORM_BT1886 4
float srgb_channel_to_linear(float x) {
return mix(x / 12.92,
pow((x + 0.055) / 1.055, 2.4),
x > 0.04045);
}
vec3 srgb_color_to_linear(vec3 color) {
return vec3(
srgb_channel_to_linear(color.r),
srgb_channel_to_linear(color.g),
srgb_channel_to_linear(color.b)
);
}
vec3 pq_color_to_linear(vec3 color) {
float inv_m1 = 1 / 0.1593017578125;
float inv_m2 = 1 / 78.84375;
float c1 = 0.8359375;
float c2 = 18.8515625;
float c3 = 18.6875;
vec3 num = max(pow(color, vec3(inv_m2)) - c1, 0);
vec3 denom = c2 - c3 * pow(color, vec3(inv_m2));
return pow(num / denom, vec3(inv_m1));
}
vec3 bt1886_color_to_linear(vec3 color) {
float lb = pow(0.0001, 1.0 / 2.4);
float lw = pow(1.0, 1.0 / 2.4);
float a = pow(lw - lb, 2.4);
float b = lb / (lw - lb);
return a * pow(color + vec3(b), vec3(2.4));
}
void main() {
vec4 in_color = textureLod(tex, uv, 0);
// Convert from pre-multiplied alpha to straight alpha
float alpha = in_color.a;
vec3 rgb;
if (alpha == 0) {
rgb = vec3(0);
} else {
rgb = in_color.rgb / alpha;
}
if (TEXTURE_TRANSFORM != TEXTURE_TRANSFORM_IDENTITY) {
rgb = max(rgb, vec3(0));
}
if (TEXTURE_TRANSFORM == TEXTURE_TRANSFORM_SRGB) {
rgb = srgb_color_to_linear(rgb);
} else if (TEXTURE_TRANSFORM == TEXTURE_TRANSFORM_ST2084_PQ) {
rgb = pq_color_to_linear(rgb);
} else if (TEXTURE_TRANSFORM == TEXTURE_TRANSFORM_GAMMA22) {
rgb = pow(rgb, vec3(2.2));
} else if (TEXTURE_TRANSFORM == TEXTURE_TRANSFORM_BT1886) {
rgb = bt1886_color_to_linear(rgb);
}
rgb *= data.luminance_multiplier;
rgb = mat3(data.matrix) * rgb;
// Back to pre-multiplied alpha
out_color = vec4(rgb * alpha, alpha);
out_color *= data.alpha;
}