gpu/shaders: update piet-gpu

Changes:
- faster implementation of RGBA output
- fix stroked clips and images

Signed-off-by: Elias Naur <mail@eliasnaur.com>
This commit is contained in:
Elias Naur
2021-03-31 19:55:29 +02:00
parent 5e1a662b94
commit ebf2dcea50
6 changed files with 106 additions and 128 deletions
+37 -77
View File
@@ -13,9 +13,12 @@
#include "mem.h"
#include "setup.h"
#define CHUNK 8
#define CHUNK_DY (TILE_HEIGHT_PX / CHUNK)
layout(local_size_x = TILE_WIDTH_PX, local_size_y = CHUNK_DY) in;
#define CHUNK_X 2
#define CHUNK_Y 4
#define CHUNK CHUNK_X * CHUNK_Y
#define CHUNK_DX (TILE_WIDTH_PX / CHUNK_X)
#define CHUNK_DY (TILE_HEIGHT_PX / CHUNK_Y)
layout(local_size_x = CHUNK_DX, local_size_y = CHUNK_DY) in;
layout(set = 0, binding = 1) readonly buffer ConfigBuf {
Config conf;
@@ -32,36 +35,6 @@ layout(rgba8, set = 0, binding = 3) uniform readonly image2D images[1];
#include "ptcl.h"
#include "tile.h"
#define BLEND_STACK_SIZE 4
// Layout of a clip scratch frame:
// Each frame is WIDTH * HEIGHT ClipStates, then a link reference.
struct ClipState {
uint srgb;
float area;
};
// Link offset and frame size in 32-bit words.
#define CLIP_STATE_SIZE 2
#define CLIP_LINK_OFFSET (TILE_WIDTH_PX * TILE_HEIGHT_PX * CLIP_STATE_SIZE)
#define CLIP_BUF_SIZE (CLIP_LINK_OFFSET + 1)
shared MallocResult sh_clip_alloc;
// Allocate a scratch buffer for clipping.
MallocResult alloc_clip_buf(uint link) {
if (gl_LocalInvocationID.x == 0 && gl_LocalInvocationID.y == 0) {
MallocResult m = malloc(CLIP_BUF_SIZE * 4);
if (!m.failed) {
write_mem(m.alloc, (m.alloc.offset >> 2) + CLIP_LINK_OFFSET, link);
}
sh_clip_alloc = m;
}
barrier();
return sh_clip_alloc;
}
vec3 tosRGB(vec3 rgb) {
bvec3 cutoff = greaterThanEqual(rgb, vec3(0.0031308));
vec3 below = vec3(12.92)*rgb;
@@ -90,10 +63,14 @@ uint packsRGB(vec4 rgba) {
return packUnorm4x8(rgba.wzyx);
}
uvec2 chunk_offset(uint i) {
return uvec2(i % CHUNK_X * CHUNK_DX, i / CHUNK_X * CHUNK_DY);
}
vec4[CHUNK] fillImage(uvec2 xy, CmdImage cmd_img) {
vec4 rgba[CHUNK];
for (uint i = 0; i < CHUNK; i++) {
ivec2 uv = ivec2(xy.x, xy.y + i * CHUNK_DY) + cmd_img.offset;
ivec2 uv = ivec2(xy + chunk_offset(i)) + cmd_img.offset;
#ifdef ENABLE_IMAGE_INDICES
vec4 fg_rgba = imageLoad(images[cmd_img.index], uv);
#else
@@ -114,23 +91,24 @@ void main() {
Alloc cmd_alloc = slice_mem(conf.ptcl_alloc, tile_ix * PTCL_INITIAL_ALLOC, PTCL_INITIAL_ALLOC);
CmdRef cmd_ref = CmdRef(cmd_alloc.offset);
uvec2 xy_uint = uvec2(gl_GlobalInvocationID.x, gl_LocalInvocationID.y + TILE_HEIGHT_PX * gl_WorkGroupID.y);
// Read scrach space allocation, written first in the command list.
Alloc scratch_alloc = alloc_read(cmd_alloc, cmd_ref.offset);
cmd_ref.offset += Alloc_size;
uvec2 xy_uint = uvec2(gl_LocalInvocationID.x + TILE_WIDTH_PX * gl_WorkGroupID.x, gl_LocalInvocationID.y + TILE_HEIGHT_PX * gl_WorkGroupID.y);
vec2 xy = vec2(xy_uint);
vec4 rgba[CHUNK];
ClipState blend_stack[BLEND_STACK_SIZE][CHUNK];
uint blend_spill = 0;
uint blend_sp = 0;
Alloc clip_tos = new_alloc(0, 0);
for (uint i = 0; i < CHUNK; i++) {
rgba[i] = vec4(0.0);
#ifdef ENABLE_IMAGE_INDICES
if (xy_uint.x < 1024 && xy_uint.y < 1024) {
rgba[i] = imageLoad(images[gl_WorkGroupID.x / 64], ivec2(xy_uint.x, xy_uint.y + CHUNK_DY * i)/4);
rgba[i] = imageLoad(images[gl_WorkGroupID.x / 64], ivec2(xy_uint + chunk_offset(i))/4);
}
#endif
}
float area[CHUNK];
uint clip_depth = 0;
while (true) {
uint tag = Cmd_tag(cmd_alloc, cmd_ref).tag;
if (tag == Cmd_End) {
@@ -148,7 +126,7 @@ void main() {
vec2 line_vec = seg.vector;
for (uint k = 0; k < CHUNK; k++) {
vec2 dpos = xy + vec2(0.5, 0.5) - seg.origin;
dpos.y += float(k * CHUNK_DY);
dpos += vec2(chunk_offset(k));
float t = clamp(dot(line_vec, dpos) / dot(line_vec, line_vec), 0.0, 1.0);
df[k] = min(df[k], length(line_vec * t - dpos));
}
@@ -167,7 +145,7 @@ void main() {
do {
TileSeg seg = TileSeg_read(new_alloc(tile_seg_ref.offset, TileSeg_size), tile_seg_ref);
for (uint k = 0; k < CHUNK; k++) {
vec2 my_xy = vec2(xy.x, xy.y + float(k * CHUNK_DY));
vec2 my_xy = xy + vec2(chunk_offset(k));
vec2 start = seg.origin - my_xy;
vec2 end = start + seg.vector;
vec2 window = clamp(vec2(start.y, end.y), 0.0, 1.0);
@@ -223,47 +201,29 @@ void main() {
cmd_ref.offset += 4 + CmdImage_size;
break;
case Cmd_BeginClip:
uint blend_slot = blend_sp % BLEND_STACK_SIZE;
if (blend_sp == blend_spill + BLEND_STACK_SIZE) {
// spill to scratch buffer
MallocResult m = alloc_clip_buf(clip_tos.offset);
if (m.failed) {
return;
}
clip_tos = m.alloc;
uint base_ix = (clip_tos.offset >> 2) + CLIP_STATE_SIZE * (gl_LocalInvocationID.x + TILE_WIDTH_PX * gl_LocalInvocationID.y);
for (uint k = 0; k < CHUNK; k++) {
uint srgb = blend_stack[blend_slot][k].srgb;
uint area = floatBitsToUint(blend_stack[blend_slot][k].area);
write_mem(clip_tos, base_ix + 0 + k * CLIP_STATE_SIZE * TILE_WIDTH_PX * CHUNK_DY, srgb);
write_mem(clip_tos, base_ix + 1 + k * CLIP_STATE_SIZE * TILE_WIDTH_PX * CHUNK_DY, area);
}
blend_spill++;
}
uint base_ix = (scratch_alloc.offset >> 2) + CLIP_STATE_SIZE * (clip_depth * TILE_WIDTH_PX * TILE_HEIGHT_PX +
gl_LocalInvocationID.x + TILE_WIDTH_PX * gl_LocalInvocationID.y);
for (uint k = 0; k < CHUNK; k++) {
blend_stack[blend_slot][k] = ClipState(packsRGB(rgba[k]), clamp(abs(area[k]), 0.0, 1.0));
uvec2 offset = chunk_offset(k);
uint srgb = packsRGB(vec4(rgba[k]));
float alpha = clamp(abs(area[k]), 0.0, 1.0);
write_mem(scratch_alloc, base_ix + 0 + CLIP_STATE_SIZE * (offset.x + offset.y * TILE_WIDTH_PX), srgb);
write_mem(scratch_alloc, base_ix + 1 + CLIP_STATE_SIZE * (offset.x + offset.y * TILE_WIDTH_PX), floatBitsToUint(alpha));
rgba[k] = vec4(0.0);
}
blend_sp++;
clip_depth++;
cmd_ref.offset += 4;
break;
case Cmd_EndClip:
blend_slot = (blend_sp - 1) % BLEND_STACK_SIZE;
if (blend_sp == blend_spill) {
uint base_ix = (clip_tos.offset >> 2) + CLIP_STATE_SIZE * (gl_LocalInvocationID.x + TILE_WIDTH_PX * gl_LocalInvocationID.y);
for (uint k = 0; k < CHUNK; k++) {
uint srgb = read_mem(clip_tos, base_ix + 0 + k * CLIP_STATE_SIZE * TILE_WIDTH_PX * CHUNK_DY);
uint area = read_mem(clip_tos, base_ix + 1 + k * CLIP_STATE_SIZE * TILE_WIDTH_PX * CHUNK_DY);
ClipState state = ClipState(srgb, uintBitsToFloat(area));
blend_stack[blend_slot][k] = state;
}
clip_tos.offset = read_mem(clip_tos, (clip_tos.offset >> 2) + CLIP_LINK_OFFSET);
blend_spill--;
}
blend_sp--;
clip_depth--;
base_ix = (scratch_alloc.offset >> 2) + CLIP_STATE_SIZE * (clip_depth * TILE_WIDTH_PX * TILE_HEIGHT_PX +
gl_LocalInvocationID.x + TILE_WIDTH_PX * gl_LocalInvocationID.y);
for (uint k = 0; k < CHUNK; k++) {
vec4 bg = unpacksRGB(blend_stack[blend_slot][k].srgb);
vec4 fg = rgba[k] * area[k] * blend_stack[blend_slot][k].area;
uvec2 offset = chunk_offset(k);
uint srgb = read_mem(scratch_alloc, base_ix + 0 + CLIP_STATE_SIZE * (offset.x + offset.y * TILE_WIDTH_PX));
uint alpha = read_mem(scratch_alloc, base_ix + 1 + CLIP_STATE_SIZE * (offset.x + offset.y * TILE_WIDTH_PX));
vec4 bg = unpacksRGB(srgb);
vec4 fg = rgba[k] * area[k] * uintBitsToFloat(alpha);
rgba[k] = bg * (1.0 - fg.a) + fg;
}
cmd_ref.offset += 4;
@@ -276,6 +236,6 @@ void main() {
}
for (uint i = 0; i < CHUNK; i++) {
imageStore(image, ivec2(xy_uint.x, xy_uint.y + CHUNK_DY * i), vec4(tosRGB(rgba[i].rgb), rgba[i].a));
imageStore(image, ivec2(xy_uint + chunk_offset(i)), vec4(tosRGB(rgba[i].rgb), rgba[i].a));
}
}