From a616b4d010a346d7cbfc026a0bb255d0f0626292 Mon Sep 17 00:00:00 2001 From: Raph Levien Date: Wed, 20 May 2020 16:36:09 -0700 Subject: [PATCH] Rework right_edge computation in elements Trying to fit it into the fancy monad doesn't really work, so use a more straightforward approach to compute it from the aggregate. Also add yEdge logic (basically copying piet-metal). With a fix to ELEMENT_BINNING_RATIO (which I had simply gotten wrong), the example renders almost correctly, with small bounding box artifacts. --- piet-gpu-types/src/state.rs | 1 - piet-gpu/shader/binning.comp | 9 ++++---- piet-gpu/shader/binning.spv | Bin 22592 -> 19600 bytes piet-gpu/shader/build.ninja | 2 +- piet-gpu/shader/coarse.comp | 24 +++++++++++++++++++++ piet-gpu/shader/coarse.spv | Bin 38016 -> 43040 bytes piet-gpu/shader/elements.comp | 38 +++++++++++++++++++++++----------- piet-gpu/shader/elements.spv | Bin 45312 -> 45536 bytes piet-gpu/shader/setup.h | 2 +- piet-gpu/shader/state.h | 10 +++------ piet-gpu/src/lib.rs | 2 +- piet-gpu/src/render_ctx.rs | 26 ++++++++++++++--------- 12 files changed, 76 insertions(+), 38 deletions(-) diff --git a/piet-gpu-types/src/state.rs b/piet-gpu-types/src/state.rs index b93e9f3..35076f0 100644 --- a/piet-gpu-types/src/state.rs +++ b/piet-gpu-types/src/state.rs @@ -8,7 +8,6 @@ piet_gpu! { translate: [f32; 2], bbox: [f32; 4], linewidth: f32, - right_edge: f32, flags: u32, } } diff --git a/piet-gpu/shader/binning.comp b/piet-gpu/shader/binning.comp index 138621e..713a654 100644 --- a/piet-gpu/shader/binning.comp +++ b/piet-gpu/shader/binning.comp @@ -50,10 +50,10 @@ shared uint sh_chunk_jump[N_TILE]; shared float sh_right_edge[N_TILE]; -#define StateBuf_stride (4 + 2 * State_size) +#define StateBuf_stride (8 + 2 * State_size) -StateRef state_aggregate_ref(uint partition_ix) { - return StateRef(8 + partition_ix * StateBuf_stride); +uint state_right_edge_index(uint partition_ix) { + return 2 + partition_ix * (StateBuf_stride / 4); } void main() { @@ -120,8 +120,7 @@ void main() { // look-forward is small (performance may degrade in the case // of massively complex paths). do { - StateRef agg_ref = state_aggregate_ref(aggregate_ix); - my_right_edge = State_read(agg_ref).right_edge; + my_right_edge = uintBitsToFloat(state[state_right_edge_index(aggregate_ix)]); aggregate_ix++; } while (isinf(my_right_edge)); } diff --git a/piet-gpu/shader/binning.spv b/piet-gpu/shader/binning.spv index dc1713b5505929835d055744fc3124cd12d0d6e1..e932e4d3b944d2352e9ea514e2b4b4250c3e9a46 100644 GIT binary patch literal 19600 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 WpK!IODe3bw;29KczE5)Br~d_$M=(MF literal 22592 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 diff --git a/piet-gpu/shader/build.ninja b/piet-gpu/shader/build.ninja index 3b6b963..14c72aa 100644 --- a/piet-gpu/shader/build.ninja +++ b/piet-gpu/shader/build.ninja @@ -12,7 +12,7 @@ build image.spv: glsl image.comp | scene.h build elements.spv: glsl elements.comp | scene.h state.h annotated.h -build binning.spv: glsl binning.comp | annotated.h bins.h setup.h +build binning.spv: glsl binning.comp | annotated.h state.h bins.h setup.h build coarse.spv: glsl coarse.comp | annotated.h bins.h ptcl.h setup.h diff --git a/piet-gpu/shader/coarse.comp b/piet-gpu/shader/coarse.comp index 2389e27..03c4535 100644 --- a/piet-gpu/shader/coarse.comp +++ b/piet-gpu/shader/coarse.comp @@ -310,6 +310,30 @@ void main() { switch (tag) { case Annotated_FillLine: + AnnoFillLineSeg fill_line = Annotated_FillLine_read(ref); + // This is basically the same logic as piet-metal, but should be made numerically robust. + vec2 tile_xy = vec2(tile_x * TILE_WIDTH_PX, tile_y * TILE_HEIGHT_PX); + float yEdge = mix(fill_line.p0.y, fill_line.p1.y, (tile_xy.x - fill_line.p0.x) / (fill_line.p1.x - fill_line.p0.x)); + if (min(fill_line.p0.x, fill_line.p1.x) < tile_xy.x && yEdge >= tile_xy.y && yEdge < tile_xy.y + TILE_HEIGHT_PX) { + Segment edge_seg; + if (fill_line.p0.x > fill_line.p1.x) { + fill_line.p1 = vec2(tile_xy.x, yEdge); + edge_seg.start = fill_line.p1; + edge_seg.end = vec2(tile_xy.x, tile_xy.y + TILE_HEIGHT_PX); + } else { + fill_line.p0 = vec2(tile_xy.x, yEdge); + edge_seg.start = vec2(tile_xy.x, tile_xy.y + TILE_HEIGHT_PX); + edge_seg.end = fill_line.p0; + } + alloc_chunk(chunk_n_segs, seg_chunk_ref, first_seg_chunk, seg_limit); + Segment_write(SegmentRef(seg_chunk_ref.offset + SegChunk_size + Segment_size * chunk_n_segs), edge_seg); + chunk_n_segs++; + } + Segment fill_seg = Segment(fill_line.p0, fill_line.p1); + alloc_chunk(chunk_n_segs, seg_chunk_ref, first_seg_chunk, seg_limit); + Segment_write(SegmentRef(seg_chunk_ref.offset + SegChunk_size + Segment_size * chunk_n_segs), fill_seg); + chunk_n_segs++; + break; case Annotated_StrokeLine: AnnoStrokeLineSeg line = Annotated_StrokeLine_read(ref); Segment seg = Segment(line.p0, line.p1); diff --git a/piet-gpu/shader/coarse.spv b/piet-gpu/shader/coarse.spv index bc097e44388cf90bb53859a8801d1fe1b4f343e3..3d3f3ff34e9f936435e516410382d85c0fb9e92a 100644 GIT binary patch literal 43040 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 D@a*Ai literal 38016 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

3dIb`ZoUe;A+OOA9;NDs(rIh_lB!E zuA`U-$Gk6CeIJT3oLe>jhA8u9-MT+6!q4kmiu=PoabAs2qCUUC7t~mv3n{L}PpGqR z4kv#0jcrdTxcBu*HP5*AgWFgBrm7RJb`6?)U?|wjJ)muW%4CZDinHH_fz7krZ^O~l zGiM{fYR*sk?*coH?7@+6{nYJ$G_{xgYa2yTvwv~+U^lpR4~{`o&mKIW_IK{af|IXn zCD%XW8CTeo>v%NvjAsH^&A8bE2ZGfnQjF`^)Z7Ef+uE2XVw(gu4}D!*xxUW3V|1>Q zQ%~(%&hbHL>dEO~u$u2e$@>tvYn<=vQ{d*Oo_15gw$+w)-v^g#^8>hk>aNXU)LyQQ zwnHgu<}J?J{1Du_Hb7TRaWU$XxeYB;|Q^59_wLBGE?mxLc V#%$h?&3%yhv@Z9B`y=Pb{{z)BoU8x< diff --git a/piet-gpu/shader/elements.comp b/piet-gpu/shader/elements.comp index 341952b..bdb4e0d 100644 --- a/piet-gpu/shader/elements.comp +++ b/piet-gpu/shader/elements.comp @@ -34,14 +34,14 @@ layout(set = 0, binding = 2) buffer AnnotatedBuf { #include "state.h" #include "annotated.h" -#define StateBuf_stride (4 + 2 * State_size) +#define StateBuf_stride (8 + 2 * State_size) StateRef state_aggregate_ref(uint partition_ix) { - return StateRef(8 + partition_ix * StateBuf_stride); + return StateRef(12 + partition_ix * StateBuf_stride); } StateRef state_prefix_ref(uint partition_ix) { - return StateRef(8 + partition_ix * StateBuf_stride + State_size); + return StateRef(12 + partition_ix * StateBuf_stride + State_size); } uint state_flag_index(uint partition_ix) { @@ -81,13 +81,12 @@ State combine_state(State a, State b) { c.translate.x = a.mat.x * b.translate.x + a.mat.z * b.translate.y + a.translate.x; c.translate.y = a.mat.y * b.translate.x + a.mat.w * b.translate.y + a.translate.y; c.linewidth = (b.flags & FLAG_SET_LINEWIDTH) == 0 ? a.linewidth : b.linewidth; - c.right_edge = (a.flags & FLAG_SET_BBOX) != 0 ? a.right_edge : (a.flags & FLAG_RESET_BBOX) != 0 ? a.bbox.z : c.right_edge; c.flags = (a.flags & (FLAG_SET_LINEWIDTH | FLAG_SET_BBOX)) | b.flags; c.flags |= (a.flags & FLAG_RESET_BBOX) >> 1; return c; } -State map_element(ElementRef ref) { +State map_element(ElementRef ref, inout bool is_fill) { // TODO: it would *probably* be more efficient to make the memory read patterns less // divergent, though it would be more wasted memory. uint tag = Element_tag(ref); @@ -97,6 +96,7 @@ State map_element(ElementRef ref) { c.translate = vec2(0.0, 0.0); c.linewidth = 1.0; // TODO should be 0.0 c.flags = 0; + is_fill = false; switch (tag) { case Element_FillLine: case Element_StrokeLine: @@ -115,6 +115,8 @@ State map_element(ElementRef ref) { c.bbox.zw = max(max(cubic.p0, cubic.p1), max(cubic.p2, cubic.p3)); break; case Element_Fill: + is_fill = true; + // fall-through case Element_Stroke: c.flags = FLAG_RESET_BBOX; break; @@ -145,9 +147,10 @@ shared vec4 sh_mat[WG_SIZE]; shared vec2 sh_translate[WG_SIZE]; shared vec4 sh_bbox[WG_SIZE]; shared float sh_width[WG_SIZE]; -shared float sh_right_edge[WG_SIZE]; shared uint sh_flags[WG_SIZE]; +shared uint sh_min_fill; + shared uint sh_tile_ix; shared State sh_prefix; @@ -157,6 +160,7 @@ void main() { // 4.4 of prefix sum paper). if (gl_LocalInvocationID.x == 0) { sh_tile_ix = atomicAdd(state[0], 1); + sh_min_fill = ~0; } barrier(); uint tile_ix = sh_tile_ix; @@ -164,18 +168,24 @@ void main() { uint ix = tile_ix * PARTITION_SIZE + gl_LocalInvocationID.x * N_ROWS; ElementRef ref = ElementRef(ix * Element_size); - th_state[0] = map_element(ref); + bool is_fill; + uint my_min_fill = ~0; + th_state[0] = map_element(ref, is_fill); + if (is_fill) my_min_fill = ix; for (uint i = 1; i < N_ROWS; i++) { // discussion question: would it be faster to load using more coherent patterns // into thread memory? This is kinda strided. - th_state[i] = combine_state(th_state[i - 1], map_element(Element_index(ref, i))); + th_state[i] = combine_state(th_state[i - 1], map_element(Element_index(ref, i), is_fill)); + if (is_fill && my_min_fill == ~0) { + my_min_fill = ix + i; + } } + atomicMin(sh_min_fill, my_min_fill); State agg = th_state[N_ROWS - 1]; sh_mat[gl_LocalInvocationID.x] = agg.mat; sh_translate[gl_LocalInvocationID.x] = agg.translate; sh_bbox[gl_LocalInvocationID.x] = agg.bbox; sh_width[gl_LocalInvocationID.x] = agg.linewidth; - sh_right_edge[gl_LocalInvocationID.x] = agg.right_edge; sh_flags[gl_LocalInvocationID.x] = agg.flags; for (uint i = 0; i < LG_WG_SIZE; i++) { barrier(); @@ -194,7 +204,6 @@ void main() { sh_translate[gl_LocalInvocationID.x] = agg.translate; sh_bbox[gl_LocalInvocationID.x] = agg.bbox; sh_width[gl_LocalInvocationID.x] = agg.linewidth; - sh_right_edge[gl_LocalInvocationID.x] = agg.right_edge; sh_flags[gl_LocalInvocationID.x] = agg.flags; } @@ -203,7 +212,6 @@ void main() { exclusive.mat = vec4(1.0, 0.0, 0.0, 1.0); exclusive.translate = vec2(0.0, 0.0); exclusive.linewidth = 1.0; //TODO should be 0.0 - exclusive.right_edge = 0.0; exclusive.flags = 0; // Publish aggregate for this partition @@ -244,6 +252,7 @@ void main() { } } barrier(); + my_min_fill = sh_min_fill; if (tile_ix != 0) { exclusive = sh_prefix; } @@ -256,12 +265,17 @@ void main() { other.translate = sh_translate[ix]; other.bbox = sh_bbox[ix]; other.linewidth = sh_width[ix]; - other.right_edge = sh_right_edge[ix]; other.flags = sh_flags[ix]; row = combine_state(row, other); } + if (my_min_fill == ~0 && gl_LocalInvocationID.x == 0) { + state[state_flag_index(tile_ix) + 1] = 0x7f800000; // infinity + } for (uint i = 0; i < N_ROWS; i++) { State st = combine_state(row, th_state[i]); + if (my_min_fill == ix + i) { + state[state_flag_index(tile_ix) + 1] = floatBitsToUint(st.bbox.z); + } // We write the state now for development purposes, but the // actual goal is to write transformed and annotated elements. //State_write(StateRef((ix + i) * State_size), st); diff --git a/piet-gpu/shader/elements.spv b/piet-gpu/shader/elements.spv index c947240a374822edb8c39f605604b116253e8cd9..962bd0ac664fc8283b64a2a94fa207832f65fff5 100644 GIT binary patch literal 45536 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 literal 45312 zcma)_2Y_Bx)wM6oObEUAmQX|Qz4sRBOm-Is=oZ+Q6N9FSJR?Y z)r?i2R=?H2T?Vc=se9OptFN)L_F1Y9yOwQMe7eA$w6Q}*k5eCyFdMqs?6iI~|_@H5dMyTWUxYUZhagGP@V zHvG^5le#A!JhXd-se@NIc$HPwJ9w4#@b6$vs%jzu%{ddeHHO}tv(gWw_FaaL?8&L- zXKK#QYEF3V*IFgHp9!q4t0s4?CahxI8LN4~wf~@r!-ot@iBog6O2oILnj7DCeO=Xj z;GGU0GOVme%}-g+0`S_em0#{B^~h6?^~pVk6IN~4w=lRK->bf~BIU7$Nj&Ck^Ox~l&0_-V5SH9x6QUe+j2jq!KaPFSsd+?N0+X0M_nas=B|>)%l= zj(@xE&T1*}mZQgv!G&77S{$jUxw9Hj`>6Nf|Kxrqj@*C9prPZ(jGt)S8LH*bjMb}# zI(V6XS;w~aU01aNc$e;p;}0Be1?|19=4a}3>w$NjIAq+U5#uM0Z7)+RpSqu^wRKe+!h3wd?iV#bV~2FZ`?R?GtJ|1k zhIDgTqSl$JP3U{Z_A0bTC40L{_tD1qw`-iS+5%i(W(IW+8JW|%aph_6zs-Bb%~EYs zjB6hx4?(Zw-xy=-BF4ZXhTH9bM`+ivT~Caes~w9Np6ma;g7)|wit)P^<6EcQ{|Mmv z?NW^2vl!oAhyNbH@p}~G_bJAI?Hv5t3byOtyJ!5Y)!<_M|G8iPk2r&R;>=PFE8_I* zn*Tl(_FhLdv?oSa<#k|}ZuVud*VX(?-Rqr|=UB^+-hD3jlYK64?sLymb+4!U??3)f zy4E?N<~4N;yD#Uj=Zd=b7^-=JU*vb^iKx)T&d>&(wK$ zRY${3q@OnTfSRB3UgJE~op<(8S2ag<0zBitKD|17>yQ<*QbzNbW**0xueC=ys^h`! zdGx7Hs^hnhB`XBC7Ii=6Tuy;cU9|RG)ciE(qF&C$d8>IG%X6ZunydOQ+SIsTpJh*N z&3U#B^-S5i^}hWM@iN!b!I|rsbsjGT!`f4A%~jpc)Va=5oeQ_7mhYhL$4~frSqams z%JE)z&Y^GTo~OF7SB!SC|0B$#_Nh5_HF{01&T)QEj*jXAaC?4pRTuZl=O+07&(_#7 zt+`xO6YS_Bs zef`Q;AA$dRact%7sBWYmQsbNG_iy1DtJ~6n6vVQGu=YF{r-}Zi)wYn2L za(H*^J6`Lak&*wS7~|Z**h$^(J@^pVRrhuP=`snZ+piI&oi@f?^KT#eiOr8f7`7~jt7)iz(P%{!{M0qs56QGERLLh zuiCsPZYLKE^7O==zRl~noz*OD-g<;K?_6!Z24Pw?F9=WGRlv!+M%%9^@49W?lXs&w z@5#G)oA>11rp5Hg7$yTi3VSe67?q7@oS00;jIy+J1Fi9n~p?-x-D9 zISs!H3%^SWzbhJk*A;%Z7Jhg1^6RYbZu6e?xWCPN*2DJ^9G9N;c&yEP*5j!*?>P?7 z!`t)itUd&DEf_Mkb&NWz&l`MNZV07)h6bOb!53)o#TtCsUc94P5uWv46~x+H_R^>cM@g&%r(S zzMi#d>x8L>vE|2r%20yOBkMG4hs*B)5>l`oh0L^#8 z*8E-pPmSAAy$)~tvG>3}YqV?YtUl`H+gVN5RaFP^-7NOL@TsvntHt0$eFxLZ+gUB% z%id9K0UvWnd!4sz*tUmv*W-5RW$W8|2RL%fpn>Cu4jHq}xXEz2s z4eB1v`@ZbmBaBxIuJcjwtn*3W_C2JlI$gg}?b}`E^=M!LRAXxhKMTDrg;>+rZ4juTStk)je%qz9wk-J=oS;kG-vXRGa5(Q)}$AZLR#; zgx*!X)YkL038kZY6|FtLj_NPs`d;`?@c8ag!zb2rpT1AIE}hkky?9r(B7FFvyiuLh zdeus7&i`IMybEdYjT(GYxW(mIY~8SL*Wd#ie1~4VPqim}%=qyK4%&an&;xs(tvahA z4Zj26Om+0cLG5R)NUuQM0!6!8M#9q9sIs)E~>rrm+{Udw%bXLbS_;C$>LN7jD zbt=5|=Gt{`)O%Vl-_GjvUc9S13(g+vnWV?)oL)Yi)p-qmeuIC%7w@R9gijoQNNX?M z0M7pT5xCqxkMZM-1t9lvUJ!(SYr=W7uD`!`R%`XLcU9}cTRCed=ddAKuCE*Q^5?$T;DZ}{7<@$io!dPz zyqBGKHt<%y+DV`By?i>WgBtwcf^UWYW2_BJ1*)p8`EQ=1=WFq)&(({={cOdY^yz5f z&ek*bVjB1u&u8xbE!O6%abGRt=h(!SnNMy$9?4qyKZ8%r z*VTFsz|?xbZ*ToR8zi3h{lzr!v3|Mn=vv&Lb+5)bmXq=Qz>Zg21l2Vx z$0x>O=-T?xjIk7bVk`|dhMKkkwawa>0n7E#=FdYiZbh);)U>Ts+Z^XJrCc9vKE!66 z53r6?)8+%L>*qKhUgi2|^NV`Mtq*pbn(Mv+z2iKGTz7xApq4pr1XgpLu{WbPmd9AW z6}`tLe0#9#9KJKyH4EPz?3}{)0uLzoeqd{leSfg|<<4aUedaO}>|E3q!DAGCYR|l! zoBr17y+9wwxqtmmKt*pLT8L^I1Llc#LZKtGUk(rZ4x2F(=nP+KkELX)C5< zwHed*l!aL*Q=k<_oGciTdw9m1^ba3|7Wx%YOenjn)NTtJRhUi$2mVv zFL#Z8Nw1IEdNud{pq98#f&J+J481mE#r^^~b*cZ3R*rui?zPwPZ_&HPo=fugYwlb# zuMfawyxAb0x5+mToJ)Rd`~qO(c`nAj8(LZ4-nEbU2GzKK?e98GLQ8!o*Y*ME`d?6U z&t>_wHD9ylH`d(qPy2H<_gt30QgipE$07GxkAwG2xqfTVyJl)02f6o6wajZU#QhOI z0`8s)9|QN^6h0B|eK7n`_)Il--WS2MuJTLauB&zC9&Mf8i{;k&1wH?3Y1S$Ceyo-} zC$pGi3Vs&c>v!zu!@W<<#i;2hK;89w!(#X>&k=RK-h``_ExvEHe2?8IzHh_T;wxUB z*|@LXDfEor*NIluM&297g559K1LNQvwwCT3=^lEI4N2&^q2eHS}k)v z9Nw1z;m5#_#l8?;r-4U--RH*p4%|Jh9{(SK`_=xpfL))q)>+*OHx08apQOAFMUwJqq^tCEjDTOIq(_a5T=l-T9IPbsEtN9@M;{YLmmxbHW@jpzG~aQ%J1QF7mJgpb6&UBMmi`;FKg@B59C`+lS3LkjMA z-)ofi0}DP9yYDk%*WdRUCHH+s$$g&@Zau!s2pOZxQY@vF|Oy9q)UKaGx=JZxL=j-&=&A3irK5xX( zKI8b_B6jon-Xh%RSl?TO8_#zZ;o5y?5w6{L7V=HF3VMG$h~_=>DYOl^2C`h$#9F@* zAFs)i;A;AO!d3KOu%FNI*Vau_^V%xjgeX3L9t!r^$md_%`(!r$Vd&btMjO+9L*jZb z*7g~363_k(^7yQ3^ZuMVj|4l$v0lgJu^kOoJCQk<^H{K&_w&sCIB;|B$D^rd+zDVc z@A=2pu}*{=Pn)^DXQ(Cj$>5e&`=0_=^SOUV=HmLF3Ric$_ZYe3wVeT0)8_p}z7DZQ zVLKCi8@;;oa8I2D_P*pAJ4UXb*!z*|>zbYe_88fJOs?bp1FJPlxO^9VgeTs?Vy4Sts9So6sBNuJ+=n|XeRrmm0o$KQj^<9AN;crASy zuCC8y`d4T#(Hv_Yxjy1o>Al9gcV7d$_wBv@yg~ma&5!m!)OP#idJAlfTz}pMtNCuh z>yP|(nz4-C!szAwBJ=$tKF#^QgQlK*e*&9t3Ul+j_Pb#Bruvcf{NDqs--3_V#P`9* zQTP7%0lgpV)AnbYn)QiO&tJjKdj5u{o_hWcF6;RR+i<~ggbkLUFlwQfw$ z{eQ!a>3pnHu1{kA2b`GJ`6cZ^ntJN|s@7Ad8`PMd=f;%llbF-M6Z2{GY2luW>iT#d zb%524={emAHm2vaG3ELsW*0ayJsYiiShxX0qDr=j7J`29heK{+dde(V1uyM=# z!|Z74`gpwN0K2aoYaMcZl4nkEGtXRT>iW1x<_4R`J>vY`NAsYm>*HRV7wlehta;@6 zB+q={W}f-c)b(+HF90@Ad4E_CO?}ddHeau21qT3~uIG1WjEZ_tK(Z^OX08 zerW3YxF`FA-II5=}jMmI6PEk7Lav*C%Bz zKvUPpeY_0VJmvjiSu}NhJRg<=dp9k6!=1F52f@Sst6$ygU!B09VU(LYrE7 zPk95)d>+e{u=yS%*8sWiC}Ur_w&z+V_r0Wc_uMMAJ^AGC)OL^Isl9<^L|HU@jFwfWvh?sbQ0R-1qiqIZloeKw`{ z+5Szi{bumgu{qc}GM_ErYOaIx*$V8(`DojcrsjOaiL(tj^Vu3K&wRE8UquXc>)DQ8 zE%W&nIP)0@mS;ZOgPo6Kv}Ha%SGey|i+yU@5u93f0L!g~uG)$JTt}}S|DD0EQNAzl z0?zkk{mrSSU&ibTHpflG_1R-LxLVe253nECP227?HP=m?INt^vC(jIf!PPuY=G_yl z=3Mutcf7sNZTr&iNAsh7P;Iw2?_m0UX!qRs(UQ5=FTVc zI0Rg-$DwdFkG1P@IM|Qtq3tl5n(HA>oTI>5k0ZhItjE#d%ZZ_GO~=ryWj&4syB_M= zkDyn}oR0^qX*-Ty9@~lFtj7spdDi13uR*PPSA^33H7uyb*YHfuYTUOnT_1}FAe zV0q?wE;!epbHMT(pYMU)uj4Vn;e&5E3ccE z!quLl7SDmp!G1gkv|UD1Gp;!6bOqRTwPILb*PP`2e_#`E&TQ#8gkr2f^xz`4HHcd5)Cplb8>K6VvDHU%-9NR*%mVu(~mQ z_Iw0v%shL__0iw^(qmxvs_XJ7y*##Gf*q^vae8^KT~C0$b~#3yKE_e^{K!7F*Y+g6 z`&!#mVE3@S&lk_oKTGqY{a3Z!KJ$7GY>d1YdLFEn_tNsGX~r_PIAebec5LSL8*t|Q zB3SNv`ELEU;L}-C$Hf14V0Gv561_a@@O!Z9U>t4wyg;w+`022{3O+&0Y|D2bpTgC5;D~uW`wXmR^V9mS#B97~e2!*J$9pbV zlh>9n(6pUN9%K9)Y#jCE{tvjB`%5(SnF zJtx>W>RGF~z}BQKYc)5xxyJLLsb}20V8^Ow+zk+ubC{b`;{V&i!4SOjc+=J4n2a?d6A!lK|i>D5zLKd^P>J}lSIbJd*2 zH&6T*1DF1C-^-N#j?2830GIPx60YX6>J7}?_xnr1)m&*wz8>Nw02>HMP+)r}e;U<@&7;SC7vIV1Jh)*9Eyg=6A1c49;HjcPixBYny=G zYwG6rcQDk9?KNdnuw!#JErDafYoB(vbOI;Ot0Bn!S(SIZR=X| zx)5y}G{^dhwr#EHwuf(-@A?=Qwg{8wj>ueKMzSfnBeh<8uA9d#~9Z?3~N@ z&O4x~=bo@*?cJ^UC_0iRIkadV8^Ow>~3J|Fh_Y!+#Ow8 z{PrmP^4-!Ld!lPgj&Fk{!PQrkCg3+8=x&K912=o?AZK7z4Q)!GCgY4F}8J z+XJwT1n)zyZjNE}YS!+xX*5{P^)()0s{`Qb@i`DYs`fF4Tp#V8A7jAH^J6TUdVI!# zjgkE(*C%T<0h~1&50-25-wjLzJJ#F>(aW<&lfW0_;}~t_8u|Pt_q&1j2K&tMaD2<> z+#}#>sZX1lZ$Kuuw(PgeIHoO-wDcf{C=?GwB`4N9ssLzj>!ZkqMY zOP}9qeF*H_!XIt$=NkN_27k5SZ-L*gdFKBx+`Q%de*ss|{qPa6TFxnJQp@^030BKm zJPlTRism)p8Tw~wPteSxJ!5|b*5-b4Zt~ck2bXbw4OjEplejN}6IXl2{syegxUP{r zw%>xwxW9+1d96y^m%)jvJ!4-1YcsBEEsyOra2fXvxSH45#C;Q-xNm?n_77lf#`T!V zWBVi6wek7J>)|^zwb=gzc8;;X3s&2a^TPY#do;(Wd)(ir|1-_K;PEi0T))Kp3)uN3 z=3l{TvHuNhow5HNtd^Yr06RuKIX?uOGv~EjKVy1Md_>dk`6ABwvH*Btnx6$}o-gy$ zFGTZvS%g04$H(CEeEGb=ziRN#X?pwncS_3f{+*JN`*%vh{dY0`of3J@r%%Av<+^6A zJ_W1ieEJNmHihQeTeDjHzW}S{eEK(7tvsLp1J6Fvp0QtowHepB%VYBj}HsiWC`N7(Z>mHNGwh-83nR9JnxLWLsfITL$FA7)7x!4cv81=^arTpDc7od0tD5_169HBHQAz-qBC3wCW{Ukk8WQR4Y;?*`XA*Q8b9)?HqcRzp+IHEDIQ zTGq)qsb%fg1gqtmv=&&cye6#;&)(LavFm`fxzAi1d2H)}%ed>q)yiwq2Jpnyp0OK> zX~uPpTb$$Chq-PHFXL_kS1Yeco5B-Ud*W^e)@EFfl{~gBz-8Pm;cDeIX)Ac*YR}lM z!P<=LF_*`-Ex3%k9bB!vCJlrquJ(-m7Fe5c-8=Hwb^w=gcZ92z*QA}`iK{(hcLr-S zu6s}(+pgd;?(T54-DtVi?Ey|)?HRi#SetR(%ktRv0+(_3fvfFJOWb|IiK{(h_XBG) zuIGe2wjp5mUalScgVkam3U&|0J`AjuYs+x3W7KnP83FcO%QaN4Ut*2~yMGdM6j&|x z(O~yM><56=lJh{YW7Ly#4A`8xhRXFz%&}niKw^#qtHnMZ?6Hh}0$43M4+1+zJvk?W z&6#V1T))KZ274S6^I))A?32MBkJt|Zt0m{5V8^H@=V4%TPNI1{<@y=3Kj-)1VC`PF z#kp?#J$pHtpJixXx0j}0mgaSPdHP(pk78V|n_jn%EBMLaQ)+Ha+K+}Cr@W3HgQlMA z=&@k6td%*`vKGgKTN*LFPMrW(E3cy`!n41%XY5H}ZLWv4%40hftd?3&16zOgrd%KW zU8C>RcGpjw^;-$ssx&_<(_Ft5=~tn-eyh=E{mx)qxqjyq`~vWWHBU`v!i`g|-&ttt zS--QvYFR&XsAZn#g4J>#`W{%VT)*?+SwHO=dp=m3>u0U<*uD=|ORYZuTYuJ1u8;n% z(M7f0^%H0P*2K0B&Cgn`#yyXIZJO)1E`8ST62_J5cSXUk1z%V5)O0D_IOY0XhNhnN zyBw^R^)rWB=6NMpE$ep`Sgl;YtKnHc?HPLwSexr-t@7Be2dm{AzX7af?KjfjL~}k_ zPq{vhcg=3D?XIUd>$xGeO=x~LqPZW}r{9?7dTvUe^}LmF<$B)H;CDCp{SE$bgFn{b zPZj(*@bfj#@wp9dUFGrlF`9ag&+TBf93N{|%R1f(R?G3Z3#?WipP#^Ue6(lmPr=$e zKF(bp+dbei?!9oe@;U2g@Wj=gvG;+s8P_$G$MyiYjQexATKSyyAUtukXY4~@ZN~Lj z$Yc8jxQsgmu2w#0JpxZ$?HT(hSetP@rt;Vx2bXbw30IqqmgkEnz=^9pW1m!~8P~lb zkL_u28TT2u+B~$xeHNU!+B5c7U~R^AkI7?u0qn8NdG%|sTI?@^JtndL2CNqQOJLVF z_TPflV*ef3HH!WBV72@#<7Kcpjq6zL?)O*dU!{2t=<=(zR$V!7TBC0fL$-Se#Z1#@pf(ZIwH<>#Cz=)G(VfsypHsx-<;-k zWJ~&-$A4m+dU+ndi>99Q_&u^3w%ThUU})?jPe zmfmaIZ1f*8&TCt0{3~3)vc|umsps19cd(j!+jr8l;{Ok@x@%`lxj&z|F5)-Q>pUs>x{=AflkLR4z0bw2#3K~uL@W6G`7 zS~|eKzf`wYd1~#CzAMeo&a~9J3)otBqqo+6^!`2FverIu{mNRWLsL(!eH}wft&8G6 zJzU*djVZTQYnc(eM4ii8<*C)@o;_)PcBiG*J;2ubZF+0ug}P)Vc!xv&(7LYD~GcTFabZpH$) zxPE1=^P;Jz*7?9{sdXv*=ZC9Xt1;!)YAp+b{a&JOt@70B^Uq+KpZ#d5br9HEhtONA z&ykBUuB>$txPE1=i=wHg)_!2M)VezU{o(4?YD~GcTFc@s+|FgK^3>`zb{Ngi{8;ggv}GAr*18m2zp~b)(bQAx0I*tWT@U|d;Of?DOu4mM%W~jN>Ri?;PpzZS z52X1SO|#aK^as$abqu|=`rXdIEp4sgt2X$04Zd-M`?sRY@!K}Ie=EAQ@7mzsZt(pY zd{~1Y(BS^9=raD~f{$fhN7g*|kCouALwPJ#MpMr{ZWXZF6#QI!*GMh*wY9)%Id*G< z)yikpb>R7ZaP1kpE?Ap!U2A!4>x0X<8^G0GppM*YH-smy_Ke*Ktj)L{GkI*AfXld> z!qv)W)y?3Et36{k2WvB~$6g-Wmf$k(R&cfQS#@i8;%d*>ZNS=$>mHKFwjH>PI}ons zxsi4F7CdpaXYBT1ZN_yk%46FRT*loAt~O5*cV~FwYR}kRz}k%Ko|eb98@PJv-LbRN--NEs_4GUS&0w{h&p!gMNpqZWT_ZL9lK&QPng3R}TJG=WzYU)J z>dF6ObZyChJ6J9G?*J#iam}x$U-I7xF7w|7SIcvN`F{dWe)Z)4DY~}gzZ`5yqQCI8RC$!}cqtLc~g4}#1555d*) zTw(r);pX?6QXc&i`3-ZOQ*Duv+pz2Tp$DnqN)7 zu|LZwB&ySoc!hfe-m9>^8W#>mi%vl zli#@JSJN-~-v*cY{|HwbL(6^P9kBVmuQ<+Y-=EObllxt;T5`V!PHtnGTTQ>@eji-s z{xe){A}zT;0GsaB=Dw6Z z<30kbC)Yp0$z=?4sp(h#PA;_d?-A%)f4kiKTsQbons_q(VKnb~N6_b<_b&#P_q>nc zjw$bXpP;Gdp7$wOE%!WQsAUfS0juSn_a#`(bK7~j=f8qmPxGEfsV!U9ej2!1)?-@m zzZvT|1t-68&9A0k@=p&g^UnZR z^W4t-XM~%-dCi{*U0d?c3|342S-{C}T=T2xm;AGW%lxy!)yjL`?C|6-=RXI!w&b4^ ztd{(9fs^03=2z1%`R4|g`R9SFmG``P;pT5%^XEg?mi+UB)slY!aPk}1{A&6o|AOE$ z|3YxJ@}9RaJo(G{FM_Tu`4cWx$!cG0df=Uve!AE^{phS1ZrG<>BUP?)??ewPo#B1gj*sq4JE%{dmt0n&$;N&;1`PKAG{x!j6{w?vie?4&W8`u15`X&GR;4=RPaJBN>+Yp}o<^6smbZyDMF<346HvuQV zam}x$Uvuw&m-+ZPjpp7znf^O9K9&A-ntT5Y`t1EpiBse>5SfYq}1 zjiHwH*b=Oky}uP$t=#)t!>y;xvkjVh=DsaBb2o-_SJN-KwgZ>B2Ex_Kz5gw^xte=_ zdvtAC`yIe)$-g5w`HgFSHT{x*Cvcg6XSiCq_jiFOf4TQ}Mc0=6yMfh`e|K>58`u15 z`X&D!;4=T7aJ6#pe;c0s<=)>5U0d?+4OUD3eZa|YT=T2xm;C#J%l!Mn)ylm;2%h}q z-XDyvE%}Fl)slaIaPk}1{A&6o|4?w5e;8b?ecx%nLm3V?zx&m3p7$fr)RTK8SS`6n zfs@;q=2p|MdET8%JU?gCJnzn;KZoYI_C5MMdyZzTdb#HhKvU1Tbs$*HT2spycxusZ zEoz=m%~~!*^K%|8wVYpLuK^d(tn2&qUIV;F984^)0djpN*F1HPg&U)+dmNg2>K+eP zE9;&BPu<$BTP?@N_e}@Eo3SUNsptAJ39ROx^5^^~F|He~ZcOW!du&g^b_m#cYI82~ z{2RVQ!CogFqpi7q7i07D16tPaq8cAV|3jMVcL}}g)q1`lPS#JK<7=MvI}C1&a{UfR zQ_uPx0ah#5??`yoPrLI`Yk!Y#KSLY^Z^k|vO+D*(3|KAecO*q1PjOLnML7(&XB*v=e-yEI-S38-Ox=#fU zo|gB=^d5KPp9WU<{i8VVAGKXY^Hb)&5^nCR>681rj8jkUGvI1v?la-$)|PtC2CJV% zOFid+)vZUIdioImI+~wrXjzME!Pav(I5u?|N|Zm-qM^(6uH1jbO*BXY5VjZ_05qy0-ZJNM5hw z>-1UgThO&7$E{$;s%MV3fip*I(C0Yb`8)p~gIxoClIwP`HGM!UkL?}k+A{V|u;bM; z_Aan{E63aGh?>6f`3X34F4ya)=-T3UH#l=H>$nG9TjqQ(*si z3jU@XkD+Ue-{auqC~Ns8y0+wa0_<4z%<)NZ=4cK2pFmD4f-VRE8yfW>B8kT_u{0&`O=KOcC zW7RYEAK-7w@gcgl_KXfQ@Hgf754yJaeF;vEvX-yVwIv6S4wYloGskJrGDmCBC&zzU zaBB_dldA)4P41m?KAq^=GPVosc=e3!1J2&DPWO(QzMF8L^f|UK*!bno4yH#_e+(a= z`DOsC`K+D4Sv4bE-F@^4ac2hm@o!dXn~A38^O-m`%>vHamHT5>bZzmQt?(=N>g?#+ z?xVKp=;xq0R^7iflAQMc;#o+aIce79bE5v%W6g8Z`>|$y=Ax-tvpBWP15VB5@tzl5 zTm0rL{K{iBKf1Qmya3p->eif`_NjS6ur)ak{jJBE7p70m`Yc52PqSvR$JO6ySp@8H zokH`OY6JR3(bVJ951jqs-jM5KP3AGCv9nhe12^}|;%MsGD@%aY%Du8ATs?bbX|NyH zUE5MLHS>v+ZvfbJFZbp$XzIzgELhFGl)bqeT-|)mC9&p8d$Sj{;6kE7rECkU)S`}(Y} zK8d+4xH;eL(9~1!K(LyPulKE38UHP`W=-3psb~BSU^QFDXTCe4IbWaW%%g8&?*wkf z-Wg3j^W6okW*k4p5;||MIr{43e#!B+m**N}pMAS4*!5_BKi>^qTl{thd+liY?SZZ> z_vk&rj#batZ-bMgJh%5k*A~CM!O2mcL;Ij>OOAcPj#WR7nfv{8Kd`yACEg&g>zSHe zA2ogBGZ>uO%A7;cwZ(6LaB3^BJ44a6rM6*U$Es)SaBy;z*N_qD+Tu47oE&8>qtLY_ z$7rx))ieJCz~~XS+7j;s zaOQ73=dY%3d`<+Xw(|I&gsv@qCxfl+16t{K3c9w`cB+`Bp0THalcQX_@1Sdo-|67w zD38T=(X}PV8DPh%XZ~k`&8;o*&H|gaS@YTG+A{VWu;bM;_FS-Qm$9y$n!fS*9ys$V z>pc%$Tl~%kXI|ynU4X7F^STi1SoMtkJ~%nbJ@Er{ZSlJZoE&8>KSbA-92bKftDgB^ z0yej{#Jd!nwJYOYhORARF9$nbJ!7u`XYCy8+NtTg3D;}CCtV4)-tt-WDm3*xi(U;@ zGe(|8uYs$(jy~sH5BB5prMBy6H_?2~5u4BV&^LgcPx-rSH=?Oq-?iFl-Y1Rec;jUJ z&0y;-$NvaTJ>%u&c;ocEe+8Q(@oojXM){p>`7O2G^|=jfz2*A+7)?Fvb30hgb1MJ; zbnbwwXMKJG_T&0!yNh-Y&H0H_&riYTD}UeaZZvi0cPG8v`5Dvk#&Nv$-V1Kl`!h84 z)O#OT&F?a)_kOr~>U|LG$9lE>oc0Tv`NY{{4}r}$g;riu9!A$@%@5Gat=YK7FjnR~ z1?({>=llqoddADk@y5w9eH3httdG20AJ-|qkAYpoV#)llA;1xVfHBps8m) zp9HIUUC6kn;LY>uX*BgmI99%Ycn0iP^^AKKY(4Hb>yhgh`>(*wdY(g5Pd(3r)jYoW zndJ*`^$&^~e+^GA*Tt_sqzV+MM?$5r&<%+*Zei`7WC@cox7Ur z?K_V@fSvD@dc6EiTI_!WYxnuu@$$E8`}=5rs_h{Oj{|zaD#! zoyR)IZhCAvcAkTBkKF>qm;t;ay}GeHXVo&l8Nq7hv6~659-oZyAHaE`s>wP*Z-;O4v+LQ~K9g~1tbEbW>1BH-q{7e!Ogy!(OG zjN`{xnZL(dUwz8G!YbB#|Gf!aJ=@|HY{w`qOY-Cw~fHfb=w$CJ?pj! zSj{+o%#-zVzv-(_xp%#%nZtYNX4uS;d#K#!v(n#tUiSJ{*t6Gt){wi`{hJtDg9p>A zn|lj-HFJ4C-v+Ffz3zLtZQ<(i*$!+yx#!FENxcJWd+L?@{jaRodvogD5qs+00W7y( z|1QQ(;9>OY*1J8unz>y6oxy6U*ZbuzaP|1?3btN-j3L)YyZ80oz{V)|;O=ns`0N2T zhCarS>r>9jdzNz=h0k8Kzt6GaJjZ&@-bwRwJI&`JF3=>wdemI(E(s}=jR&AUBmweKx4^i diff --git a/piet-gpu/shader/setup.h b/piet-gpu/shader/setup.h index 6b00661..b913086 100644 --- a/piet-gpu/shader/setup.h +++ b/piet-gpu/shader/setup.h @@ -58,7 +58,7 @@ // This is the ratio of the number of elements in a binning workgroup // over the number of elements in a partition workgroup. -#define ELEMENT_BINNING_RATIO 4 +#define ELEMENT_BINNING_RATIO 2 #define BIN_INITIAL_ALLOC 64 #define BIN_ALLOC 256 diff --git a/piet-gpu/shader/state.h b/piet-gpu/shader/state.h index bc6192f..2547b93 100644 --- a/piet-gpu/shader/state.h +++ b/piet-gpu/shader/state.h @@ -9,11 +9,10 @@ struct State { vec2 translate; vec4 bbox; float linewidth; - float right_edge; uint flags; }; -#define State_size 52 +#define State_size 48 StateRef State_index(StateRef ref, uint index) { return StateRef(ref.offset + index * State_size); @@ -33,14 +32,12 @@ State State_read(StateRef ref) { uint raw9 = state[ix + 9]; uint raw10 = state[ix + 10]; uint raw11 = state[ix + 11]; - uint raw12 = state[ix + 12]; State s; s.mat = vec4(uintBitsToFloat(raw0), uintBitsToFloat(raw1), uintBitsToFloat(raw2), uintBitsToFloat(raw3)); s.translate = vec2(uintBitsToFloat(raw4), uintBitsToFloat(raw5)); s.bbox = vec4(uintBitsToFloat(raw6), uintBitsToFloat(raw7), uintBitsToFloat(raw8), uintBitsToFloat(raw9)); s.linewidth = uintBitsToFloat(raw10); - s.right_edge = uintBitsToFloat(raw11); - s.flags = raw12; + s.flags = raw11; return s; } @@ -57,7 +54,6 @@ void State_write(StateRef ref, State s) { state[ix + 8] = floatBitsToUint(s.bbox.z); state[ix + 9] = floatBitsToUint(s.bbox.w); state[ix + 10] = floatBitsToUint(s.linewidth); - state[ix + 11] = floatBitsToUint(s.right_edge); - state[ix + 12] = s.flags; + state[ix + 11] = s.flags; } diff --git a/piet-gpu/src/lib.rs b/piet-gpu/src/lib.rs index 65bbe5c..70b02f5 100644 --- a/piet-gpu/src/lib.rs +++ b/piet-gpu/src/lib.rs @@ -46,8 +46,8 @@ pub fn render_scene(rc: &mut impl RenderContext) { let circle = Circle::new(center, radius); rc.fill(circle, &color); } - /* let mut path = BezPath::new(); + /* path.move_to((100.0, 1150.0)); path.line_to((200.0, 1200.0)); path.line_to((150.0, 1250.0)); diff --git a/piet-gpu/src/render_ctx.rs b/piet-gpu/src/render_ctx.rs index 8d68b0c..da234de 100644 --- a/piet-gpu/src/render_ctx.rs +++ b/piet-gpu/src/render_ctx.rs @@ -215,6 +215,7 @@ impl PietGpuRenderContext { match el { PathEl::MoveTo(p) => { let scene_pt = to_f32_2(p); + start_pt = Some(scene_pt); last_pt = Some(scene_pt); } PathEl::LineTo(p) => { @@ -228,11 +229,13 @@ impl PietGpuRenderContext { } PathEl::ClosePath => { if let (Some(start), Some(last)) = (start_pt.take(), last_pt.take()) { - let seg = LineSeg { - p0: last, - p1: start, - }; - self.encode_line_seg(seg, is_fill); + if last != start { + let seg = LineSeg { + p0: last, + p1: start, + }; + self.encode_line_seg(seg, is_fill); + } } } _ => (), @@ -246,6 +249,7 @@ impl PietGpuRenderContext { match el { PathEl::MoveTo(p) => { let scene_pt = to_f32_2(p); + start_pt = Some(scene_pt); last_pt = Some(scene_pt); } PathEl::LineTo(p) => { @@ -283,11 +287,13 @@ impl PietGpuRenderContext { } PathEl::ClosePath => { if let (Some(start), Some(last)) = (start_pt.take(), last_pt.take()) { - let seg = LineSeg { - p0: last, - p1: start, - }; - self.encode_line_seg(seg, is_fill); + if last != start { + let seg = LineSeg { + p0: last, + p1: start, + }; + self.encode_line_seg(seg, is_fill); + } } } }