From f0127812eb31d4fc0cad331838eb727982002ee4 Mon Sep 17 00:00:00 2001 From: Elias Naur Date: Thu, 18 Mar 2021 20:17:04 +0100 Subject: [PATCH] tightly pack fine rasterizer commands Reclaims the space waste from splitting fill mode commands from fill commands. For example, a CmdStroke + CmdColor use an extra tag word compared to the former combined CmdStroke. This change shaves off that one word. In the future, we can pack several command tags into one tag word, saving even more space. Fixes #66 Signed-off-by: Elias Naur --- piet-gpu/shader/coarse.comp | 22 ++++++++++++++-------- piet-gpu/shader/coarse.spv | Bin 57852 -> 58380 bytes piet-gpu/shader/kernel4.comp | 9 ++++++++- piet-gpu/shader/kernel4.spv | Bin 37712 -> 38328 bytes 4 files changed, 22 insertions(+), 9 deletions(-) diff --git a/piet-gpu/shader/coarse.comp b/piet-gpu/shader/coarse.comp index 860be2e..a4837bd 100644 --- a/piet-gpu/shader/coarse.comp +++ b/piet-gpu/shader/coarse.comp @@ -324,16 +324,18 @@ void main() { if (tile.tile.offset != 0) { CmdFill cmd_fill = CmdFill(tile.tile.offset, tile.backdrop); Cmd_Fill_write(cmd_alloc, cmd_ref, cmd_fill); + cmd_ref.offset += 4 + CmdFill_size; } else { Cmd_Solid_write(cmd_alloc, cmd_ref); + cmd_ref.offset += 4; } } else { CmdStroke cmd_stroke = CmdStroke(tile.tile.offset, 0.5 * fill.linewidth); Cmd_Stroke_write(cmd_alloc, cmd_ref, cmd_stroke); + cmd_ref.offset += 4 + CmdStroke_size; } - cmd_ref.offset += Cmd_size; Cmd_Color_write(cmd_alloc, cmd_ref, CmdColor(fill.rgba_color)); - cmd_ref.offset += Cmd_size; + cmd_ref.offset += 4 + CmdColor_size; break; case Annotated_Image: tile = Tile_read(read_tile_alloc(element_ref_ix), TileRef(sh_tile_base[element_ref_ix] @@ -346,16 +348,18 @@ void main() { if (tile.tile.offset != 0) { CmdFill cmd_fill = CmdFill(tile.tile.offset, tile.backdrop); Cmd_Fill_write(cmd_alloc, cmd_ref, cmd_fill); + cmd_ref.offset += 4 + CmdFill_size; } else { Cmd_Solid_write(cmd_alloc, cmd_ref); + cmd_ref.offset += 4; } } else { CmdStroke cmd_stroke = CmdStroke(tile.tile.offset, 0.5 * fill_img.linewidth); Cmd_Stroke_write(cmd_alloc, cmd_ref, cmd_stroke); + cmd_ref.offset += 4 + CmdStroke_size; } - cmd_ref.offset += Cmd_size; Cmd_Image_write(cmd_alloc, cmd_ref, CmdImage(fill_img.index, fill_img.offset)); - cmd_ref.offset += Cmd_size; + cmd_ref.offset += 4 + CmdImage_size; break; case Annotated_BeginClip: tile = Tile_read(read_tile_alloc(element_ref_ix), TileRef(sh_tile_base[element_ref_ix] @@ -373,18 +377,20 @@ void main() { if (tile.tile.offset != 0) { CmdFill cmd_fill = CmdFill(tile.tile.offset, tile.backdrop); Cmd_Fill_write(cmd_alloc, cmd_ref, cmd_fill); + cmd_ref.offset += 4 + CmdFill_size; } else { // TODO: here is where a bunch of optimization magic should happen float alpha = tile.backdrop == 0 ? 0.0 : 1.0; Cmd_Alpha_write(cmd_alloc, cmd_ref, CmdAlpha(alpha)); + cmd_ref.offset += 4 + CmdAlpha_size; } } else { CmdStroke cmd_stroke = CmdStroke(tile.tile.offset, 0.5 * begin_clip.linewidth); Cmd_Stroke_write(cmd_alloc, cmd_ref, cmd_stroke); + cmd_ref.offset += 4 + CmdStroke_size; } - cmd_ref.offset += Cmd_size; Cmd_BeginClip_write(cmd_alloc, cmd_ref); - cmd_ref.offset += Cmd_size; + cmd_ref.offset += 4; if (clip_depth < 32) { clip_one_mask &= ~(1 << clip_depth); } @@ -398,9 +404,9 @@ void main() { break; } Cmd_Solid_write(cmd_alloc, cmd_ref); - cmd_ref.offset += Cmd_size; + cmd_ref.offset += 4; Cmd_EndClip_write(cmd_alloc, cmd_ref); - cmd_ref.offset += Cmd_size; + cmd_ref.offset += 4; } break; } diff --git a/piet-gpu/shader/coarse.spv b/piet-gpu/shader/coarse.spv index 7e85c00d21ea24504008271f6a538a0d649e516b..763da55dfe178000cde8215b1f25e0e200f1a2dc 100644 GIT binary patch delta 9308 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 W;HPl1(Q=9pEC%>^{&hDE>-K-rn~etm delta 8819 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 diff --git a/piet-gpu/shader/kernel4.comp b/piet-gpu/shader/kernel4.comp index 8e26e1b..b9f59dc 100644 --- a/piet-gpu/shader/kernel4.comp +++ b/piet-gpu/shader/kernel4.comp @@ -153,6 +153,7 @@ void main() { for (uint k = 0; k < CHUNK; k++) { area[k] = clamp(stroke.half_width + 0.5 - df[k], 0.0, 1.0); } + cmd_ref.offset += 4 + CmdStroke_size; break; case Cmd_Fill: CmdFill fill = Cmd_Fill_read(cmd_alloc, cmd_ref); @@ -184,17 +185,20 @@ void main() { for (uint k = 0; k < CHUNK; k++) { area[k] = min(abs(area[k]), 1.0); } + cmd_ref.offset += 4 + CmdFill_size; break; case Cmd_Solid: for (uint k = 0; k < CHUNK; k++) { area[k] = 1.0; } + cmd_ref.offset += 4; break; case Cmd_Alpha: CmdAlpha alpha = Cmd_Alpha_read(cmd_alloc, cmd_ref); for (uint k = 0; k < CHUNK; k++) { area[k] = alpha.alpha; } + cmd_ref.offset += 4 + CmdAlpha_size; break; case Cmd_Color: CmdColor color = Cmd_Color_read(cmd_alloc, cmd_ref); @@ -202,6 +206,7 @@ void main() { for (uint k = 0; k < CHUNK; k++) { rgb[k] = mix(rgb[k], fg_rgba.rgb, mask[k] * area[k] * fg_rgba.a); } + cmd_ref.offset += 4 + CmdColor_size; break; case Cmd_Image: CmdImage fill_img = Cmd_Image_read(cmd_alloc, cmd_ref); @@ -209,6 +214,7 @@ void main() { for (uint k = 0; k < CHUNK; k++) { rgb[k] = mix(rgb[k], rgba[k].rgb, mask[k] * area[k] * rgba[k].a); } + cmd_ref.offset += 4 + CmdImage_size; break; case Cmd_BeginClip: uint blend_slot = blend_sp % BLEND_STACK_SIZE; @@ -229,6 +235,7 @@ void main() { blend_stack[blend_slot][k] = packsRGB(vec4(rgb[k], clamp(abs(area[k]), 0.0, 1.0))); } blend_sp++; + cmd_ref.offset += 4; break; case Cmd_EndClip: blend_slot = (blend_sp - 1) % BLEND_STACK_SIZE; @@ -245,13 +252,13 @@ void main() { vec4 rgba = unpacksRGB(blend_stack[blend_slot][k]); rgb[k] = mix(rgba.rgb, rgb[k], area[k] * rgba.a); } + cmd_ref.offset += 4; break; case Cmd_Jump: cmd_ref = CmdRef(Cmd_Jump_read(cmd_alloc, cmd_ref).new_ref); cmd_alloc.offset = cmd_ref.offset; continue; } - cmd_ref.offset += Cmd_size; } for (uint i = 0; i < CHUNK; i++) { diff --git a/piet-gpu/shader/kernel4.spv b/piet-gpu/shader/kernel4.spv index 91e54ddfff9844a1350488c066010c6c7398e303..5f776e438a537827e3b267d839191e0790d3e4c0 100644 GIT binary patch delta 12783 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