From b571e0d10cde705ca7d03b4ef987f90edd6fdcf8 Mon Sep 17 00:00:00 2001 From: Raph Levien Date: Tue, 9 Jun 2020 17:20:58 -0700 Subject: [PATCH] Continue wiring up gpu-side flattening All segments given to path coarse raster are cubics. Flatten to quadratics. This works but the quality is not (yet) good. --- piet-gpu/shader/elements.comp | 27 +++--- piet-gpu/shader/elements.spv | Bin 52612 -> 51548 bytes piet-gpu/shader/path_coarse.comp | 158 ++++++++++++++++++++----------- piet-gpu/shader/path_coarse.spv | Bin 15936 -> 19216 bytes piet-gpu/src/render_ctx.rs | 2 +- 5 files changed, 118 insertions(+), 69 deletions(-) diff --git a/piet-gpu/shader/elements.comp b/piet-gpu/shader/elements.comp index 0855219..ad39af2 100644 --- a/piet-gpu/shader/elements.comp +++ b/piet-gpu/shader/elements.comp @@ -318,29 +318,34 @@ void main() { case Element_StrokeLine: LineSeg line = Element_StrokeLine_read(this_ref); PathStrokeLine path_line; - path_line.p0 = st.mat.xy * line.p0.x + st.mat.zw * line.p0.y + st.translate; - path_line.p1 = st.mat.xy * line.p1.x + st.mat.zw * line.p1.y + st.translate; - path_line.path_ix = st.path_count; + vec2 p0 = st.mat.xy * line.p0.x + st.mat.zw * line.p0.y + st.translate; + vec2 p1 = st.mat.xy * line.p1.x + st.mat.zw * line.p1.y + st.translate; + PathStrokeCubic path_cubic; + path_cubic.p0 = p0; + path_cubic.p1 = mix(p0, p1, 1.0 / 3.0); + path_cubic.p2 = mix(p1, p0, 1.0 / 3.0); + path_cubic.p3 = p1; + path_cubic.path_ix = st.path_count; if (tag == Element_StrokeLine) { - path_line.stroke = get_linewidth(st); + path_cubic.stroke = get_linewidth(st); } else { - path_line.stroke = vec2(0.0); + path_cubic.stroke = vec2(0.0); } // We do encoding a bit by hand to minimize divergence. Another approach // would be to have a fill/stroke bool. PathSegRef path_out_ref = PathSegRef((st.pathseg_count - 1) * PathSeg_size); - uint out_tag = tag == Element_FillLine ? PathSeg_FillLine : PathSeg_StrokeLine; + uint out_tag = tag == Element_FillLine ? PathSeg_FillCubic : PathSeg_StrokeCubic; pathseg[path_out_ref.offset >> 2] = out_tag; - PathStrokeLine_write(PathStrokeLineRef(path_out_ref.offset + 4), path_line); + PathStrokeCubic_write(PathStrokeCubicRef(path_out_ref.offset + 4), path_cubic); break; case Element_FillCubic: case Element_StrokeCubic: CubicSeg cubic = Element_StrokeCubic_read(this_ref); - PathStrokeCubic path_cubic; + path_cubic; path_cubic.p0 = st.mat.xy * cubic.p0.x + st.mat.zw * cubic.p0.y + st.translate; path_cubic.p1 = st.mat.xy * cubic.p1.x + st.mat.zw * cubic.p1.y + st.translate; - path_cubic.p1 = st.mat.xy * cubic.p2.x + st.mat.zw * cubic.p2.y + st.translate; - path_cubic.p1 = st.mat.xy * cubic.p3.x + st.mat.zw * cubic.p3.y + st.translate; + path_cubic.p2 = st.mat.xy * cubic.p2.x + st.mat.zw * cubic.p2.y + st.translate; + path_cubic.p3 = st.mat.xy * cubic.p3.x + st.mat.zw * cubic.p3.y + st.translate; path_cubic.path_ix = st.path_count; if (tag == Element_StrokeCubic) { path_cubic.stroke = get_linewidth(st); @@ -350,7 +355,7 @@ void main() { // We do encoding a bit by hand to minimize divergence. Another approach // would be to have a fill/stroke bool. path_out_ref = PathSegRef((st.pathseg_count - 1) * PathSeg_size); - out_tag = tag == Element_FillLine ? PathSeg_FillCubic : PathSeg_StrokeCubic; + out_tag = tag == Element_FillCubic ? PathSeg_FillCubic : PathSeg_StrokeCubic; pathseg[path_out_ref.offset >> 2] = out_tag; PathStrokeCubic_write(PathStrokeCubicRef(path_out_ref.offset + 4), path_cubic); break; diff --git a/piet-gpu/shader/elements.spv b/piet-gpu/shader/elements.spv index 55a43f2579fa9e0941bc29175631138ea17b2a0a..e6bd773f61ae6ef12a5159cd34d15a19179705d9 100644 GIT binary patch literal 51548 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 diff --git a/piet-gpu/shader/path_coarse.comp b/piet-gpu/shader/path_coarse.comp index 693082e..1bbad42 100644 --- a/piet-gpu/shader/path_coarse.comp +++ b/piet-gpu/shader/path_coarse.comp @@ -33,6 +33,14 @@ layout(set = 0, binding = 2) buffer TileBuf { #define SX (1.0 / float(TILE_WIDTH_PX)) #define SY (1.0 / float(TILE_HEIGHT_PX)) +#define Q_ACCURACY 0.025 +#define MAX_HYPOT2 (432.0 * Q_ACCURACY * Q_ACCURACY) + +vec2 eval_cubic(vec2 p0, vec2 p1, vec2 p2, vec2 p3, float t) { + float mt = 1.0 - t; + return p0 * (mt * mt * mt) + (p1 * (mt * mt * 3.0) + (p2 * (mt * 3.0) + p3 * t) * t) * t; +} + void main() { uint element_ix = gl_GlobalInvocationID.x; PathSegRef ref = PathSegRef(element_ix * PathSeg_size); @@ -48,6 +56,7 @@ void main() { PathStrokeLine line; float dx; switch (tag) { + /* case PathSeg_FillLine: case PathSeg_StrokeLine: line = PathSeg_StrokeLine_read(ref); @@ -63,66 +72,101 @@ void main() { b = invslope; // Note: assumes square tiles, otherwise scale. a = (line.p0.x - (line.p0.y - 0.5 * float(TILE_HEIGHT_PX)) * b) * SX; break; - } - int x0 = int(floor((xmin) * SX)); - int x1 = int(ceil((xmax) * SX)); - int y0 = int(floor((ymin) * SY)); - int y1 = int(ceil((ymax) * SY)); - - uint path_ix = line.path_ix; - Path path = Path_read(PathRef(path_ix * Path_size)); - ivec4 bbox = ivec4(path.bbox); - x0 = clamp(x0, bbox.x, bbox.z); - y0 = clamp(y0, bbox.y, bbox.w); - x1 = clamp(x1, bbox.x, bbox.z); - y1 = clamp(y1, bbox.y, bbox.w); - float t = a + b * float(y0); - int stride = bbox.z - bbox.x; - int base = (y0 - bbox.y) * stride - bbox.x; - // TODO: can be tighter, use c to bound width - uint n_tile_alloc = uint((x1 - x0) * (y1 - y0)); - // Consider using subgroups to aggregate atomic add. - uint tile_offset = atomicAdd(alloc, n_tile_alloc * TileSeg_size); - TileSeg tile_seg; - for (int y = y0; y < y1; y++) { - float tile_y0 = float(y * TILE_HEIGHT_PX); - if (tag == PathSeg_FillLine && min(line.p0.y, line.p1.y) <= tile_y0) { - int xray = max(int(ceil(t - 0.5 * b)), bbox.x); - if (xray < bbox.z) { - int backdrop = line.p1.y < line.p0.y ? 1 : -1; - TileRef tile_ref = Tile_index(path.tiles, uint(base + xray)); - uint tile_el = tile_ref.offset >> 2; - atomicAdd(tile[tile_el + 1], backdrop); - } - } - int xx0 = clamp(int(floor(t - c)), x0, x1); - int xx1 = clamp(int(ceil(t + c)), x0, x1); - for (int x = xx0; x < xx1; x++) { - float tile_x0 = float(x * TILE_WIDTH_PX); - TileRef tile_ref = Tile_index(path.tiles, uint(base + x)); - uint tile_el = tile_ref.offset >> 2; - uint old = atomicExchange(tile[tile_el], tile_offset); - tile_seg.start = line.p0; - tile_seg.end = line.p1; - float y_edge = 0.0; - if (tag == PathSeg_FillLine) { - y_edge = mix(line.p0.y, line.p1.y, (tile_x0 - line.p0.x) / dx); - if (min(line.p0.x, line.p1.x) < tile_x0 && y_edge >= tile_y0 && y_edge < tile_y0 + TILE_HEIGHT_PX) { - if (line.p0.x > line.p1.x) { - tile_seg.end = vec2(tile_x0, y_edge); - } else { - tile_seg.start = vec2(tile_x0, y_edge); + */ + case PathSeg_FillCubic: + case PathSeg_StrokeCubic: + PathStrokeCubic cubic = PathSeg_StrokeCubic_read(ref); + vec2 err_v = 3.0 * (cubic.p2 - cubic.p1) + cubic.p0 - cubic.p3; + float err = err_v.x * err_v.x + err_v.y * err_v.y; + // The number of quadratics. + uint n = max(uint(ceil(pow(err * (1.0 / MAX_HYPOT2), 1.0 / 6.0))), 1); + vec2 p0 = cubic.p0; + float step = 1.0 / float(n); + uint path_ix = cubic.path_ix; + Path path = Path_read(PathRef(path_ix * Path_size)); + ivec4 bbox = ivec4(path.bbox); + for (int i = 0; i < n; i++) { + // TODO: probably need special logic to make sure it's manifold + float t = float(i + 1) * step; + vec2 p2 = eval_cubic(cubic.p0, cubic.p1, cubic.p2, cubic.p3, t); + /* + vec2 p1 = eval_cubic(cubic.p0, cubic.p1, cubic.p2, cubic.p3, t - 0.5 * step); + p1 = 2.0 * p1 - 0.5 * (p0 + p2); + */ + + xmin = min(p0.x, p2.x) - cubic.stroke.x; + xmax = max(p0.x, p2.x) + cubic.stroke.x; + ymin = min(p0.y, p2.y) - cubic.stroke.y; + ymax = max(p0.y, p2.y) + cubic.stroke.y; + float dx = p2.x - p0.x; + float dy = p2.y - p0.y; + // Set up for per-scanline coverage formula, below. + float invslope = abs(dy) < 1e-9 ? 1e9 : dx / dy; + c = (cubic.stroke.x + abs(invslope) * (0.5 * float(TILE_HEIGHT_PX) + cubic.stroke.y)) * SX; + b = invslope; // Note: assumes square tiles, otherwise scale. + a = (p0.x - (p0.y - 0.5 * float(TILE_HEIGHT_PX)) * b) * SX; + + int x0 = int(floor((xmin) * SX)); + int x1 = int(ceil((xmax) * SX)); + int y0 = int(floor((ymin) * SY)); + int y1 = int(ceil((ymax) * SY)); + + x0 = clamp(x0, bbox.x, bbox.z); + y0 = clamp(y0, bbox.y, bbox.w); + x1 = clamp(x1, bbox.x, bbox.z); + y1 = clamp(y1, bbox.y, bbox.w); + float xc = a + b * float(y0); + int stride = bbox.z - bbox.x; + int base = (y0 - bbox.y) * stride - bbox.x; + // TODO: can be tighter, use c to bound width + uint n_tile_alloc = uint((x1 - x0) * (y1 - y0)); + // Consider using subgroups to aggregate atomic add. + uint tile_offset = atomicAdd(alloc, n_tile_alloc * TileSeg_size); + TileSeg tile_seg; + for (int y = y0; y < y1; y++) { + float tile_y0 = float(y * TILE_HEIGHT_PX); + if (tag == PathSeg_FillCubic && min(p0.y, p2.y) <= tile_y0) { + int xray = max(int(ceil(xc - 0.5 * b)), bbox.x); + if (xray < bbox.z) { + int backdrop = p2.y < p0.y ? 1 : -1; + TileRef tile_ref = Tile_index(path.tiles, uint(base + xray)); + uint tile_el = tile_ref.offset >> 2; + atomicAdd(tile[tile_el + 1], backdrop); } - } else { - y_edge = 1e9; } + int xx0 = clamp(int(floor(xc - c)), x0, x1); + int xx1 = clamp(int(ceil(xc + c)), x0, x1); + for (int x = xx0; x < xx1; x++) { + float tile_x0 = float(x * TILE_WIDTH_PX); + TileRef tile_ref = Tile_index(path.tiles, uint(base + x)); + uint tile_el = tile_ref.offset >> 2; + uint old = atomicExchange(tile[tile_el], tile_offset); + tile_seg.start = p0; + tile_seg.end = p2; + float y_edge = 0.0; + if (tag == PathSeg_FillCubic) { + y_edge = mix(p0.y, p2.y, (tile_x0 - p0.x) / dx); + if (min(p0.x, p2.x) < tile_x0 && y_edge >= tile_y0 && y_edge < tile_y0 + TILE_HEIGHT_PX) { + if (p0.x > p2.x) { + tile_seg.end = vec2(tile_x0, y_edge); + } else { + tile_seg.start = vec2(tile_x0, y_edge); + } + } else { + y_edge = 1e9; + } + } + tile_seg.y_edge = y_edge; + tile_seg.next.offset = old; + TileSeg_write(TileSegRef(tile_offset), tile_seg); + tile_offset += TileSeg_size; + } + xc += b; + base += stride; } - tile_seg.y_edge = y_edge; - tile_seg.next.offset = old; - TileSeg_write(TileSegRef(tile_offset), tile_seg); - tile_offset += TileSeg_size; + + p0 = p2; } - t += b; - base += stride; + break; } } diff --git a/piet-gpu/shader/path_coarse.spv b/piet-gpu/shader/path_coarse.spv index 7098a630e9193c4f1362f158e1627dc0b19dd1c5..0d10ea29b09467422501158eb90a77ad575156a6 100644 GIT binary patch literal 19216 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 literal 15936 zcmZvi2Vh=R8HR63(z5p+C1sY;LfJzgEz~dy6bd3@4QZ2>*fa@kT3SJEL6#!m0vsrc zDB{2Y4pb1_3-{gw2jWIWQSo{1e_wk1;U|alzVG*)@B7ZV=iYnrHy!KkKB=lERO|EK zE$dbFXNzh*l&adOnppR}bLP#NzI=RO`XPrNsKcgJNA0K2X83f`chZ*j4~=Mel(sp# z+7`5Kn!dIU{xi)3kj`qus&`Ib@9C%a&Y9h}aBQq^`S|ML!M@?4k-@%!p=E;$$A?x9 z>bHL3H#D+vc*Q{J(1k~tzpI+We^oWNfBb@Z2vsJ$~P^!Ty1%_^ens zKJ6)`PFpc!#?g%FBGM-G%c#DK|29vY!Nv82oR6BHb@SP%+8SO59bDWu-oN<&^3+3{ z1jgSA-&XuhtL=+%>(=h6wYJCD?#URP)sEn^hKB1Ew?4U_vc7J(K7B(Y1B0tlUNfq$ zZN-!GpNwy-zRqe_a6N?H>%JSk^K>!HCHJ!~S7)^+Tpx9P@4OL*GJ7yS=0XT#;?vV_p^Mwe;Hd6t+P_IrooYc zCw<&&tNR8A7IR-%w?6K*k-=3CL)pG!YbJKzMazc92g~Jc6;_wu?7gOpX)6~URJTPl zrv1OAneLO<;{f8f=G#&EKxnO3M|CimTYwrmtE2SkzeqE@t9k}~vma-z;6}7|H9upl z@$$jNC>_D2s`7C$Kbj21U-Z9k{Q4+)>&;)jMWZ1KZdyrX(PpjCTk zbv<~je_8)hdh58EK6809c->q&t6SkNniFvzazEo}_Kv?zz{h#qL0`_}&K7Ux(NWzE z&l-Ln+{)Wk{TVzsJh*glWZXv!vDUAjt&4~IdWT0B^bemjvT}4`|M<}8$Vn&QYu?A` zb8Y?u=H5r|s-6JP93CEBSg(F-{nh-8^wn2@xlFA6+;fe_Raxij-s?98y}2gnSYw{h z;C1WQS#1jUIUf6FZT2nUtCqIj7p~DxHSe$QNBJJ`)rEap&13JV4ucQWYtm6YL%iCW zx~f^=p^=r#heyYrycToOQuBQ9g1Y98st?@X;9>A8cB}KcP|U6quLQ4d^ozx{-dU{y zyJ}t->%FYuneSCK&wlExu7T%yW8B-}-ms3n6U-eqG(g4jyY=l~-qb&_x(`0m=kDsu z^5fT4ea;xF&4b0b52CRYb)4_U&IFA6Fnrare$Dmx$Keb57cLoCHaZrqgNt0pbQ9Hn zTwApA+HTawH_4d6Vd8dF+rd|{nBwjlV};wI+78B_apRfmTcd7pt+<~^>B&&-%6 z?`-(!@IXDclVkJ2(&Rh?EzeHZ<63wb|GI+rV)y+!k>=UrM55+-wL9ETFY{CDsBvfg z?AlEOAIJMFn^LnDe+#&bcWYxS&yL|c+t4bm0ISZ zpE1sf; z$=IF1j#cZ%*R@UUQ&{6&8k>IF9KRcV#=EBat2v)N8k=iB8NMgIn(?h=FM2h{8Eaqq z#M%#REH&4{cfIqsxkl>NIE`LE?bbM*-t}|5Hm`>-#ctXJ+I|hMUyKDm0_?b5s3Uvd zn%v`Za~;$8w6qp?pSSY0u6qyMkN&ghwK*sA+V|2@hx}ApIes48y%hg*!LDC;AGoXF zgW#;$5ZJZw`kLPdo7^?ayqAHK-*vf|R_41A?!Iyz-a>C|*Wp%rxpCi0Z_R2)H~h9n z(|#A&yk6VX{UPuZ+-Rxe9=Ll{|NH6ncW=nQ(r~Y{`{*z9)?uC6|4KiBrfz<@&jU5> ze`~N~lK)@e18I|+XN9&j$2izI`7AJ|d_tpbjinQ8ENhw#?i;)M!0?mdQ$ZyWa< zRoXpEmE7}GxYyV-RmnY9mE5yc$vt0%yIyMweiz&`R_wdOJ!6HtM?7PNyI!8L!mY=1 zR>?hQg`3ZFR>?hIg*)D}Rk-mzUxjP;d{uJKSK+=dJX@9Ab5*$cJy(_7b5*$UJy(^y zyN!FkirxA=V}+aFGgiqxUxl0B^Hs@bwsFr_vHM=}j1_J^&sX8Tdpuu->+ktWK9jq~ z=hNS5kJ5T*$8gVhAO3@;ek^yG_me!fe}dIs!gzfjr>Xf|o6C5grT?a>JKp^DlC1n@Cghxga)e_uCsm)}yy}nz4)jT)!(2VK3U~4pO@!O{Hb1h51ZPB%DOuhAc z4a`sdjx>h$#MmBeu8Z4Z?0}~2GHN!)j^OQR>elQtQY~?I20vZRyP#`}-{i)xz2;rf zwWa26FhBKoL&nga7*oJcSMzS@+SWET?+!MOx;6V8S4*5d!Kt~ITv_M6(6z;H@5axX zOTVe;+EVjAV1DX#Hiq`Z*cY6d%NYBiYs)(C4>pdvHT$knOPuN8r>pq@bZzlFu<>iJ zc?P<+)O-+_pL(5*p*=AU20vZRhoEcAIv)x)j=DAbK2%Gb!@HjbHn| zKMGx2*63)kW7W;)`&KP+jsYiMxz@*`Ym47;ji32SzaDgL$u|@1SatLHK3B_rIUcOG zG54?c$_Ze8xNECQ+lSeYo%GM7X`4;+xpES{AD?U5PNbbe^I0M`S10oo}JBwbP^*RIWy0$+n&P3Ce81ul6&3c># z=BHi{ZHf0RaN?Ege-65~?5}5o&!(wg-puPS&=(H6hwg4NHXIj6bwYN_>k zU~APjpI)B&&Iemx`+n?4(-yx4g5E6wFWkJDK(ou9#>1F|an*XqaA}xXZvh z(Gqt#SgnjZ4(F%7H?$}23a~cgUPv!b+>5|_&=PkQSgnk^8qQB$ulB@!0a%-HSJKN9 z_Y&|lTH?MCtX9T-5uBg8UhRqdVz4&jUQ92a$$s=qw-)SPIRb1h&rO%Y)%9OPFOTgd zV6~jFt`O5Mr+LQOjqz84)g6Boz1%Z|zw2HNo=UH-{W5wr>$xBO*U{7*e@(;n^_pJ~_gWio3H>W*`t&sM^m%2Y$LCdzkKZ#S&a2VXH|8oi<~3k` z>hDX;VGMn&!F<{?_6D%mFY#{#TSM+Kmp*f)UPn~8rjxP2Yoh^8K&H#I)xI^2S$o*Lc^=BKW~9LCVc8qB9XHM|AveoOpY z!R_ntRy6ha+}8M%>+m)-_0;foFh6w-<}ijn)?hyE*5Ets9pJu#-vOTAaIeEV!LHqC zt7Q)F1v}4j9p496kI(xXpC006y*_}ZekpmZ z?Jlt6)Xj4zy;}S~2)6db{1CW(eLsw*o|qp2J5D`u?g1Oyd)mAo1?#7t*dGHMyR7%) zaP`E#7wlMd>%E&^EqOixc8`SL4<4pv`~zTp)Z_C>u-7#FQ()(uF`owOqn`Rd12&d6 zpBX;WJ_}a2uKVca&TSU9&x0q>%4gsg;QHk`_a(5}7ikak`-w5X40f#dbq`G+k|clLj$&acydgXTy3HygWsVtos2jPP%RU7z%>VAFSs0j=3Lx09Uv6@6yX1@BDuV_IJ%Yn%qBvtGOPY6Mq8s zV;$OlOjENCan2z>1#e1gKhORQOLty9e zv8Lu91+l@7n2a?auGF^nRS5KEI)Em~U z>c;onwkcRG=OpjP&EV<};3MB0tmbpg7=B-B#*T1()N^m_ z1jeO4Q)|z?u`^g(>fQxB+~o3FPKI9y&)H&ExN)Y@9IL-RuAkqpYEPY0z-67g!L4&G z>*+jphwG!BI`;q@KlaqQC%U%Oxfi&sb8mQA=Tvy=bgcgRSZ6oA_Qcv3Z0*|o4p{Em z??>-FXz%-H8vS&dAMFP;cKgIS5NwR_8DR6}-aiPekGl7}e1Dp;%_Yv*L%_z$`{z)w zTKWDt46bhNeqSxm_#?pOeR?F^c)3rH0_&rmeR?!lJ@@G`;P(6USTuEW`W?7j?DyY} z&wbhh?q;p@(WZ~zp{wUUods4a@6+Sq>bXx(0ITIboe5TRp5B+w1gqtq>;>nZ)E2)J z!JlJOJk*>|PJ-*3dr-SI&ZgI9jbp?=1)TS^{u6=YkWzr-(lvU0a@6&jUMFJ+b=0hjG2~o!9wr z{nULPS!X}k``mxCw`S|nFKebfwJZQXT`ddIwZ(6s@pG;{wA3?*t}W-NMPPILd%H2T z$9FNX+lu9ftuOP>|AD{0mx z&RSmte!6S23SC?LRyTg_*W?B0+U{xA=VGv9)ve=&^r=JJCA3Rv)*;UNya?>|3V$)! z^_oju@AoxeebjTmt_7F(t6V?V%Dm<<{FnaedKu-*r&d$z}91K|GnyJu(|WxmFuIw&)t`TXVbh!p1EEI*5B`u zQ?HtS8FLNTXRzOe`S&+3hpSodwe)g*{ac*t!N${e9lhLl3tjaJ{x^f(G1?OUm0;uN z%=Rj{n!lGCN1K{!FrD7@vUj}aomYeRq2(R<8n9ZP$=cK$zaPEhr_np!=g|#de|HJL z5q>*7_t{NwHT|qdn_BX}7JO$j-g;gK_Z^;kUJqB(&+*#StjFJtt;as`-hl1FV*Jf; zwaiDGn&ZFPjQ4lp|L|lxg67|C_-~v3{k!{o-^4OjSF5{jLSM%@R61N|mxaWg2b^*9$ z#k082l3|)!>`TF3>)1!Y zYI#SEf*qrt_s4}`?+N#%&kMPJiMbr?bxzE2uv+XZz+SJ|SAx}&^CGZg)RS`+*qnLB z$n{Ii)nKnx?$H;3^*@4UjdFeBe+k%YkQ!cC<8}5I!F>+I{$j9NYFq<$jCyKZ3pS_k zDs#%$(9F3J{iQVR|K<56&a-eLcx#%UEonXrx1isO=Cg1c`poO{MtAKqmn*>PdG=fh zR&(yzJ6D0TceH2h)nIMbBu-7%yFJa%wzSl=9oU+7p!fN_KK=EyNwm~>4OqXj#+Sp@ z^Srwjtmggbd)x8X(bQc#W6JY)Fs}e_N>jI1d1~De+)eYd3(Z=0qMzJgpV_<8ta}Q5 z>U=d=pR&%^z}2%pH-H_R@1$=6tKCS;TwV)yoHplTJ+GswTdO#=?g^es^RpMtT6d@4 zn`V9c(C58(GuU+re{&nZqmAEL@VmfwH$3xwBiuaYeBT6D&)&HOtmfYFI#|Okw5-S5 zz-pQM+rer*wCuIp!MD-OqdjBa0oG<*=OT~oo!~O=yWncQw8VWkIB~US?0dl4jO&`n zV|y>SjQc*g+Nrd}eLpyHwP)-Hz}k%K+R9`5AlNy4mNUUb`VZ68K17SpN5J}IZ9fWD zyN4E^kAbZ@aXt=KE92bT_$1DKa5dx1WryrR{|TBkn8O(Qc-`-(e}Lv*@On5G`6p

eH_0h{by*}-Rt7)_4U9rXnv;C-0S<%AJE`w^as-1 z_Xp8upMM@aiI#o)1+ZhRKQ(_5te!Rb5?C$!));E>|1wxD`}RSwS`W>A@D=*6(yYfk zJv7H|K>szGHs1vk>A&7+*+1WaXa5-2HCEFv`M(J+^M4Djmi=x1Z_|=rJ^8=W*pmOd zaJA(B9ys}pYkoETlK=bQGXD?YYPk>0|3jMjz0N(f`ea$nz=8gmHYgUjV<~9 P1W!KWm`_c={C@R6I6yN5 diff --git a/piet-gpu/src/render_ctx.rs b/piet-gpu/src/render_ctx.rs index 221b737..f914a2e 100644 --- a/piet-gpu/src/render_ctx.rs +++ b/piet-gpu/src/render_ctx.rs @@ -242,7 +242,7 @@ impl PietGpuRenderContext { } fn encode_path(&mut self, path: impl Iterator, is_fill: bool) { - let flatten = true; + let flatten = false; if flatten { let mut start_pt = None; let mut last_pt = None;