#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 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)); } 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_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)); } rgb *= data.luminance_multiplier; rgb = mat3(data.matrix) * rgb; // Back to pre-multiplied alpha out_color = vec4(rgb * alpha, alpha); out_color *= data.alpha; }