diff --git a/piet-gpu/shader/elements.comp b/piet-gpu/shader/elements.comp index ad39af2..905f875 100644 --- a/piet-gpu/shader/elements.comp +++ b/piet-gpu/shader/elements.comp @@ -317,7 +317,6 @@ void main() { case Element_FillLine: case Element_StrokeLine: LineSeg line = Element_StrokeLine_read(this_ref); - PathStrokeLine path_line; 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; @@ -338,6 +337,30 @@ void main() { pathseg[path_out_ref.offset >> 2] = out_tag; PathStrokeCubic_write(PathStrokeCubicRef(path_out_ref.offset + 4), path_cubic); break; + case Element_FillQuad: + case Element_StrokeQuad: + QuadSeg quad = Element_StrokeQuad_read(this_ref); + p0 = st.mat.xy * quad.p0.x + st.mat.zw * quad.p0.y + st.translate; + p1 = st.mat.xy * quad.p1.x + st.mat.zw * quad.p1.y + st.translate; + vec2 p2 = st.mat.xy * quad.p2.x + st.mat.zw * quad.p2.y + st.translate; + path_cubic; + path_cubic.p0 = p0; + path_cubic.p1 = mix(p1, p0, 1.0 / 3.0); + path_cubic.p2 = mix(p1, p2, 1.0 / 3.0); + path_cubic.p3 = p2; + path_cubic.path_ix = st.path_count; + if (tag == Element_StrokeQuad) { + path_cubic.stroke = get_linewidth(st); + } else { + 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. + path_out_ref = PathSegRef((st.pathseg_count - 1) * PathSeg_size); + out_tag = tag == Element_FillQuad ? PathSeg_FillCubic : PathSeg_StrokeCubic; + pathseg[path_out_ref.offset >> 2] = out_tag; + PathStrokeCubic_write(PathStrokeCubicRef(path_out_ref.offset + 4), path_cubic); + break; case Element_FillCubic: case Element_StrokeCubic: CubicSeg cubic = Element_StrokeCubic_read(this_ref); diff --git a/piet-gpu/shader/elements.spv b/piet-gpu/shader/elements.spv index e6bd773..552956c 100644 Binary files a/piet-gpu/shader/elements.spv and b/piet-gpu/shader/elements.spv differ diff --git a/piet-gpu/shader/path_coarse.comp b/piet-gpu/shader/path_coarse.comp index 1bbad42..c7fef8c 100644 --- a/piet-gpu/shader/path_coarse.comp +++ b/piet-gpu/shader/path_coarse.comp @@ -33,7 +33,8 @@ 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 ACCURACY 0.25 +#define Q_ACCURACY 0.01 #define MAX_HYPOT2 (432.0 * Q_ACCURACY * Q_ACCURACY) vec2 eval_cubic(vec2 p0, vec2 p1, vec2 p2, vec2 p3, float t) { @@ -76,10 +77,16 @@ void main() { case PathSeg_FillCubic: case PathSeg_StrokeCubic: PathStrokeCubic cubic = PathSeg_StrokeCubic_read(ref); + // Commented out code is for computing error bound on conversion to quadratics + /* 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); + */ + // This calculation is based on Sederberg, CAGD Notes section 10.6 + vec2 l = max(abs(cubic.p0 + cubic.p2 - 2 * cubic.p1), abs(cubic.p1 + cubic.p3 - 2 * cubic.p2)); + uint n = max(uint(ceil(sqrt(length(l) * (0.75 / ACCURACY)))), 1); vec2 p0 = cubic.p0; float step = 1.0 / float(n); uint path_ix = cubic.path_ix; diff --git a/piet-gpu/shader/path_coarse.spv b/piet-gpu/shader/path_coarse.spv index 0d10ea2..f91fbb5 100644 Binary files a/piet-gpu/shader/path_coarse.spv and b/piet-gpu/shader/path_coarse.spv differ