pre-allocate kernel4 scratch space in coarse.comp

coarse.comp knows the maximum stack depth, and can pre-allocate scratch
space for kernel4.comp. Kernel4 no longer contains allocations nor
control barriers.

The invocation local blend stack is gone as well; it didn't seem to make
any difference in performance to always use global memory for pushing
and popping.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
This commit is contained in:
Elias Naur 2021-03-30 20:16:36 +02:00
parent e6b535d942
commit 22507dea0e
5 changed files with 57 additions and 58 deletions

View file

@ -152,6 +152,12 @@ void main() {
uint part_start_ix = 0; uint part_start_ix = 0;
uint ready_ix = 0; uint ready_ix = 0;
// Leave room for the fine rasterizer scratch allocation.
Alloc scratch_alloc = slice_mem(cmd_alloc, 0, Alloc_size);
cmd_ref.offset += Alloc_size;
uint num_begin_slots = 0;
uint begin_slot = 0;
while (true) { while (true) {
for (uint i = 0; i < N_SLICE; i++) { for (uint i = 0; i < N_SLICE; i++) {
sh_bitmaps[i][th_ix] = 0; sh_bitmaps[i][th_ix] = 0;
@ -370,6 +376,8 @@ void main() {
if (clip_depth < 32) { if (clip_depth < 32) {
clip_one_mask &= ~(1 << clip_depth); clip_one_mask &= ~(1 << clip_depth);
} }
begin_slot++;
num_begin_slots = max(num_begin_slots, begin_slot);
} }
clip_depth++; clip_depth++;
break; break;
@ -381,6 +389,7 @@ void main() {
} }
Cmd_Solid_write(cmd_alloc, cmd_ref); Cmd_Solid_write(cmd_alloc, cmd_ref);
cmd_ref.offset += 4; cmd_ref.offset += 4;
begin_slot--;
Cmd_EndClip_write(cmd_alloc, cmd_ref); Cmd_EndClip_write(cmd_alloc, cmd_ref);
cmd_ref.offset += 4; cmd_ref.offset += 4;
} }
@ -408,5 +417,13 @@ void main() {
} }
if (bin_tile_x + tile_x < conf.width_in_tiles && bin_tile_y + tile_y < conf.height_in_tiles) { if (bin_tile_x + tile_x < conf.width_in_tiles && bin_tile_y + tile_y < conf.height_in_tiles) {
Cmd_End_write(cmd_alloc, cmd_ref); Cmd_End_write(cmd_alloc, cmd_ref);
if (num_begin_slots > 0) {
// Write scratch allocation: one word per BeginClip per rasterizer chunk.
uint scratch_size = num_begin_slots * TILE_WIDTH_PX * TILE_HEIGHT_PX * 4;
MallocResult scratch = malloc(scratch_size);
// Ignore scratch.failed; we don't use the allocation and kernel4
// checks for memory overflow before using it.
alloc_write(scratch_alloc, scratch_alloc.offset, scratch.alloc);
}
} }
} }

Binary file not shown.

View file

@ -35,30 +35,6 @@ layout(rgba8, set = 0, binding = 3) uniform readonly image2D images[1];
#include "ptcl.h" #include "ptcl.h"
#include "tile.h" #include "tile.h"
#define BLEND_STACK_SIZE 4
// Layout of a clip scratch frame:
// Each frame is WIDTH * HEIGHT 32-bit words, then a link reference.
// Link offset and frame size in 32-bit words.
#define CLIP_LINK_OFFSET (TILE_WIDTH_PX * TILE_HEIGHT_PX)
#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) { vec3 tosRGB(vec3 rgb) {
bvec3 cutoff = greaterThanEqual(rgb, vec3(0.0031308)); bvec3 cutoff = greaterThanEqual(rgb, vec3(0.0031308));
vec3 below = vec3(12.92)*rgb; vec3 below = vec3(12.92)*rgb;
@ -115,13 +91,13 @@ void main() {
Alloc cmd_alloc = slice_mem(conf.ptcl_alloc, tile_ix * PTCL_INITIAL_ALLOC, PTCL_INITIAL_ALLOC); Alloc cmd_alloc = slice_mem(conf.ptcl_alloc, tile_ix * PTCL_INITIAL_ALLOC, PTCL_INITIAL_ALLOC);
CmdRef cmd_ref = CmdRef(cmd_alloc.offset); CmdRef cmd_ref = CmdRef(cmd_alloc.offset);
// 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); 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); vec2 xy = vec2(xy_uint);
vec3 rgb[CHUNK]; vec3 rgb[CHUNK];
uint 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++) { for (uint i = 0; i < CHUNK; i++) {
rgb[i] = vec3(0.5); rgb[i] = vec3(0.5);
#ifdef ENABLE_IMAGE_INDICES #ifdef ENABLE_IMAGE_INDICES
@ -132,6 +108,7 @@ void main() {
} }
float area[CHUNK]; float area[CHUNK];
uint clip_depth = 0;
while (true) { while (true) {
uint tag = Cmd_tag(cmd_alloc, cmd_ref).tag; uint tag = Cmd_tag(cmd_alloc, cmd_ref).tag;
if (tag == Cmd_End) { if (tag == Cmd_End) {
@ -224,41 +201,24 @@ void main() {
cmd_ref.offset += 4 + CmdImage_size; cmd_ref.offset += 4 + CmdImage_size;
break; break;
case Cmd_BeginClip: case Cmd_BeginClip:
uint blend_slot = blend_sp % BLEND_STACK_SIZE; uint base_ix = (scratch_alloc.offset >> 2) + clip_depth * TILE_WIDTH_PX * TILE_HEIGHT_PX +
if (blend_sp == blend_spill + BLEND_STACK_SIZE) { gl_LocalInvocationID.x + TILE_WIDTH_PX * gl_LocalInvocationID.y;
// 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) + gl_LocalInvocationID.x + TILE_WIDTH_PX * gl_LocalInvocationID.y;
for (uint k = 0; k < CHUNK; k++) {
uvec2 offset = chunk_offset(k);
write_mem(clip_tos, base_ix + offset.x + offset.y * TILE_WIDTH_PX, blend_stack[blend_slot][k]);
}
blend_spill++;
}
for (uint k = 0; k < CHUNK; k++) { for (uint k = 0; k < CHUNK; k++) {
blend_stack[blend_slot][k] = packsRGB(vec4(rgb[k], clamp(abs(area[k]), 0.0, 1.0))); uvec2 offset = chunk_offset(k);
uint state = packsRGB(vec4(rgb[k], clamp(abs(area[k]), 0.0, 1.0)));
write_mem(scratch_alloc, base_ix + offset.x + offset.y * TILE_WIDTH_PX, state);
} }
blend_sp++; clip_depth++;
cmd_ref.offset += 4; cmd_ref.offset += 4;
break; break;
case Cmd_EndClip: case Cmd_EndClip:
blend_slot = (blend_sp - 1) % BLEND_STACK_SIZE; clip_depth--;
if (blend_sp == blend_spill) { base_ix = (scratch_alloc.offset >> 2) + clip_depth * TILE_WIDTH_PX * TILE_HEIGHT_PX +
uint base_ix = (clip_tos.offset >> 2) + gl_LocalInvocationID.x + TILE_WIDTH_PX * gl_LocalInvocationID.y; gl_LocalInvocationID.x + TILE_WIDTH_PX * gl_LocalInvocationID.y;
for (uint k = 0; k < CHUNK; k++) {
uvec2 offset = chunk_offset(k);
blend_stack[blend_slot][k] = read_mem(clip_tos, base_ix + offset.x + offset.y * TILE_WIDTH_PX);
}
clip_tos.offset = read_mem(clip_tos, (clip_tos.offset >> 2) + CLIP_LINK_OFFSET);
blend_spill--;
}
blend_sp--;
for (uint k = 0; k < CHUNK; k++) { for (uint k = 0; k < CHUNK; k++) {
vec4 rgba = unpacksRGB(blend_stack[blend_slot][k]); uvec2 offset = chunk_offset(k);
uint state = read_mem(scratch_alloc, base_ix + offset.x + offset.y * TILE_WIDTH_PX);
vec4 rgba = unpacksRGB(state);
rgb[k] = mix(rgba.rgb, rgb[k], area[k] * rgba.a); rgb[k] = mix(rgba.rgb, rgb[k], area[k] * rgba.a);
} }
cmd_ref.offset += 4; cmd_ref.offset += 4;

Binary file not shown.

View file

@ -21,7 +21,11 @@ layout(set = 0, binding = 0) buffer Memory {
#define ERR_OUT_OF_BOUNDS 2 #define ERR_OUT_OF_BOUNDS 2
#define ERR_UNALIGNED_ACCESS 3 #define ERR_UNALIGNED_ACCESS 3
#ifdef MEM_DEBUG
#define Alloc_size 16
#else
#define Alloc_size 8 #define Alloc_size 8
#endif
// Alloc represents a memory allocation. // Alloc represents a memory allocation.
struct Alloc { struct Alloc {
@ -39,7 +43,7 @@ struct MallocResult {
bool failed; bool failed;
}; };
// new_alloc synthesizes an Alloc when its offset and size are derived. // new_alloc synthesizes an Alloc from an offset and size.
Alloc new_alloc(uint offset, uint size) { Alloc new_alloc(uint offset, uint size) {
Alloc a; Alloc a;
a.offset = offset; a.offset = offset;
@ -118,3 +122,21 @@ Alloc slice_mem(Alloc a, uint offset, uint size) {
#endif #endif
return new_alloc(a.offset + offset, size); return new_alloc(a.offset + offset, size);
} }
// alloc_write writes alloc to memory at offset bytes.
void alloc_write(Alloc a, uint offset, Alloc alloc) {
write_mem(a, offset >> 2, alloc.offset);
#ifdef MEM_DEBUG
write_mem(a, (offset >> 2) + 1, alloc.size);
#endif
}
// alloc_read reads an Alloc from memory at offset bytes.
Alloc alloc_read(Alloc a, uint offset) {
Alloc alloc;
alloc.offset = read_mem(a, offset >> 2);
#ifdef MEM_DEBUG
alloc.size = read_mem(a, (offset >> 2) + 1);
#endif
return alloc;
}