From d916a9e2c418c21c017d2b90051037f53bcc2ee1 Mon Sep 17 00:00:00 2001 From: Elias Naur Date: Tue, 30 Mar 2021 17:16:01 +0200 Subject: [PATCH 01/11] backdrop.comp: support stroked Annotated_Image and Annotated_BeginClip Commit 8db77e180efb1ed178a696d79d885a6e788aa7eb added support for strokes to FillImage and BeginClip, but missed backdrop.comp. Signed-off-by: Elias Naur --- piet-gpu/shader/backdrop.comp | 4 ++-- piet-gpu/shader/backdrop.spv | Bin 11696 -> 11680 bytes piet-gpu/shader/kernel4.spv | Bin 38540 -> 38640 bytes 3 files changed, 2 insertions(+), 2 deletions(-) diff --git a/piet-gpu/shader/backdrop.comp b/piet-gpu/shader/backdrop.comp index 8461275..b640d14 100644 --- a/piet-gpu/shader/backdrop.comp +++ b/piet-gpu/shader/backdrop.comp @@ -48,13 +48,13 @@ void main() { if (element_ix < conf.n_elements) { AnnotatedTag tag = Annotated_tag(conf.anno_alloc, ref); switch (tag.tag) { + case Annotated_Image: + case Annotated_BeginClip: case Annotated_Color: if (fill_mode_from_flags(tag.flags) != MODE_NONZERO) { break; } // Fall through. - case Annotated_Image: - case Annotated_BeginClip: PathRef path_ref = PathRef(conf.tile_alloc.offset + element_ix * Path_size); Path path = Path_read(conf.tile_alloc, path_ref); sh_row_width[th_ix] = path.bbox.z - path.bbox.x; diff --git a/piet-gpu/shader/backdrop.spv b/piet-gpu/shader/backdrop.spv index 9233dd05b0a317bda9720128ae2cdcf25a01080a..26aeb4c052b79c9b0757e2c832a45712534e4db5 100644 GIT binary patch literal 11680 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 BFpmHL delta 6958 zcmZ9Q3z$_^7036?+&erJPzMnld4oU#rerdjCYqsNsbEBy#xNitBBDG>Q#wRiS!U9; z2SyL05HUibhvB2LQnLq@(Zfe+S!#u8B`-nx{mz_4XXbw2p7sC#*Iw)F$J%Gly)SL3 zzi~r-kB0i8T~ew`-BZ^z>h2z^`u3=#=PN1AncKQ(?##B@#=Zj^s_CHGGku$~gR3cB z(YB~V0@bl?rC2Yg=foWX}n7PQTsT?l0mOD_r9k|6?_FKHc9e@QKTx$UbcP%X7;7-uuZRc4f2Uc%%&@S!7 zE#B~d5x)f-Tx$WBxdj~D0b0btwH9&Cvtr4u;&KP8IJhIWh=Xe_;xf00gF8SAIk?tB z4sJdRS>6(RY$Znrt(9En7H{yC_y=s>KK9sQ8ESfk_uqEfDa=K_qu>)besX z+vjGqU1;j^Rq)+l-=pX8Ue&(`tY-5=Vdn=Tp7AO=&&-k!8HRT+!s9$dhn>a{un(*r zeO?3mkZ#m)^w|$rzn(nCVDdQiNleGV)S;$j0JxMvmIfF>|hheCDpu zsl1`(^|b|4nuk|FuGw;Ox@J|l+7_@q^;K&drZm?z)>gJQ9oYq6BQ5%O1*@%3wFjp3 z$qeZRRo=})En+2hVK2uz)2^iLfp0%Ex34E$u5UWNUUK^C^R&xb7}#0(4goL28l%rX zzA@B|Uz6B|Cdi>h0$&GmohCROY=D8j8ssLw6JH%TlDk;wp6~%+HD8^3=p*k(GnvW75jzlUZ16z^kL?`{ zx3C9gMJJ182v|o14F#LTAW!BnurpM*kJUdMtRB^WG+52%r*rj>K#!aje>M`q>epdX zD|r-HJqGeRaC=Z=eqxS+I}r8qi5Lyn7bjv2*j(yyBF2K%iFG0in~$PQ;BT-~9ZjrHSkQ9p~O=19c*Qr+n}Q8cL+%-h5? zSJR}vf!+>RcM!u_4|z=E+z23&q6TnoR(uS}6Zr=kf? z!#V)1BVUG%qWeJM(^_=Pu^*)QF?L1a*T%y?1U5(9iPwSE*7N-Qlq*;ZCiB7K2)-UX zzQjKaHd**TQgG|T|NcG-_l>V^AMeN;!0Hk6F|au%8{~!daftVs4m)|D-3V4cm_3$% z0_;^&DSTc*>NgeoG4`poO>fFRiQ*&uOy&vpy1CHI5ZcN@vl=E*6<*DsLNng}`pxbh z)Uf(IZ@#H+0pEsIk1G5$m@3SYYvwu`sAy+5$BlA*wXqhT0lOAaS)T=~MPcYuGd?zd zIXvP&2ln!b_*K<`DJez*ovYw+fN#xj$j_tPN{g`7U^VZk==lYB`G%CQu07S-oP7yo z-WA1ad>O9hOCfH}+u-WuTT?9t{uOZf)?5Sk6vPerRk(fBy_VKu{p2^K&acrFT~Toi zdtH9D+<~%=7FWx9uv+a#d*$Et}pVdIo<20JaSr~F&kZ`1r(2;V9E+E~wfz~(q`wR{(%7*~t@n>3S| zTpYpofem&b_hRL7wcHQ(YEjp}1*;aZ4}iy)`1in@%CC^`BRJF8pdWxuQoec~gsaC& z{Sa)Ndc^$*Y+U*3`7vBQuAYa$YFYX2c^JWjIvurF%TK^@wLAirJG)1*_V*i$2mPnu zp;-Iqi^KjiFo!)kduME{n*G_Lsri1n%aft9~zz5-W|ubDf* z#;M2G%$;EMXz?v`7n+k9OWW@LJ4!oSnf}wU8|+M6B9~5Xkb7?(xPRK1)gG|3iqrBc zSS<=opPKPeTh>8-5-L1!ua{`H4{0wg(!2&%D_^4f;pIzIZa-7U&o);wbcg19sh*ck z{A}Z|c5;3GY*PWp&o=ykH#HYLwbO7`ajw7`_ZuA=pD{ew^@Og Date: Tue, 30 Mar 2021 19:56:09 +0200 Subject: [PATCH 02/11] coarse.comp: extract area commands into function No functional changes. Signed-off-by: Elias Naur --- piet-gpu/shader/coarse.comp | 64 +++++++++++------------------------- piet-gpu/shader/coarse.spv | Bin 58380 -> 55312 bytes 2 files changed, 20 insertions(+), 44 deletions(-) diff --git a/piet-gpu/shader/coarse.comp b/piet-gpu/shader/coarse.comp index a4837bd..1266ed8 100644 --- a/piet-gpu/shader/coarse.comp +++ b/piet-gpu/shader/coarse.comp @@ -91,6 +91,23 @@ bool alloc_cmd(inout Alloc cmd_alloc, inout CmdRef cmd_ref, inout uint cmd_limit return true; } +void write_fill(Alloc alloc, inout CmdRef cmd_ref, uint flags, Tile tile, float linewidth) { + if (fill_mode_from_flags(flags) == MODE_NONZERO) { + if (tile.tile.offset != 0) { + CmdFill cmd_fill = CmdFill(tile.tile.offset, tile.backdrop); + Cmd_Fill_write(alloc, cmd_ref, cmd_fill); + cmd_ref.offset += 4 + CmdFill_size; + } else { + Cmd_Solid_write(alloc, cmd_ref); + cmd_ref.offset += 4; + } + } else { + CmdStroke cmd_stroke = CmdStroke(tile.tile.offset, 0.5 * linewidth); + Cmd_Stroke_write(alloc, cmd_ref, cmd_stroke); + cmd_ref.offset += 4 + CmdStroke_size; + } +} + void main() { if (mem_error != NO_ERROR) { return; @@ -320,20 +337,7 @@ void main() { if (!alloc_cmd(cmd_alloc, cmd_ref, cmd_limit)) { break; } - if (fill_mode_from_flags(tag.flags) == MODE_NONZERO) { - 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; - } + write_fill(cmd_alloc, cmd_ref, tag.flags, tile, fill.linewidth); Cmd_Color_write(cmd_alloc, cmd_ref, CmdColor(fill.rgba_color)); cmd_ref.offset += 4 + CmdColor_size; break; @@ -344,20 +348,7 @@ void main() { if (!alloc_cmd(cmd_alloc, cmd_ref, cmd_limit)) { break; } - if (fill_mode_from_flags(tag.flags) == MODE_NONZERO) { - 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; - } + write_fill(cmd_alloc, cmd_ref, tag.flags, tile, fill_img.linewidth); Cmd_Image_write(cmd_alloc, cmd_ref, CmdImage(fill_img.index, fill_img.offset)); cmd_ref.offset += 4 + CmdImage_size; break; @@ -373,22 +364,7 @@ void main() { if (!alloc_cmd(cmd_alloc, cmd_ref, cmd_limit)) { break; } - if (fill_mode_from_flags(tag.flags) == MODE_NONZERO) { - 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; - } + write_fill(cmd_alloc, cmd_ref, tag.flags, tile, begin_clip.linewidth); Cmd_BeginClip_write(cmd_alloc, cmd_ref); cmd_ref.offset += 4; if (clip_depth < 32) { diff --git a/piet-gpu/shader/coarse.spv b/piet-gpu/shader/coarse.spv index 763da55dfe178000cde8215b1f25e0e200f1a2dc..65e834780b76dcadf4593b0854cc03b2340ad247 100644 GIT binary patch literal 55312 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ü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 Oa{bCVbT0F3^#1^bvCp~y literal 58380 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 From 22507dea0e15b003bcac8dad215e3e80921ff78a Mon Sep 17 00:00:00 2001 From: Elias Naur Date: Tue, 30 Mar 2021 20:16:36 +0200 Subject: [PATCH 03/11] 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 --- piet-gpu/shader/coarse.comp | 17 ++++++++ piet-gpu/shader/coarse.spv | Bin 55312 -> 56932 bytes piet-gpu/shader/kernel4.comp | 74 ++++++++--------------------------- piet-gpu/shader/kernel4.spv | Bin 38640 -> 35684 bytes piet-gpu/shader/mem.h | 24 +++++++++++- 5 files changed, 57 insertions(+), 58 deletions(-) diff --git a/piet-gpu/shader/coarse.comp b/piet-gpu/shader/coarse.comp index 1266ed8..3d771dd 100644 --- a/piet-gpu/shader/coarse.comp +++ b/piet-gpu/shader/coarse.comp @@ -152,6 +152,12 @@ void main() { uint part_start_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) { for (uint i = 0; i < N_SLICE; i++) { sh_bitmaps[i][th_ix] = 0; @@ -370,6 +376,8 @@ void main() { if (clip_depth < 32) { clip_one_mask &= ~(1 << clip_depth); } + begin_slot++; + num_begin_slots = max(num_begin_slots, begin_slot); } clip_depth++; break; @@ -381,6 +389,7 @@ void main() { } Cmd_Solid_write(cmd_alloc, cmd_ref); cmd_ref.offset += 4; + begin_slot--; Cmd_EndClip_write(cmd_alloc, cmd_ref); 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) { 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); + } } } diff --git a/piet-gpu/shader/coarse.spv b/piet-gpu/shader/coarse.spv index 65e834780b76dcadf4593b0854cc03b2340ad247..5bc80ae834b0f2838de88e16f8745c87559abcbf 100644 GIT binary patch literal 56932 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 UbIS2`4cVq#zj6#6%iJ6NKaR&mt^fc4 literal 55312 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ü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 Oa{bCVbT0F3^#1^bvCp~y diff --git a/piet-gpu/shader/kernel4.comp b/piet-gpu/shader/kernel4.comp index fc2523e..4fe9f76 100644 --- a/piet-gpu/shader/kernel4.comp +++ b/piet-gpu/shader/kernel4.comp @@ -35,30 +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 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) { bvec3 cutoff = greaterThanEqual(rgb, vec3(0.0031308)); 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); 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); vec2 xy = vec2(xy_uint); 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++) { rgb[i] = vec3(0.5); #ifdef ENABLE_IMAGE_INDICES @@ -132,6 +108,7 @@ void main() { } float area[CHUNK]; + uint clip_depth = 0; while (true) { uint tag = Cmd_tag(cmd_alloc, cmd_ref).tag; if (tag == Cmd_End) { @@ -224,41 +201,24 @@ 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) + 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++; - } + uint base_ix = (scratch_alloc.offset >> 2) + 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] = 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; break; case Cmd_EndClip: - blend_slot = (blend_sp - 1) % BLEND_STACK_SIZE; - if (blend_sp == blend_spill) { - 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); - 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--; + clip_depth--; + base_ix = (scratch_alloc.offset >> 2) + 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 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); } cmd_ref.offset += 4; diff --git a/piet-gpu/shader/kernel4.spv b/piet-gpu/shader/kernel4.spv index 8aba85e40eca984f6085a8e9efd13dcec9fda731..5bdc0b4acd8fd7522719ca65906ae25ea9b5e1a2 100644 GIT binary patch literal 35684 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 bHP_1a+SJOu={~Z(=hCfU`|~^#d!GFlo}<)2 literal 38640 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 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; +} From ee4429a26fd08bfd0973646fe2debb60ddf43e4e Mon Sep 17 00:00:00 2001 From: Elias Naur Date: Mon, 22 Mar 2021 16:13:39 +0100 Subject: [PATCH 04/11] kernel4: separate area from alpha in clip stack This change prepares for kernel4 to output alpha. No functional changes. Signed-off-by: Elias Naur --- piet-gpu/shader/coarse.comp | 4 ++-- piet-gpu/shader/coarse.spv | Bin 56932 -> 56952 bytes piet-gpu/shader/kernel4.comp | 21 ++++++++++++--------- piet-gpu/shader/kernel4.spv | Bin 35684 -> 36600 bytes piet-gpu/shader/setup.h | 5 ++++- 5 files changed, 18 insertions(+), 12 deletions(-) diff --git a/piet-gpu/shader/coarse.comp b/piet-gpu/shader/coarse.comp index 3d771dd..76d7fc6 100644 --- a/piet-gpu/shader/coarse.comp +++ b/piet-gpu/shader/coarse.comp @@ -418,8 +418,8 @@ void main() { 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); 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; + // 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. diff --git a/piet-gpu/shader/coarse.spv b/piet-gpu/shader/coarse.spv index 5bc80ae834b0f2838de88e16f8745c87559abcbf..7d0b629ab65764bf26e6147c0dd8e4de7547947f 100644 GIT binary patch delta 441 zcmZ8cu};EZ7`)N~O$jj}FfutqXF?=lVU{N#4GCc(A>iH++;LD*0W07On6A77gRkHV zxXB{k75{~y|9yA&|94-%cJ|NC&fBTWEMUQdi}#QGzS4YjfpK>f+;sa$!@-<<7>t4e zknoo?zC7bmT&{jv);9k3J2^tTKJ}7N_Mpx{p+XHWk}K43p+XIpAH}8C@j47G;Feot zC_V7XJ-->X25j7MmUhJo`A?js$y1$pjc+gLJ##J)rOVepOVe8d7Ca`-$C(D7=Cf(B00R zS+-H^H)qbAGjsOuY~Idh+zg~cfPpB&IG*B{OlcYhy7i9Tt2YpYg&BFROnsgpm#NQ%GWEH1$4!F{Y6w?y8cf+?Gmu!Gq9eT&JZtgSMk3u&0;R+YhKufO$jp7 oo#I;1om> 2) + clip_depth * TILE_WIDTH_PX * TILE_HEIGHT_PX + - gl_LocalInvocationID.x + TILE_WIDTH_PX * gl_LocalInvocationID.y; + 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++) { 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); + uint srgb = packsRGB(vec4(rgb[k], 1.0)); + 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)); } clip_depth++; cmd_ref.offset += 4; break; case Cmd_EndClip: clip_depth--; - base_ix = (scratch_alloc.offset >> 2) + clip_depth * TILE_WIDTH_PX * TILE_HEIGHT_PX + - gl_LocalInvocationID.x + TILE_WIDTH_PX * gl_LocalInvocationID.y; + 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++) { 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); + 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 rgba = unpacksRGB(srgb); + rgb[k] = mix(rgba.rgb, rgb[k], area[k] * uintBitsToFloat(alpha)); } cmd_ref.offset += 4; break; diff --git a/piet-gpu/shader/kernel4.spv b/piet-gpu/shader/kernel4.spv index 5bdc0b4acd8fd7522719ca65906ae25ea9b5e1a2..71b31937dda593380e33cdfe00e1252aa3dd9c7d 100644 GIT binary patch delta 4630 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 Date: Mon, 22 Mar 2021 16:06:15 +0100 Subject: [PATCH 05/11] kernel4: compute and output alpha Signed-off-by: Elias Naur --- piet-gpu/shader/kernel4.comp | 20 +++++++++++--------- piet-gpu/shader/kernel4.spv | Bin 36600 -> 36716 bytes 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/piet-gpu/shader/kernel4.comp b/piet-gpu/shader/kernel4.comp index b0c2a60..b7834cf 100644 --- a/piet-gpu/shader/kernel4.comp +++ b/piet-gpu/shader/kernel4.comp @@ -97,12 +97,12 @@ void main() { 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); - vec3 rgb[CHUNK]; + vec4 rgba[CHUNK]; for (uint i = 0; i < CHUNK; i++) { - rgb[i] = vec3(0.5); + rgba[i] = vec4(0.0); #ifdef ENABLE_IMAGE_INDICES if (xy_uint.x < 1024 && xy_uint.y < 1024) { - rgb[i] = imageLoad(images[gl_WorkGroupID.x / 64], ivec2(xy_uint + chunk_offset(i))/4).rgb; + rgba[i] = imageLoad(images[gl_WorkGroupID.x / 64], ivec2(xy_uint + chunk_offset(i))/4); } #endif } @@ -187,7 +187,7 @@ void main() { vec4 fg = unpacksRGB(color.rgba_color); for (uint k = 0; k < CHUNK; k++) { vec4 fg_k = fg * area[k]; - rgb[k] = rgb[k] * (1.0 - fg_k.a) + fg_k.rgb; + rgba[k] = rgba[k] * (1.0 - fg_k.a) + fg_k; } cmd_ref.offset += 4 + CmdColor_size; break; @@ -196,7 +196,7 @@ void main() { vec4 img[CHUNK] = fillImage(xy_uint, fill_img); for (uint k = 0; k < CHUNK; k++) { vec4 fg_k = img[k] * area[k]; - rgb[k] = rgb[k] * (1.0 - fg_k.a) + fg_k.rgb; + rgba[k] = rgba[k] * (1.0 - fg_k.a) + fg_k; } cmd_ref.offset += 4 + CmdImage_size; break; @@ -205,10 +205,11 @@ void main() { gl_LocalInvocationID.x + TILE_WIDTH_PX * gl_LocalInvocationID.y); for (uint k = 0; k < CHUNK; k++) { uvec2 offset = chunk_offset(k); - uint srgb = packsRGB(vec4(rgb[k], 1.0)); + 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); } clip_depth++; cmd_ref.offset += 4; @@ -221,8 +222,9 @@ void main() { 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 rgba = unpacksRGB(srgb); - rgb[k] = mix(rgba.rgb, rgb[k], area[k] * uintBitsToFloat(alpha)); + vec4 bg = unpacksRGB(srgb); + vec4 fg = rgba[k] * area[k] * uintBitsToFloat(alpha); + rgba[k] = bg * (1.0 - fg.a) + fg; } cmd_ref.offset += 4; break; @@ -234,6 +236,6 @@ void main() { } for (uint i = 0; i < CHUNK; i++) { - imageStore(image, ivec2(xy_uint + chunk_offset(i)), vec4(tosRGB(rgb[i]), 1.0)); + imageStore(image, ivec2(xy_uint + chunk_offset(i)), vec4(tosRGB(rgba[i].rgb), rgba[i].a)); } } diff --git a/piet-gpu/shader/kernel4.spv b/piet-gpu/shader/kernel4.spv index 71b31937dda593380e33cdfe00e1252aa3dd9c7d..af7fe183c6b89ca9d5e0c89b172b53b55c6baba7 100644 GIT binary patch literal 36716 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 literal 36600 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 Date: Thu, 8 Apr 2021 19:55:44 +0200 Subject: [PATCH 06/11] elements.comp: don't modify BeginClip bounding box The BeginClip and EndClip bounding boxes are absolute and must pairwise match. I mistakenly modified the BeginClip bounding box for stroked clips. Signed-off-by: Elias Naur --- piet-gpu/shader/elements.comp | 4 ++-- piet-gpu/shader/elements.spv | Bin 71296 -> 71120 bytes 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/piet-gpu/shader/elements.comp b/piet-gpu/shader/elements.comp index 7fb02fc..56ad6e2 100644 --- a/piet-gpu/shader/elements.comp +++ b/piet-gpu/shader/elements.comp @@ -386,10 +386,10 @@ void main() { case Element_BeginClip: Clip begin_clip = Element_BeginClip_read(this_ref); AnnoBeginClip anno_begin_clip; + // This is the absolute bbox, it's been transformed during encoding. + anno_begin_clip.bbox = begin_clip.bbox; if (is_stroke) { vec2 lw = get_linewidth(st); - // This is the absolute bbox, it's been transformed during encoding. - anno_begin_clip.bbox = begin_clip.bbox + vec4(-lw, lw); anno_begin_clip.linewidth = st.linewidth * sqrt(abs(st.mat.x * st.mat.w - st.mat.y * st.mat.z)); } else { anno_begin_clip.bbox = begin_clip.bbox; diff --git a/piet-gpu/shader/elements.spv b/piet-gpu/shader/elements.spv index d1ca8dd4f2d9240477bf14ab198f8eff4b1beb20..6bd53b3ec06e76cc0bb53bf1053246fa7bb70323 100644 GIT binary patch delta 2410 zcmZ9OOKeni6voeVX4;v-QYK9^nl22%ZbXzZnn+Y)U1&5h(ztSkO)UwL@)$_EFy>Z^ zx^v;(xG|x=5i7zJ6}4ckQpFdb_yAGr0~ADq589$uzu%pE%^b4}-IeY>tMT{h z_(yg8Kpj6chiC0G@!qv}uk2Z~dcB1U%WcYgB)qR&3Qo-N%-HEVer68O+F9{UmF~40 zSFNkms>|AxYbz_gtKy0q=FPo>raGRl@oMXpV-2YV)x%eq=C+fPXnDl z)L>BqV;)$$96nDt>=i$f;3TB49$-S8zB&j}`a!VT=pX=2|UF<3Sxmo>~lI>$_w9;@HRIz9yaf!tVF} zdciJ_rqL5mLxSNrqYl%3I!(uYdZWy=dykaSgt}KaIa4@3p5{&A7A?;Lze^`4nT2ef zI!>3WlCiLBpuPB(l(9(7M$hDUcyMFu>bIqgYdxUW@Pxi2jJ8DkHpkjNar9esYzJa( zLY#=$R;X$FwD(BD*XoL+d?1X*kGqqjeJIYu?I#+J zABTx79}5$mEIjmZY*c?x_=fo8@&bTk8nmtbafn(R|K4g;ZAvfDg3am=tSkEjOOD#DvZXhP)3)0zY<5MX?w(v38S%}R}S0< z_jSR-I|eQ)ej`oz{}vsOMmH(txR#IZTVb^1=)Mz2Pmb<;aUx>#(fuHdP8Bp4?xQ;y zjqXP&C$)TZKMAAp^U<9WKcVHLgX8C;`&rmWcUl;ZjXwM$%>7dVuTuCj9bl&OYr*E* zqyWL$cqV-O{`TNEAzn4f_Wmvnos#&B{1N-`tdL6YF#A&)`U?3>i=Pu_A3EvJ>Wb!L zm=PX~^YBHB^99k7J1+qT@4;Wf6ty{BOUSYOTN=7g>K|dWDYXDSz$DOUU;K8-y|O%96w@^I43-%Lg)~m zs@yfPkroz&X&XlV5rF&j<_XWrC;H$C=fl3i#U1m7I#in9Yl}FVztpg`R7VHLAN>y_ C{AUmV delta 2611 zcmZ9OTWnNS6o%JKXWGudfYWNGwI;@3UqqA|O(ZI@z8Fo6<ijGy0-^VljQuf&_{>3alGJ~h>Yw`BZdt2KsA!9UI%8t))s^ zKW6dq89Z%M;%mE$ookkNbx&_2Z8j&?TD#kq$Ft3m_WxE>cEK!OGtEo2*X&Iu>Py4d zcI7ThNXsaGp-NS$XO(!Jo>z)xs?F+4?YCTA6%-Q|RaK?78|3bQPc5y1}T#-ga zoezmqQRhraMV%8*MV&vAw5Xyn53E5BRMQ>yh>w+VCZw)z9}=go&he+N&d-WdSLYMr z)YLiosOK~JB8RDQ&v_&c(q^Du`0qQ~GnOb~a%Z_B4WiQ?jA=YaGy+v}A;d z31xp)+9Jg)RSX4%FVTU#T(;+gFH+&rv2(1^nq_ZOfnE@PGHYSgx?HeH7*1YdUlhha zi1}t=G`GJL+m|WV0{L$d$A_P5FUOjea9(>w8nOJ`@71i`ABi}&s6xy1+$txMl7t{R z*+ZHP+iSus7$4tENthGVq$F$>jvw|WZFZY5g*q9oexNqftmBEgBOF~_$iFVzj>vaf z-5K`x6dK=!k(ce_7pS4HJ$i_0Owa6GH?!`b2-ah|+< zgJEJ_ZE;A-V43=^aCuST`1myM3D4K?S>Si;gqP34Y|U!w6+Xzc1xrq^6_0 z<4|~HO>M^qQVwaXS82FOJ`_eS_K`UHZF;?WW9_gw8L_pfXoHG9B8<*KxKU3y zEqhD{;AnWq+CuP&l%pD)L1r5kM&rlsMCN>83`5&bTpD)pgsC6f$ zoY3&r{UnT5-nyT~(aT$RN}PC-l=MFbUx+&l4XR+kBv@^D_2$+eW~eRCcb?L-m1C6pc=F8}}l From 115cb855d9271a2135f9bbc7a70f15e910498e13 Mon Sep 17 00:00:00 2001 From: Raph Levien Date: Fri, 2 Apr 2021 18:59:07 -0700 Subject: [PATCH 07/11] Query extensions at runtime Don't run extensions unless they're available. This includes querying for descriptor indexing, and running one of two versions of kernel4 depending on whether it's enabled. Part of the support needed for #78 --- Cargo.lock | 1 - piet-gpu-derive/src/glsl.rs | 11 +- piet-gpu-hal/Cargo.toml | 1 - piet-gpu-hal/src/hub.rs | 7 + piet-gpu-hal/src/vulkan.rs | 240 ++++++++++++++++++++------------ piet-gpu/bin/winit.rs | 3 +- piet-gpu/shader/build.ninja | 5 +- piet-gpu/shader/kernel4.comp | 11 +- piet-gpu/shader/kernel4.spv | Bin 36716 -> 36004 bytes piet-gpu/shader/kernel4_idx.spv | Bin 0 -> 36108 bytes piet-gpu/shader/setup.h | 3 +- piet-gpu/src/lib.rs | 70 ++++++---- piet-gpu/src/render_ctx.rs | 26 ++-- 13 files changed, 246 insertions(+), 132 deletions(-) create mode 100644 piet-gpu/shader/kernel4_idx.spv diff --git a/Cargo.lock b/Cargo.lock index 8201647..30a5dc6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -797,7 +797,6 @@ version = "0.1.0" dependencies = [ "ash", "ash-window", - "once_cell", "raw-window-handle", ] diff --git a/piet-gpu-derive/src/glsl.rs b/piet-gpu-derive/src/glsl.rs index d9f08f3..2283ae6 100644 --- a/piet-gpu-derive/src/glsl.rs +++ b/piet-gpu-derive/src/glsl.rs @@ -157,7 +157,12 @@ fn gen_enum_read( writeln!(r, "{}Tag {}_tag({}Ref ref) {{", name, name, name).unwrap(); writeln!(r, " uint tag_and_flags = {}[ref.offset >> 2];", bufname).unwrap(); } - writeln!(r, " return {}Tag(tag_and_flags & 0xffff, tag_and_flags >> 16);", name).unwrap(); + writeln!( + r, + " return {}Tag(tag_and_flags & 0xffff, tag_and_flags >> 16);", + name + ) + .unwrap(); writeln!(r, "}}\n").unwrap(); for (var_name, payload) in variants { let payload_ix = if payload.len() == 1 { @@ -564,7 +569,9 @@ fn gen_enum_write( } writeln!(r, "}}\n").unwrap(); } - } else if payload.len() == 2 && matches!(payload[0].1.ty, GpuType::Scalar(GpuScalar::TagFlags)) { + } else if payload.len() == 2 + && matches!(payload[0].1.ty, GpuType::Scalar(GpuScalar::TagFlags)) + { if let GpuType::InlineStruct(structname) = &payload[1].1.ty { if is_mem { writeln!( diff --git a/piet-gpu-hal/Cargo.toml b/piet-gpu-hal/Cargo.toml index 9ebd772..bef3548 100644 --- a/piet-gpu-hal/Cargo.toml +++ b/piet-gpu-hal/Cargo.toml @@ -8,6 +8,5 @@ edition = "2018" [dependencies] ash = "0.31" -once_cell = "1.3.1" ash-window = "0.5" raw-window-handle = "0.3" diff --git a/piet-gpu-hal/src/hub.rs b/piet-gpu-hal/src/hub.rs index a52040f..5649546 100644 --- a/piet-gpu-hal/src/hub.rs +++ b/piet-gpu-hal/src/hub.rs @@ -209,6 +209,13 @@ impl Session { pub unsafe fn create_sampler(&self, params: SamplerParams) -> Result { self.0.device.create_sampler(params) } + + /// Report whether the device supports descriptor indexing. + /// + /// As we have more queries, we might replace this with a capabilities structure. + pub fn has_descriptor_indexing(&self) -> bool { + self.0.device.has_descriptor_indexing + } } impl CmdBuf { diff --git a/piet-gpu-hal/src/vulkan.rs b/piet-gpu-hal/src/vulkan.rs index 20d15e4..bddbedc 100644 --- a/piet-gpu-hal/src/vulkan.rs +++ b/piet-gpu-hal/src/vulkan.rs @@ -2,12 +2,12 @@ use std::borrow::Cow; use std::ffi::{CStr, CString}; +use std::os::raw::c_char; use std::sync::Arc; use ash::extensions::{ext::DebugUtils, khr}; use ash::version::{DeviceV1_0, EntryV1_0, InstanceV1_0}; use ash::{vk, Device, Entry, Instance}; -use once_cell::sync::Lazy; use crate::{Device as DeviceTrait, Error, ImageLayout, SamplerParams}; @@ -16,6 +16,7 @@ pub struct VkInstance { #[allow(unused)] entry: Entry, instance: Instance, + get_phys_dev_props: Option, _dbg_loader: Option, _dbg_callbk: Option, } @@ -27,6 +28,8 @@ pub struct VkDevice { queue: vk::Queue, qfi: u32, timestamp_period: f32, + /// Does the device support descriptor indexing? + pub has_descriptor_indexing: bool, } struct RawDevice { @@ -95,6 +98,7 @@ pub struct PipelineBuilder { bindings: Vec, binding_flags: Vec, max_textures: u32, + has_descriptor_indexing: bool, } pub struct DescriptorSetBuilder { @@ -104,6 +108,16 @@ pub struct DescriptorSetBuilder { sampler: vk::Sampler, } +struct Extensions { + exts: Vec<*const c_char>, + exist_exts: Vec, +} + +struct Layers { + layers: Vec<*const c_char>, + exist_layers: Vec, +} + unsafe extern "system" fn vulkan_debug_callback( message_severity: vk::DebugUtilsMessageSeverityFlagsEXT, message_type: vk::DebugUtilsMessageTypeFlagsEXT, @@ -133,24 +147,6 @@ unsafe extern "system" fn vulkan_debug_callback( vk::FALSE } -static LAYERS: Lazy> = Lazy::new(|| { - let mut layers: Vec<&'static CStr> = vec![]; - if cfg!(debug_assertions) { - layers.push(CStr::from_bytes_with_nul(b"VK_LAYER_KHRONOS_validation\0").unwrap()); - } - layers -}); - -static EXTS: Lazy> = Lazy::new(|| { - let mut exts: Vec<&'static CStr> = vec![]; - if cfg!(debug_assertions) { - exts.push(DebugUtils::name()); - } - // We'll need this to do runtime query of descriptor indexing. - //exts.push(vk::KhrGetPhysicalDeviceProperties2Fn::name()); - exts -}); - impl VkInstance { /// Create a new instance. /// @@ -166,50 +162,24 @@ impl VkInstance { let app_name = CString::new("VkToy").unwrap(); let entry = Entry::new()?; - let exist_layers = entry.enumerate_instance_layer_properties()?; - let layers = LAYERS - .iter() - .filter_map(|&lyr| { - exist_layers - .iter() - .find(|x| CStr::from_ptr(x.layer_name.as_ptr()) == lyr) - .map(|_| lyr.as_ptr()) - .or_else(|| { - println!( - "Unable to find layer: {}, have you installed the Vulkan SDK?", - lyr.to_string_lossy() - ); - None - }) - }) - .collect::>(); - - let exist_exts = entry.enumerate_instance_extension_properties()?; - let mut exts = EXTS - .iter() - .filter_map(|&ext| { - exist_exts - .iter() - .find(|x| CStr::from_ptr(x.extension_name.as_ptr()) == ext) - .map(|_| ext.as_ptr()) - .or_else(|| { - println!( - "Unable to find extension: {}, have you installed the Vulkan SDK?", - ext.to_string_lossy() - ); - None - }) - }) - .collect::>(); - - let surface_extensions = match window_handle { - Some(ref handle) => ash_window::enumerate_required_extensions(*handle)?, - None => vec![], - }; - for extension in surface_extensions { - exts.push(extension.as_ptr()); + let mut layers = Layers::new(entry.enumerate_instance_layer_properties()?); + if cfg!(debug_assertions) { + layers + .try_add(CStr::from_bytes_with_nul(b"VK_LAYER_KHRONOS_validation\0").unwrap()); + } + + let mut exts = Extensions::new(entry.enumerate_instance_extension_properties()?); + let mut has_debug_ext = false; + if cfg!(debug_assertions) { + has_debug_ext = exts.try_add(DebugUtils::name()); + } + // We'll need this to do runtime query of descriptor indexing. + let has_phys_dev_props = exts.try_add(vk::KhrGetPhysicalDeviceProperties2Fn::name()); + if let Some(ref handle) = window_handle { + for ext in ash_window::enumerate_required_extensions(*handle)? { + exts.try_add(ext); + } } - exts.push(vk::KhrGetPhysicalDeviceProperties2Fn::name().as_ptr()); let instance = entry.create_instance( &vk::InstanceCreateInfo::builder() @@ -220,12 +190,12 @@ impl VkInstance { .engine_name(&app_name) .api_version(vk::make_version(1, 0, 0)), ) - .enabled_layer_names(&layers) - .enabled_extension_names(&exts), + .enabled_layer_names(layers.as_ptrs()) + .enabled_extension_names(exts.as_ptrs()), None, )?; - let (_dbg_loader, _dbg_callbk) = if cfg!(debug_assertions) { + let (_dbg_loader, _dbg_callbk) = if has_debug_ext { let dbg_info = vk::DebugUtilsMessengerCreateInfoEXT::builder() .message_severity( vk::DebugUtilsMessageSeverityFlagsEXT::ERROR @@ -250,9 +220,20 @@ impl VkInstance { None => None, }; + let get_phys_dev_props = if has_phys_dev_props { + Some(vk::KhrGetPhysicalDeviceProperties2Fn::load(|name| { + std::mem::transmute( + entry.get_instance_proc_addr(instance.handle(), name.as_ptr()), + ) + })) + } else { + None + }; + let vk_instance = VkInstance { entry, instance, + get_phys_dev_props, _dbg_loader, _dbg_callbk, }; @@ -273,14 +254,30 @@ impl VkInstance { let (pdevice, qfi) = choose_compute_device(&self.instance, &devices, surface).ok_or("no suitable device")?; + let mut has_descriptor_indexing = false; + if let Some(ref get_phys_dev_props) = self.get_phys_dev_props { + let mut descriptor_indexing_features = + vk::PhysicalDeviceDescriptorIndexingFeatures::builder(); + // See https://github.com/MaikKlein/ash/issues/325 for why we do this workaround. + let mut features_v2 = vk::PhysicalDeviceFeatures2::default(); + features_v2.p_next = + &mut descriptor_indexing_features as *mut _ as *mut std::ffi::c_void; + get_phys_dev_props.get_physical_device_features2_khr(pdevice, &mut features_v2); + has_descriptor_indexing = descriptor_indexing_features + .shader_storage_image_array_non_uniform_indexing + == vk::TRUE + && descriptor_indexing_features.descriptor_binding_variable_descriptor_count + == vk::TRUE + && descriptor_indexing_features.runtime_descriptor_array == vk::TRUE; + } + let queue_priorities = [1.0]; let queue_create_infos = [vk::DeviceQueueCreateInfo::builder() .queue_family_index(qfi) .queue_priorities(&queue_priorities) .build()]; - // support for descriptor indexing (maybe should be optional for compatibility) - let descriptor_indexing = vk::PhysicalDeviceDescriptorIndexingFeatures::builder() + let mut descriptor_indexing = vk::PhysicalDeviceDescriptorIndexingFeatures::builder() .shader_storage_image_array_non_uniform_indexing(true) .descriptor_binding_variable_descriptor_count(true) .runtime_descriptor_array(true); @@ -291,11 +288,12 @@ impl VkInstance { }; extensions.push(vk::ExtDescriptorIndexingFn::name().as_ptr()); extensions.push(vk::KhrMaintenance3Fn::name().as_ptr()); - let create_info = vk::DeviceCreateInfo::builder() + let mut create_info = vk::DeviceCreateInfo::builder() .queue_create_infos(&queue_create_infos) - .enabled_extension_names(&extensions) - .push_next(&mut descriptor_indexing.build()) - .build(); + .enabled_extension_names(&extensions); + if has_descriptor_indexing { + create_info = create_info.push_next(&mut descriptor_indexing); + } let device = self.instance.create_device(pdevice, &create_info, None)?; let device_mem_props = self.instance.get_physical_device_memory_properties(pdevice); @@ -315,6 +313,7 @@ impl VkInstance { qfi, queue, timestamp_period, + has_descriptor_indexing, }) } @@ -569,6 +568,7 @@ impl crate::Device for VkDevice { bindings: Vec::new(), binding_flags: Vec::new(), max_textures: 0, + has_descriptor_indexing: self.has_descriptor_indexing, } } @@ -711,21 +711,23 @@ impl crate::Device for VkDevice { SamplerParams::Linear => vk::Filter::LINEAR, SamplerParams::Nearest => vk::Filter::NEAREST, }; - let sampler = device.create_sampler(&vk::SamplerCreateInfo::builder() - .mag_filter(filter) - .min_filter(filter) - .mipmap_mode(vk::SamplerMipmapMode::LINEAR) - .address_mode_u(vk::SamplerAddressMode::CLAMP_TO_BORDER) - .address_mode_v(vk::SamplerAddressMode::CLAMP_TO_BORDER) - .address_mode_w(vk::SamplerAddressMode::CLAMP_TO_BORDER) - .mip_lod_bias(0.0) - .compare_op(vk::CompareOp::NEVER) - .min_lod(0.0) - .max_lod(0.0) - .border_color(vk::BorderColor::FLOAT_TRANSPARENT_BLACK) - .max_anisotropy(1.0) - .anisotropy_enable(false) - , None)?; + let sampler = device.create_sampler( + &vk::SamplerCreateInfo::builder() + .mag_filter(filter) + .min_filter(filter) + .mipmap_mode(vk::SamplerMipmapMode::LINEAR) + .address_mode_u(vk::SamplerAddressMode::CLAMP_TO_BORDER) + .address_mode_v(vk::SamplerAddressMode::CLAMP_TO_BORDER) + .address_mode_w(vk::SamplerAddressMode::CLAMP_TO_BORDER) + .mip_lod_bias(0.0) + .compare_op(vk::CompareOp::NEVER) + .min_lod(0.0) + .max_lod(0.0) + .border_color(vk::BorderColor::FLOAT_TRANSPARENT_BLACK) + .max_anisotropy(1.0) + .anisotropy_enable(false), + None, + )?; Ok(sampler) } } @@ -1007,8 +1009,12 @@ impl crate::PipelineBuilder for PipelineBuilder { .stage_flags(vk::ShaderStageFlags::COMPUTE) .build(), ); - self.binding_flags - .push(vk::DescriptorBindingFlags::VARIABLE_DESCRIPTOR_COUNT); + let flags = if self.has_descriptor_indexing { + vk::DescriptorBindingFlags::VARIABLE_DESCRIPTOR_COUNT + } else { + Default::default() + }; + self.binding_flags.push(flags); self.max_textures += max_textures; } @@ -1231,6 +1237,64 @@ impl VkSwapchain { } } +impl Extensions { + fn new(exist_exts: Vec) -> Extensions { + Extensions { + exist_exts, + exts: vec![], + } + } + + fn try_add(&mut self, ext: &'static CStr) -> bool { + unsafe { + if self + .exist_exts + .iter() + .find(|x| CStr::from_ptr(x.extension_name.as_ptr()) == ext) + .is_some() + { + self.exts.push(ext.as_ptr()); + true + } else { + false + } + } + } + + fn as_ptrs(&self) -> &[*const c_char] { + &self.exts + } +} + +impl Layers { + fn new(exist_layers: Vec) -> Layers { + Layers { + exist_layers, + layers: vec![], + } + } + + fn try_add(&mut self, ext: &'static CStr) -> bool { + unsafe { + if self + .exist_layers + .iter() + .find(|x| CStr::from_ptr(x.layer_name.as_ptr()) == ext) + .is_some() + { + self.layers.push(ext.as_ptr()); + true + } else { + false + } + } + } + + fn as_ptrs(&self) -> &[*const c_char] { + &self.layers + } +} + unsafe fn choose_compute_device( instance: &Instance, devices: &[vk::PhysicalDevice], diff --git a/piet-gpu/bin/winit.rs b/piet-gpu/bin/winit.rs index 51004cd..420ffa5 100644 --- a/piet-gpu/bin/winit.rs +++ b/piet-gpu/bin/winit.rs @@ -25,7 +25,8 @@ fn main() -> Result<(), Error> { let (instance, surface) = VkInstance::new(Some(&window))?; unsafe { let device = instance.device(surface.as_ref())?; - let mut swapchain = instance.swapchain(WIDTH / 2, HEIGHT / 2, &device, surface.as_ref().unwrap())?; + let mut swapchain = + instance.swapchain(WIDTH / 2, HEIGHT / 2, &device, surface.as_ref().unwrap())?; let session = hub::Session::new(device); let mut current_frame = 0; diff --git a/piet-gpu/shader/build.ninja b/piet-gpu/shader/build.ninja index cce8615..22c9c78 100644 --- a/piet-gpu/shader/build.ninja +++ b/piet-gpu/shader/build.ninja @@ -5,7 +5,7 @@ glslang_validator = glslangValidator rule glsl - command = $glslang_validator -V -o $out $in + command = $glslang_validator $flags -V -o $out $in build elements.spv: glsl elements.comp | scene.h state.h annotated.h @@ -21,3 +21,6 @@ build backdrop.spv: glsl backdrop.comp | annotated.h tile.h setup.h build coarse.spv: glsl coarse.comp | annotated.h bins.h ptcl.h setup.h build kernel4.spv: glsl kernel4.comp | ptcl.h setup.h + +build kernel4_idx.spv: glsl kernel4.comp | ptcl.h setup.h + flags = -DENABLE_IMAGE_INDICES diff --git a/piet-gpu/shader/kernel4.comp b/piet-gpu/shader/kernel4.comp index b7834cf..cd31f78 100644 --- a/piet-gpu/shader/kernel4.comp +++ b/piet-gpu/shader/kernel4.comp @@ -8,7 +8,9 @@ #version 450 #extension GL_GOOGLE_include_directive : enable +#ifdef ENABLE_IMAGE_INDICES #extension GL_EXT_nonuniform_qualifier : enable +#endif #include "mem.h" #include "setup.h" @@ -26,7 +28,7 @@ layout(set = 0, binding = 1) readonly buffer ConfigBuf { layout(rgba8, set = 0, binding = 2) uniform writeonly image2D image; -#if GL_EXT_nonuniform_qualifier +#ifdef ENABLE_IMAGE_INDICES layout(rgba8, set = 0, binding = 3) uniform readonly image2D images[]; #else layout(rgba8, set = 0, binding = 3) uniform readonly image2D images[1]; @@ -100,10 +102,17 @@ void main() { vec4 rgba[CHUNK]; for (uint i = 0; i < CHUNK; i++) { rgba[i] = vec4(0.0); + // TODO: remove this debug image support when the actual image method is plumbed. +#ifdef DEBUG_IMAGES #ifdef ENABLE_IMAGE_INDICES if (xy_uint.x < 1024 && xy_uint.y < 1024) { rgba[i] = imageLoad(images[gl_WorkGroupID.x / 64], ivec2(xy_uint + chunk_offset(i))/4); } +#else + if (xy_uint.x < 1024 && xy_uint.y < 1024) { + rgb[i] = imageLoad(images[0], ivec2(xy_uint + chunk_offset(i))/4).rgb; + } +#endif #endif } diff --git a/piet-gpu/shader/kernel4.spv b/piet-gpu/shader/kernel4.spv index af7fe183c6b89ca9d5e0c89b172b53b55c6baba7..d9daddf9e7dcf7a66c4af766a9b6ab973b784e3b 100644 GIT binary patch literal 36004 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 diff --git a/piet-gpu/shader/kernel4_idx.spv b/piet-gpu/shader/kernel4_idx.spv new file mode 100644 index 0000000000000000000000000000000000000000..106a9fc13473ffa776091bf8d2cd3894c592ddde GIT binary patch literal 36108 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, } -#[derive(Clone,Copy,PartialEq)] +#[derive(Clone, Copy, PartialEq)] enum FillMode { // Fill path according to the non-zero winding rule. Nonzero = 0, @@ -121,8 +121,9 @@ impl PietGpuRenderContext { fn set_fill_mode(ctx: &mut PietGpuRenderContext, fill_mode: FillMode) { if ctx.fill_mode != fill_mode { - ctx.elements - .push(Element::SetFillMode(SetFillMode { fill_mode: fill_mode as u32 })); + ctx.elements.push(Element::SetFillMode(SetFillMode { + fill_mode: fill_mode as u32, + })); ctx.fill_mode = fill_mode; } } @@ -322,14 +323,17 @@ impl PietGpuRenderContext { fn encode_path(&mut self, path: impl Iterator, is_fill: bool) { if is_fill { - self.encode_path_inner(path.flat_map(|el| { - match el { - PathEl::MoveTo(..) => { - Some(PathEl::ClosePath) + self.encode_path_inner( + path.flat_map(|el| { + match el { + PathEl::MoveTo(..) => Some(PathEl::ClosePath), + _ => None, } - _ => None - }.into_iter().chain(Some(el)) - }).chain(Some(PathEl::ClosePath))) + .into_iter() + .chain(Some(el)) + }) + .chain(Some(PathEl::ClosePath)), + ) } else { self.encode_path_inner(path) } From bcb26c931ef320257e81a5606f04533d283e5339 Mon Sep 17 00:00:00 2001 From: Raph Levien Date: Sat, 3 Apr 2021 08:34:26 -0700 Subject: [PATCH 08/11] Clean up device create extensions --- piet-gpu-hal/src/vulkan.rs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/piet-gpu-hal/src/vulkan.rs b/piet-gpu-hal/src/vulkan.rs index bddbedc..273d860 100644 --- a/piet-gpu-hal/src/vulkan.rs +++ b/piet-gpu-hal/src/vulkan.rs @@ -282,12 +282,14 @@ impl VkInstance { .descriptor_binding_variable_descriptor_count(true) .runtime_descriptor_array(true); - let mut extensions = match surface { - Some(_) => vec![khr::Swapchain::name().as_ptr()], - None => vec![], - }; - extensions.push(vk::ExtDescriptorIndexingFn::name().as_ptr()); - extensions.push(vk::KhrMaintenance3Fn::name().as_ptr()); + let mut extensions = Vec::new(); + if surface.is_some() { + extensions.push(khr::Swapchain::name().as_ptr()); + } + if has_descriptor_indexing { + extensions.push(vk::KhrMaintenance3Fn::name().as_ptr()); + extensions.push(vk::ExtDescriptorIndexingFn::name().as_ptr()); + } let mut create_info = vk::DeviceCreateInfo::builder() .queue_create_infos(&queue_create_infos) .enabled_extension_names(&extensions); From f4be74c07f106ba9973925e1b193ae9a11911269 Mon Sep 17 00:00:00 2001 From: Elias Naur Date: Sat, 10 Apr 2021 18:12:21 +0200 Subject: [PATCH 09/11] winit: fix n_trans count Signed-off-by: Elias Naur --- piet-gpu/bin/winit.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/piet-gpu/bin/winit.rs b/piet-gpu/bin/winit.rs index 51004cd..e8a7f32 100644 --- a/piet-gpu/bin/winit.rs +++ b/piet-gpu/bin/winit.rs @@ -40,7 +40,7 @@ fn main() -> Result<(), Error> { render_scene(&mut ctx); let n_paths = ctx.path_count(); let n_pathseg = ctx.pathseg_count(); - let n_trans = ctx.pathseg_count(); + let n_trans = ctx.trans_count(); let scene = ctx.get_scene_buf(); let renderer = Renderer::new(&session, scene, n_paths, n_pathseg, n_trans)?; From 0637e2d6e507cb6c15a3cb78b1106fa0cba9abe4 Mon Sep 17 00:00:00 2001 From: Tatsuyuki Ishi Date: Sun, 11 Apr 2021 13:20:40 +0900 Subject: [PATCH 10/11] Encode premultiplied alpha in render_ctx.rs --- piet-gpu/src/lib.rs | 10 ++----- piet-gpu/src/render_ctx.rs | 58 +++++++++++++++++++++++++------------- 2 files changed, 42 insertions(+), 26 deletions(-) diff --git a/piet-gpu/src/lib.rs b/piet-gpu/src/lib.rs index 3e46eae..3a2b33e 100644 --- a/piet-gpu/src/lib.rs +++ b/piet-gpu/src/lib.rs @@ -127,16 +127,12 @@ fn render_clip_test(rc: &mut impl RenderContext) { #[allow(unused)] fn render_alpha_test(rc: &mut impl RenderContext) { - // Alpha compositing tests. kernel4 expects colors encoded in alpha-premultiplied sRGB: - // - // [α,sRGB(α⋅R),sRGB(α⋅G),sRGB(α⋅B)] - // - // See also http://ssp.impulsetrain.com/gamma-premult.html. + // Alpha compositing tests. rc.fill(diamond(Point::new(1024.0, 100.0)), &Color::Rgba32(0xff0000ff)); - rc.fill(diamond(Point::new(1024.0, 125.0)), &Color::Rgba32(0x00ba0080)); + rc.fill(diamond(Point::new(1024.0, 125.0)), &Color::Rgba32(0x00ff0080)); rc.save(); rc.clip(diamond(Point::new(1024.0, 150.0))); - rc.fill(diamond(Point::new(1024.0, 175.0)), &Color::Rgba32(0x0000ba80)); + rc.fill(diamond(Point::new(1024.0, 175.0)), &Color::Rgba32(0x0000ff80)); rc.restore(); } diff --git a/piet-gpu/src/render_ctx.rs b/piet-gpu/src/render_ctx.rs index e80d67d..ab3d777 100644 --- a/piet-gpu/src/render_ctx.rs +++ b/piet-gpu/src/render_ctx.rs @@ -1,21 +1,19 @@ use std::{borrow::Cow, ops::RangeBounds}; -use piet_gpu_types::encoder::{Encode, Encoder}; - -use piet_gpu_types::scene::{ - Clip, CubicSeg, Element, FillColor, SetFillMode, LineSeg, QuadSeg, SetLineWidth, Transform, -}; - use piet::{ - kurbo::{Affine, Insets, PathEl, Point, Rect, Shape, Size}, - HitTestPosition, TextAttribute, TextStorage, + HitTestPosition, + kurbo::{Affine, Insets, PathEl, Point, Rect, Shape, Size}, TextAttribute, TextStorage, }; - use piet::{ Color, Error, FixedGradient, FontFamily, HitTestPoint, ImageFormat, InterpolationMode, IntoBrush, LineMetric, RenderContext, StrokeStyle, Text, TextLayout, TextLayoutBuilder, }; +use piet_gpu_types::encoder::{Encode, Encoder}; +use piet_gpu_types::scene::{ + Clip, CubicSeg, Element, FillColor, LineSeg, QuadSeg, SetFillMode, SetLineWidth, Transform, +}; + pub struct PietGpuImage; #[derive(Clone)] @@ -70,7 +68,7 @@ struct ClipElement { bbox: Option, } -#[derive(Clone,Copy,PartialEq)] +#[derive(Clone, Copy, PartialEq)] enum FillMode { // Fill path according to the non-zero winding rule. Nonzero = 0, @@ -138,7 +136,14 @@ impl RenderContext for PietGpuRenderContext { } fn solid_brush(&mut self, color: Color) -> Self::Brush { - PietGpuBrush::Solid(color.as_rgba_u32()) + // kernel4 expects colors encoded in alpha-premultiplied sRGB: + // + // [α,sRGB(α⋅R),sRGB(α⋅G),sRGB(α⋅B)] + // + // See also http://ssp.impulsetrain.com/gamma-premult.html. + let (r, g, b, a) = color.as_rgba(); + let premul = Color::rgba(to_srgb(from_srgb(r) * a), to_srgb(from_srgb(g) * a), to_srgb(from_srgb(b) * a), a); + PietGpuBrush::Solid(premul.as_rgba_u32()) } fn gradient(&mut self, _gradient: impl Into) -> Result { @@ -176,8 +181,7 @@ impl RenderContext for PietGpuRenderContext { _brush: &impl IntoBrush, _width: f64, _style: &StrokeStyle, - ) { - } + ) {} fn fill(&mut self, shape: impl Shape, brush: &impl IntoBrush) { let brush = brush.make_brush(self, || shape.bounding_box()).into_owned(); @@ -279,8 +283,7 @@ impl RenderContext for PietGpuRenderContext { _image: &Self::Image, _rect: impl Into, _interp: InterpolationMode, - ) { - } + ) {} fn draw_image_area( &mut self, @@ -288,8 +291,7 @@ impl RenderContext for PietGpuRenderContext { _src_rect: impl Into, _dst_rect: impl Into, _interp: InterpolationMode, - ) { - } + ) {} fn blurred_rect(&mut self, _rect: Rect, _blur_radius: f64, _brush: &impl IntoBrush) {} @@ -320,7 +322,7 @@ impl PietGpuRenderContext { self.pathseg_count += 1; } - fn encode_path(&mut self, path: impl Iterator, is_fill: bool) { + fn encode_path(&mut self, path: impl Iterator, is_fill: bool) { if is_fill { self.encode_path_inner(path.flat_map(|el| { match el { @@ -335,7 +337,7 @@ impl PietGpuRenderContext { } } - fn encode_path_inner(&mut self, path: impl Iterator) { + fn encode_path_inner(&mut self, path: impl Iterator) { let flatten = false; if flatten { let mut start_pt = None; @@ -583,3 +585,21 @@ fn to_scene_transform(transform: Affine) -> Transform { translate: [c[4] as f32, c[5] as f32], } } + +fn to_srgb(f: f64) -> f64 { + if f <= 0.0031308 { + f * 12.92 + } else { + let a = 0.055; + (1. + a) * f64::powf(f, f64::recip(2.4)) - a + } +} + +fn from_srgb(f: f64) -> f64 { + if f <= 0.04045 { + f / 12.92 + } else { + let a = 0.055; + f64::powf((f + a) * f64::recip(1. + a), 2.4) + } +} \ No newline at end of file From 45ea43c1578a565e912c983e1c1ff4fc982f08e7 Mon Sep 17 00:00:00 2001 From: Elias Naur Date: Sun, 11 Apr 2021 19:54:40 +0200 Subject: [PATCH 11/11] kernel4: replace continue in switch to support D3D11 shader model 5.0 Without this change, the fxc.exe compiler complains error X3708: continue cannot be used in a switch Signed-off-by: Elias Naur --- piet-gpu/shader/kernel4.comp | 2 +- piet-gpu/shader/kernel4.spv | Bin 36716 -> 36716 bytes 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/piet-gpu/shader/kernel4.comp b/piet-gpu/shader/kernel4.comp index b7834cf..d366dd6 100644 --- a/piet-gpu/shader/kernel4.comp +++ b/piet-gpu/shader/kernel4.comp @@ -231,7 +231,7 @@ void main() { case Cmd_Jump: cmd_ref = CmdRef(Cmd_Jump_read(cmd_alloc, cmd_ref).new_ref); cmd_alloc.offset = cmd_ref.offset; - continue; + break; } } diff --git a/piet-gpu/shader/kernel4.spv b/piet-gpu/shader/kernel4.spv index af7fe183c6b89ca9d5e0c89b172b53b55c6baba7..4d05170d8757ddab222265672f312b902dcb38f6 100644 GIT binary patch delta 16 YcmaDekLk@krVS5L7)>`nOzGAF07yIs@Bjb+ delta 16 YcmaDekLk@krVS5L7-cs