gtk/gsk/vulkan/resources/blend-mode.frag
Benjamin Otte 8207c548cc vulkan: Combine textures and samplers again
This reverts most of commit f420c143e0
again because it turns out GPUs like combined images and samplers.

But: The one thing we don't revert is allowing the C code to select any
combination of sampler and image:
gsk_vulkan_render_get_image_descriptor() now takes a 2nd argument
specifying the sampler.

This allows the same flexibility as before, we just combine things
early.

This change was inspired by
https://developer.nvidia.com/blog/vulkan-dos-donts/
2023-07-16 12:12:36 +02:00

320 lines
6.8 KiB
GLSL

#version 450
#include "common.frag.glsl"
#include "clip.frag.glsl"
#include "rect.frag.glsl"
layout(location = 0) in vec2 inPos;
layout(location = 1) in Rect inTopRect;
layout(location = 2) in Rect inBottomRect;
layout(location = 3) in vec2 inTopTexCoord;
layout(location = 4) in vec2 inBottomTexCoord;
layout(location = 5) flat in uint inTopTexId;
layout(location = 6) flat in uint inBottomTexId;
layout(location = 7) flat in uint inBlendMode;
layout(location = 0) out vec4 color;
float
combine (float source, float backdrop)
{
return source + backdrop * (1 - source);
}
vec4
composite (vec4 Cs, vec4 Cb, vec3 B)
{
float ao = Cs.a + Cb.a * (1 - Cs.a);
vec3 Co = (Cs.a*(1 - Cb.a)*Cs.rgb + Cs.a*Cb.a*B + (1 - Cs.a)*Cb.a*Cb.rgb) / ao;
return vec4(Co, ao);
}
vec4
normal (vec4 Cs, vec4 Cb)
{
return composite (Cs, Cb, Cs.rgb);
}
vec4
multiply (vec4 Cs, vec4 Cb)
{
return composite (Cs, Cb, Cs.rgb * Cb.rgb);
}
vec4
difference (vec4 Cs, vec4 Cb)
{
return composite (Cs, Cb, abs(Cs.rgb - Cb.rgb));
}
vec4
screen (vec4 Cs, vec4 Cb)
{
return composite (Cs, Cb, Cs.rgb + Cb.rgb - Cs.rgb * Cb.rgb);
}
float
hard_light (float source, float backdrop)
{
if (source <= 0.5)
return 2 * backdrop * source;
else
return 2 * (backdrop + source - backdrop * source) - 1;
}
vec4
hard_light (vec4 Cs, vec4 Cb)
{
vec3 B = vec3 (hard_light (Cs.r, Cb.r),
hard_light (Cs.g, Cb.g),
hard_light (Cs.b, Cb.b));
return composite (Cs, Cb, B);
}
float
soft_light (float source, float backdrop)
{
float db;
if (backdrop <= 0.25)
db = ((16 * backdrop - 12) * backdrop + 4) * backdrop;
else
db = sqrt (backdrop);
if (source <= 0.5)
return backdrop - (1 - 2 * source) * backdrop * (1 - backdrop);
else
return backdrop + (2 * source - 1) * (db - backdrop);
}
vec4
soft_light (vec4 Cs, vec4 Cb)
{
vec3 B = vec3 (soft_light (Cs.r, Cb.r),
soft_light (Cs.g, Cb.g),
soft_light (Cs.b, Cb.b));
return composite (Cs, Cb, B);
}
vec4
overlay (vec4 Cs, vec4 Cb)
{
vec3 B = vec3 (hard_light (Cb.r, Cs.r),
hard_light (Cb.g, Cs.g),
hard_light (Cb.b, Cs.b));
return composite (Cs, Cb, B);
}
vec4
darken (vec4 Cs, vec4 Cb)
{
vec3 B = min (Cs.rgb, Cb.rgb);
return composite (Cs, Cb, B);
}
vec4
lighten (vec4 Cs, vec4 Cb)
{
vec3 B = max (Cs.rgb, Cb.rgb);
return composite (Cs, Cb, B);
}
float
color_dodge (float source, float backdrop)
{
return (source == 1.0) ? source : min (backdrop / (1.0 - source), 1.0);
}
vec4
color_dodge (vec4 Cs, vec4 Cb)
{
vec3 B = vec3 (color_dodge (Cs.r, Cb.r),
color_dodge (Cs.g, Cb.g),
color_dodge (Cs.b, Cb.b));
return composite (Cs, Cb, B);
}
float
color_burn (float source, float backdrop)
{
return (source == 0.0) ? source : max ((1.0 - ((1.0 - backdrop) / source)), 0.0);
}
vec4
color_burn (vec4 Cs, vec4 Cb)
{
vec3 B = vec3 (color_burn (Cs.r, Cb.r),
color_burn (Cs.g, Cb.g),
color_burn (Cs.b, Cb.b));
return composite (Cs, Cb, B);
}
vec4
exclusion (vec4 Cs, vec4 Cb)
{
vec3 B = Cb.rgb + Cs.rgb - 2.0 * Cb.rgb * Cs.rgb;
return composite (Cs, Cb, B);
}
float
lum (vec3 c)
{
return 0.3 * c.r + 0.59 * c.g + 0.11 * c.b;
}
vec3
clip_color (vec3 c)
{
float l = lum (c);
float n = min (c.r, min (c.g, c.b));
float x = max (c.r, max (c.g, c.b));
if (n < 0) c = l + (((c - l) * l) / (l - n));
if (x > 1) c = l + (((c - l) * (1 - l)) / (x - l));
return c;
}
vec3
set_lum (vec3 c, float l)
{
float d = l - lum (c);
return clip_color (vec3 (c.r + d, c.g + d, c.b + d));
}
float
sat (vec3 c)
{
return max (c.r, max (c.g, c.b)) - min (c.r, min (c.g, c.b));
}
vec3
set_sat (vec3 c, float s)
{
float cmin = min (c.r, min (c.g, c.b));
float cmax = max (c.r, max (c.g, c.b));
vec3 res;
if (cmax == cmin)
res = vec3 (0, 0, 0);
else
{
if (c.r == cmax)
{
if (c.g == cmin)
{
res.b = ((c.b - cmin) * s) / (cmax - cmin);
res.g = 0;
}
else
{
res.g = ((c.g - cmin) * s) / (cmax - cmin);
res.b = 0;
}
res.r = s;
}
else if (c.g == cmax)
{
if (c.r == cmin)
{
res.b = ((c.b - cmin) * s) / (cmax - cmin);
res.r = 0;
}
else
{
res.r = ((c.r - cmin) * s) / (cmax - cmin);
res.b = 0;
}
res.g = s;
}
else
{
if (c.r == cmin)
{
res.g = ((c.g - cmin) * s) / (cmax - cmin);
res.r = 0;
}
else
{
res.r = ((c.r - cmin) * s) / (cmax - cmin);
res.g = 0;
}
res.b = s;
}
}
return res;
}
vec4
colorize (vec4 Cs, vec4 Cb)
{
vec3 B = set_lum (Cs.rgb, lum (Cb.rgb));
return composite (Cs, Cb, B);
}
vec4
hue (vec4 Cs, vec4 Cb)
{
vec3 B = set_lum (set_sat (Cs.rgb, sat (Cb.rgb)), lum (Cb.rgb));
return composite (Cs, Cb, B);
}
vec4
saturation (vec4 Cs, vec4 Cb)
{
vec3 B = set_lum (set_sat (Cb.rgb, sat (Cs.rgb)), lum (Cb.rgb));
return composite (Cs, Cb, B);
}
vec4
luminosity (vec4 Cs, vec4 Cb)
{
vec3 B = set_lum (Cb.rgb, lum (Cs.rgb));
return composite (Cs, Cb, B);
}
void main()
{
float source_alpha = rect_coverage (inTopRect, inPos);
vec4 source = texture (get_sampler (inTopTexId), inTopTexCoord) * source_alpha;
float backdrop_alpha = rect_coverage (inBottomRect, inPos);
vec4 backdrop = texture (get_sampler (inBottomTexId), inBottomTexCoord) * backdrop_alpha;
vec4 result;
if (inBlendMode == 0)
result = normal (source, backdrop);
else if (inBlendMode == 1)
result = multiply (source, backdrop);
else if (inBlendMode == 2)
result = screen (source, backdrop);
else if (inBlendMode == 3)
result = overlay (source, backdrop);
else if (inBlendMode == 4)
result = darken (source, backdrop);
else if (inBlendMode == 5)
result = lighten (source, backdrop);
else if (inBlendMode == 6)
result = color_dodge (source, backdrop);
else if (inBlendMode == 7)
result = color_burn (source, backdrop);
else if (inBlendMode == 8)
result = hard_light (source, backdrop);
else if (inBlendMode == 9)
result = soft_light (source, backdrop);
else if (inBlendMode == 10)
result = difference (source, backdrop);
else if (inBlendMode == 11)
result = exclusion (source, backdrop);
else if (inBlendMode == 12)
result = colorize (source, backdrop);
else if (inBlendMode == 13)
result = hue (source, backdrop);
else if (inBlendMode == 14)
result = saturation (source, backdrop);
else if (inBlendMode == 15)
result = luminosity (source, backdrop);
else
discard;
color = clip_scaled (inPos, result);
}