Remove manual blend stack spilling and rely on scratch memory instead

v2: Add a panic when the nested blend depth exceeds the limit.
v3: Rebase and partially remove code introduced in 22507de.
This commit is contained in:
Ishi Tatsuyuki 2021-03-30 12:59:49 +09:00 committed by Tatsuyuki Ishi
parent 379fb1caaa
commit 7a2dc37d36
7 changed files with 17 additions and 35 deletions

View file

@ -148,12 +148,6 @@ 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;
bool mem_ok = mem_error == NO_ERROR; bool mem_ok = mem_error == NO_ERROR;
while (true) { while (true) {
for (uint i = 0; i < N_SLICE; i++) { for (uint i = 0; i < N_SLICE; i++) {
@ -373,8 +367,6 @@ 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;
@ -386,7 +378,6 @@ 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;
} }
@ -414,13 +405,5 @@ 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 state per BeginClip per rasterizer chunk.
uint scratch_size = num_begin_slots * TILE_WIDTH_PX * TILE_HEIGHT_PX * CLIP_STATE_SIZE * 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

@ -37,6 +37,7 @@ layout(rgba8, set = 0, binding = 3) uniform restrict readonly image2D images[1];
#include "ptcl.h" #include "ptcl.h"
#include "tile.h" #include "tile.h"
#define MAX_BLEND_STACK 128
mediump vec3 tosRGB(mediump vec3 rgb) { mediump vec3 tosRGB(mediump vec3 rgb) {
bvec3 cutoff = greaterThanEqual(rgb, vec3(0.0031308)); bvec3 cutoff = greaterThanEqual(rgb, vec3(0.0031308));
mediump vec3 below = vec3(12.92)*rgb; mediump vec3 below = vec3(12.92)*rgb;
@ -90,13 +91,11 @@ 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);
mediump vec4 rgba[CHUNK]; mediump vec4 rgba[CHUNK];
uint blend_stack[MAX_BLEND_STACK][CHUNK];
mediump float blend_alpha_stack[MAX_BLEND_STACK][CHUNK];
for (uint i = 0; i < CHUNK; i++) { for (uint i = 0; i < CHUNK; i++) {
rgba[i] = vec4(0.0); rgba[i] = vec4(0.0);
// TODO: remove this debug image support when the actual image method is plumbed. // TODO: remove this debug image support when the actual image method is plumbed.
@ -208,14 +207,12 @@ void main() {
cmd_ref.offset += 4 + CmdImage_size; cmd_ref.offset += 4 + CmdImage_size;
break; break;
case Cmd_BeginClip: case Cmd_BeginClip:
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++) { for (uint k = 0; k < CHUNK; k++) {
uvec2 offset = chunk_offset(k); // We reject any inputs that might overflow in render_ctx.rs.
uint srgb = packsRGB(vec4(rgba[k])); // The following is a sanity check so we don't corrupt memory should there be malformed inputs.
mediump float alpha = clamp(abs(area[k]), 0.0, 1.0); uint d = min(clip_depth, MAX_BLEND_STACK - 1);
write_mem(scratch_alloc, base_ix + 0 + CLIP_STATE_SIZE * (offset.x + offset.y * TILE_WIDTH_PX), srgb); blend_stack[d][k] = packsRGB(vec4(rgba[k]));
write_mem(scratch_alloc, base_ix + 1 + CLIP_STATE_SIZE * (offset.x + offset.y * TILE_WIDTH_PX), floatBitsToUint(alpha)); blend_alpha_stack[d][k] = clamp(abs(area[k]), 0.0, 1.0);
rgba[k] = vec4(0.0); rgba[k] = vec4(0.0);
} }
clip_depth++; clip_depth++;
@ -223,14 +220,10 @@ void main() {
break; break;
case Cmd_EndClip: case Cmd_EndClip:
clip_depth--; 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++) { for (uint k = 0; k < CHUNK; k++) {
uvec2 offset = chunk_offset(k); uint d = min(clip_depth, MAX_BLEND_STACK - 1);
uint srgb = read_mem(scratch_alloc, base_ix + 0 + CLIP_STATE_SIZE * (offset.x + offset.y * TILE_WIDTH_PX)); mediump vec4 bg = unpacksRGB(blend_stack[d][k]);
uint alpha = read_mem(scratch_alloc, base_ix + 1 + CLIP_STATE_SIZE * (offset.x + offset.y * TILE_WIDTH_PX)); mediump vec4 fg = rgba[k] * area[k] * blend_alpha_stack[d][k];
mediump vec4 bg = unpacksRGB(srgb);
mediump vec4 fg = rgba[k] * area[k] * uintBitsToFloat(alpha);
rgba[k] = bg * (1.0 - fg.a) + fg; rgba[k] = bg * (1.0 - fg.a) + fg;
} }
cmd_ref.offset += 4; cmd_ref.offset += 4;

Binary file not shown.

Binary file not shown.

View file

@ -30,6 +30,8 @@ const WIDTH_IN_TILES: usize = 128;
const HEIGHT_IN_TILES: usize = 96; const HEIGHT_IN_TILES: usize = 96;
const PTCL_INITIAL_ALLOC: usize = 1024; const PTCL_INITIAL_ALLOC: usize = 1024;
const MAX_BLEND_STACK: usize = 128;
const N_CIRCLES: usize = 0; const N_CIRCLES: usize = 0;
pub fn render_svg(rc: &mut impl RenderContext, filename: &str, scale: f64) { pub fn render_svg(rc: &mut impl RenderContext, filename: &str, scale: f64) {

View file

@ -8,6 +8,7 @@ use piet::{
Color, Error, FixedGradient, FontFamily, HitTestPoint, ImageFormat, InterpolationMode, Color, Error, FixedGradient, FontFamily, HitTestPoint, ImageFormat, InterpolationMode,
IntoBrush, LineMetric, RenderContext, StrokeStyle, Text, TextLayout, TextLayoutBuilder, IntoBrush, LineMetric, RenderContext, StrokeStyle, Text, TextLayout, TextLayoutBuilder,
}; };
use crate::MAX_BLEND_STACK;
use piet_gpu_types::encoder::{Encode, Encoder}; use piet_gpu_types::encoder::{Encode, Encoder};
use piet_gpu_types::scene::{ use piet_gpu_types::scene::{
@ -211,6 +212,9 @@ impl RenderContext for PietGpuRenderContext {
self.elements.push(Element::BeginClip(Clip { self.elements.push(Element::BeginClip(Clip {
bbox: Default::default(), bbox: Default::default(),
})); }));
if self.clip_stack.len() >= MAX_BLEND_STACK {
panic!("Maximum clip/blend stack size {} exceeded", MAX_BLEND_STACK);
}
self.clip_stack.push(ClipElement { self.clip_stack.push(ClipElement {
bbox: None, bbox: None,
begin_ix, begin_ix,