1#version 450
2// Draws a solid fill, a client dmabuf (sampled image) or a client wl_shm
3// buffer (B8G8R8A8 words in a storage buffer). Client pixels are
4// premultiplied, as Wayland buffers are: the pipeline blends ONE,
5// ONE_MINUS_SRC_ALPHA. Scaled draws filter linearly; 1:1 draws read the
6// texel under the fragment, pixel exact.
7
8layout(push_constant) uniform Draw {
9 ivec4 rect;
10 vec4 map;
11 vec4 color;
12 uvec4 buf;
13 uvec4 misc;
14} d;
15
16layout(set = 0, binding = 0) uniform sampler2D tex;
17layout(std430, set = 0, binding = 1) readonly buffer Pixels { uint pixels[]; };
18
19layout(location = 0) out vec4 color;
20
21const uint modeSolid = 0u;
22const uint modeImage = 1u;
23const uint flagOpaque = 1u;
24const uint flagExact = 2u;
25
26// texel reads buffer pixel p, clamped to the buffer (clamp to edge).
27vec4 texel(ivec2 p) {
28 p = clamp(p, ivec2(0), ivec2(d.buf.yz) - 1);
29 // Little-endian B,G,R,A bytes: unpack yields (B, G, R, A).
30 return unpackUnorm4x8(pixels[d.buf.x + uint(p.y) * d.buf.y + uint(p.x)]).zyxw;
31}
32
33void main() {
34 vec2 src = d.map.xy + gl_FragCoord.xy * d.map.zw;
35 bool exact = (d.misc.y & flagExact) != 0u;
36 vec4 c;
37 if (d.misc.x == modeSolid) {
38 c = d.color;
39 } else if (d.misc.x == modeImage) {
40 ivec2 size = textureSize(tex, 0);
41 c = exact ? texelFetch(tex, clamp(ivec2(floor(src)), ivec2(0), size - 1), 0) : texture(tex, src / vec2(size));
42 } else if (exact) {
43 c = texel(ivec2(floor(src)));
44 } else {
45 // Bilinear: four texel reads around the sample point.
46 vec2 p = src - 0.5;
47 ivec2 i = ivec2(floor(p));
48 vec2 f = p - vec2(i);
49 c = mix(mix(texel(i), texel(i + ivec2(1, 0)), f.x), mix(texel(i + ivec2(0, 1)), texel(i + ivec2(1, 1)), f.x), f.y);
50 }
51 if ((d.misc.y & flagOpaque) != 0u) {
52 c.a = 1.0;
53 }
54 color = c;
55}