mirror of
https://github.com/italicsjenga/vello.git
synced 2025-01-10 12:41:30 +11:00
use tag flags for fill vs stroke modes in scene elements
Encode stroke vs fill as tag flags, thereby reducing the number of scene elements. Encoding change only, no functional changes. The previous Stroke and Fill commands are merged to one command, FillColor. The encoding to annotated element is divergent, which is fixed when annotated elements move to tag flags. Updates #70 Signed-off-by: Elias Naur <mail@eliasnaur.com>
This commit is contained in:
parent
a5b6bda941
commit
e9ff509ab9
|
@ -1,7 +1,7 @@
|
|||
use piet_gpu_derive::piet_gpu;
|
||||
|
||||
pub use self::scene::{
|
||||
Clip, CubicSeg, Element, Fill, LineSeg, QuadSeg, SetLineWidth, Stroke, Transform,
|
||||
Clip, CubicSeg, Element, FillColor, LineSeg, QuadSeg, SetLineWidth, Transform,
|
||||
};
|
||||
|
||||
piet_gpu! {
|
||||
|
@ -22,16 +22,13 @@ piet_gpu! {
|
|||
p2: [f32; 2],
|
||||
p3: [f32; 2],
|
||||
}
|
||||
struct Fill {
|
||||
struct FillColor {
|
||||
rgba_color: u32,
|
||||
}
|
||||
struct FillImage {
|
||||
index: u32,
|
||||
offset: [i16; 2],
|
||||
}
|
||||
struct Stroke {
|
||||
rgba_color: u32,
|
||||
}
|
||||
struct SetLineWidth {
|
||||
width: f32,
|
||||
}
|
||||
|
@ -45,19 +42,12 @@ piet_gpu! {
|
|||
}
|
||||
enum Element {
|
||||
Nop,
|
||||
// Another approach to encoding would be to use a single
|
||||
// variant but have a bool for fill/stroke. This could be
|
||||
// packed into the tag, so the on-the-wire representation
|
||||
// would be very similar to what's here.
|
||||
StrokeLine(LineSeg),
|
||||
FillLine(LineSeg),
|
||||
|
||||
StrokeQuad(QuadSeg),
|
||||
FillQuad(QuadSeg),
|
||||
StrokeCubic(CubicSeg),
|
||||
FillCubic(CubicSeg),
|
||||
Stroke(Stroke),
|
||||
Fill(Fill),
|
||||
Line(TagFlags, LineSeg),
|
||||
Quad(TagFlags, QuadSeg),
|
||||
Cubic(TagFlags, CubicSeg),
|
||||
|
||||
FillColor(TagFlags, FillColor),
|
||||
SetLineWidth(SetLineWidth),
|
||||
Transform(Transform),
|
||||
BeginClip(Clip),
|
||||
|
|
|
@ -110,30 +110,26 @@ State map_element(ElementRef ref) {
|
|||
c.pathseg_count = 0;
|
||||
c.trans_count = 0;
|
||||
switch (tag) {
|
||||
case Element_FillLine:
|
||||
case Element_StrokeLine:
|
||||
LineSeg line = Element_FillLine_read(ref);
|
||||
case Element_Line:
|
||||
LineSeg line = Element_Line_read(ref);
|
||||
c.bbox.xy = min(line.p0, line.p1);
|
||||
c.bbox.zw = max(line.p0, line.p1);
|
||||
c.pathseg_count = 1;
|
||||
break;
|
||||
case Element_FillQuad:
|
||||
case Element_StrokeQuad:
|
||||
QuadSeg quad = Element_FillQuad_read(ref);
|
||||
case Element_Quad:
|
||||
QuadSeg quad = Element_Quad_read(ref);
|
||||
c.bbox.xy = min(min(quad.p0, quad.p1), quad.p2);
|
||||
c.bbox.zw = max(max(quad.p0, quad.p1), quad.p2);
|
||||
c.pathseg_count = 1;
|
||||
break;
|
||||
case Element_FillCubic:
|
||||
case Element_StrokeCubic:
|
||||
CubicSeg cubic = Element_FillCubic_read(ref);
|
||||
case Element_Cubic:
|
||||
CubicSeg cubic = Element_Cubic_read(ref);
|
||||
c.bbox.xy = min(min(cubic.p0, cubic.p1), min(cubic.p2, cubic.p3));
|
||||
c.bbox.zw = max(max(cubic.p0, cubic.p1), max(cubic.p2, cubic.p3));
|
||||
c.pathseg_count = 1;
|
||||
break;
|
||||
case Element_Fill:
|
||||
case Element_FillColor:
|
||||
case Element_FillImage:
|
||||
case Element_Stroke:
|
||||
case Element_BeginClip:
|
||||
c.flags = FLAG_RESET_BBOX;
|
||||
c.path_count = 1;
|
||||
|
@ -291,11 +287,11 @@ void main() {
|
|||
// gains to be had from stashing in shared memory or possibly
|
||||
// registers (though register pressure is an issue).
|
||||
ElementRef this_ref = Element_index(ref, i);
|
||||
uint tag = Element_tag(this_ref).tag;
|
||||
switch (tag) {
|
||||
case Element_FillLine:
|
||||
case Element_StrokeLine:
|
||||
LineSeg line = Element_StrokeLine_read(this_ref);
|
||||
ElementTag tag = Element_tag(this_ref);
|
||||
bool is_stroke = fill_mode_from_flags(tag.flags) == MODE_STROKE;
|
||||
switch (tag.tag) {
|
||||
case Element_Line:
|
||||
LineSeg line = Element_Line_read(this_ref);
|
||||
PathStrokeCubic path_cubic;
|
||||
path_cubic.p0 = line.p0;
|
||||
path_cubic.p1 = mix(line.p0, line.p1, 1.0 / 3.0);
|
||||
|
@ -303,7 +299,7 @@ void main() {
|
|||
path_cubic.p3 = line.p1;
|
||||
path_cubic.path_ix = st.path_count;
|
||||
path_cubic.trans_ix = st.trans_count;
|
||||
if (tag == Element_StrokeLine) {
|
||||
if (is_stroke) {
|
||||
path_cubic.stroke = get_linewidth(st);
|
||||
} else {
|
||||
path_cubic.stroke = vec2(0.0);
|
||||
|
@ -311,20 +307,19 @@ void main() {
|
|||
// 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(conf.pathseg_alloc.offset + (st.pathseg_count - 1) * PathSeg_size);
|
||||
uint out_tag = tag == Element_FillLine ? PathSeg_FillCubic : PathSeg_StrokeCubic;
|
||||
uint out_tag = !is_stroke ? PathSeg_FillCubic : PathSeg_StrokeCubic;
|
||||
write_mem(conf.pathseg_alloc, path_out_ref.offset >> 2, out_tag);
|
||||
PathStrokeCubic_write(conf.pathseg_alloc, PathStrokeCubicRef(path_out_ref.offset + 4), path_cubic);
|
||||
break;
|
||||
case Element_FillQuad:
|
||||
case Element_StrokeQuad:
|
||||
QuadSeg quad = Element_StrokeQuad_read(this_ref);
|
||||
case Element_Quad:
|
||||
QuadSeg quad = Element_Quad_read(this_ref);
|
||||
path_cubic.p0 = quad.p0;
|
||||
path_cubic.p1 = mix(quad.p1, quad.p0, 1.0 / 3.0);
|
||||
path_cubic.p2 = mix(quad.p1, quad.p2, 1.0 / 3.0);
|
||||
path_cubic.p3 = quad.p2;
|
||||
path_cubic.path_ix = st.path_count;
|
||||
path_cubic.trans_ix = st.trans_count;
|
||||
if (tag == Element_StrokeQuad) {
|
||||
if (is_stroke) {
|
||||
path_cubic.stroke = get_linewidth(st);
|
||||
} else {
|
||||
path_cubic.stroke = vec2(0.0);
|
||||
|
@ -332,20 +327,19 @@ 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(conf.pathseg_alloc.offset + (st.pathseg_count - 1) * PathSeg_size);
|
||||
out_tag = tag == Element_FillQuad ? PathSeg_FillCubic : PathSeg_StrokeCubic;
|
||||
out_tag = !is_stroke ? PathSeg_FillCubic : PathSeg_StrokeCubic;
|
||||
write_mem(conf.pathseg_alloc, path_out_ref.offset >> 2, out_tag);
|
||||
PathStrokeCubic_write(conf.pathseg_alloc, PathStrokeCubicRef(path_out_ref.offset + 4), path_cubic);
|
||||
break;
|
||||
case Element_FillCubic:
|
||||
case Element_StrokeCubic:
|
||||
CubicSeg cubic = Element_StrokeCubic_read(this_ref);
|
||||
case Element_Cubic:
|
||||
CubicSeg cubic = Element_Cubic_read(this_ref);
|
||||
path_cubic.p0 = cubic.p0;
|
||||
path_cubic.p1 = cubic.p1;
|
||||
path_cubic.p2 = cubic.p2;
|
||||
path_cubic.p3 = cubic.p3;
|
||||
path_cubic.path_ix = st.path_count;
|
||||
path_cubic.trans_ix = st.trans_count;
|
||||
if (tag == Element_StrokeCubic) {
|
||||
if (is_stroke) {
|
||||
path_cubic.stroke = get_linewidth(st);
|
||||
} else {
|
||||
path_cubic.stroke = vec2(0.0);
|
||||
|
@ -353,27 +347,28 @@ 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(conf.pathseg_alloc.offset + (st.pathseg_count - 1) * PathSeg_size);
|
||||
out_tag = tag == Element_FillCubic ? PathSeg_FillCubic : PathSeg_StrokeCubic;
|
||||
out_tag = !is_stroke ? PathSeg_FillCubic : PathSeg_StrokeCubic;
|
||||
write_mem(conf.pathseg_alloc, path_out_ref.offset >> 2, out_tag);
|
||||
PathStrokeCubic_write(conf.pathseg_alloc, PathStrokeCubicRef(path_out_ref.offset + 4), path_cubic);
|
||||
break;
|
||||
case Element_Stroke:
|
||||
Stroke stroke = Element_Stroke_read(this_ref);
|
||||
case Element_FillColor:
|
||||
FillColor fill = Element_FillColor_read(this_ref);
|
||||
// TODO: merge paths when annotations use tag flags.
|
||||
if (is_stroke) {
|
||||
AnnoStroke anno_stroke;
|
||||
anno_stroke.rgba_color = stroke.rgba_color;
|
||||
anno_stroke.rgba_color = fill.rgba_color;
|
||||
vec2 lw = get_linewidth(st);
|
||||
anno_stroke.bbox = st.bbox + vec4(-lw, lw);
|
||||
anno_stroke.linewidth = st.linewidth * sqrt(abs(st.mat.x * st.mat.w - st.mat.y * st.mat.z));
|
||||
AnnotatedRef out_ref = AnnotatedRef(conf.anno_alloc.offset + (st.path_count - 1) * Annotated_size);
|
||||
Annotated_Stroke_write(conf.anno_alloc, out_ref, anno_stroke);
|
||||
break;
|
||||
case Element_Fill:
|
||||
Fill fill = Element_Fill_read(this_ref);
|
||||
} else {
|
||||
AnnoFill anno_fill;
|
||||
anno_fill.rgba_color = fill.rgba_color;
|
||||
anno_fill.bbox = st.bbox;
|
||||
out_ref = AnnotatedRef(conf.anno_alloc.offset + (st.path_count - 1) * Annotated_size);
|
||||
AnnotatedRef out_ref = AnnotatedRef(conf.anno_alloc.offset + (st.path_count - 1) * Annotated_size);
|
||||
Annotated_Fill_write(conf.anno_alloc, out_ref, anno_fill);
|
||||
}
|
||||
break;
|
||||
case Element_FillImage:
|
||||
FillImage fill_img = Element_FillImage_read(this_ref);
|
||||
|
@ -381,7 +376,7 @@ void main() {
|
|||
anno_fill_img.index = fill_img.index;
|
||||
anno_fill_img.offset = fill_img.offset;
|
||||
anno_fill_img.bbox = st.bbox;
|
||||
out_ref = AnnotatedRef(conf.anno_alloc.offset + (st.path_count - 1) * Annotated_size);
|
||||
AnnotatedRef out_ref = AnnotatedRef(conf.anno_alloc.offset + (st.path_count - 1) * Annotated_size);
|
||||
Annotated_FillImage_write(conf.anno_alloc, out_ref, anno_fill_img);
|
||||
break;
|
||||
case Element_BeginClip:
|
||||
|
|
Binary file not shown.
|
@ -14,7 +14,7 @@ struct CubicSegRef {
|
|||
uint offset;
|
||||
};
|
||||
|
||||
struct FillRef {
|
||||
struct FillColorRef {
|
||||
uint offset;
|
||||
};
|
||||
|
||||
|
@ -22,10 +22,6 @@ struct FillImageRef {
|
|||
uint offset;
|
||||
};
|
||||
|
||||
struct StrokeRef {
|
||||
uint offset;
|
||||
};
|
||||
|
||||
struct SetLineWidthRef {
|
||||
uint offset;
|
||||
};
|
||||
|
@ -78,14 +74,14 @@ CubicSegRef CubicSeg_index(CubicSegRef ref, uint index) {
|
|||
return CubicSegRef(ref.offset + index * CubicSeg_size);
|
||||
}
|
||||
|
||||
struct Fill {
|
||||
struct FillColor {
|
||||
uint rgba_color;
|
||||
};
|
||||
|
||||
#define Fill_size 4
|
||||
#define FillColor_size 4
|
||||
|
||||
FillRef Fill_index(FillRef ref, uint index) {
|
||||
return FillRef(ref.offset + index * Fill_size);
|
||||
FillColorRef FillColor_index(FillColorRef ref, uint index) {
|
||||
return FillColorRef(ref.offset + index * FillColor_size);
|
||||
}
|
||||
|
||||
struct FillImage {
|
||||
|
@ -99,16 +95,6 @@ FillImageRef FillImage_index(FillImageRef ref, uint index) {
|
|||
return FillImageRef(ref.offset + index * FillImage_size);
|
||||
}
|
||||
|
||||
struct Stroke {
|
||||
uint rgba_color;
|
||||
};
|
||||
|
||||
#define Stroke_size 4
|
||||
|
||||
StrokeRef Stroke_index(StrokeRef ref, uint index) {
|
||||
return StrokeRef(ref.offset + index * Stroke_size);
|
||||
}
|
||||
|
||||
struct SetLineWidth {
|
||||
float width;
|
||||
};
|
||||
|
@ -141,19 +127,15 @@ ClipRef Clip_index(ClipRef ref, uint index) {
|
|||
}
|
||||
|
||||
#define Element_Nop 0
|
||||
#define Element_StrokeLine 1
|
||||
#define Element_FillLine 2
|
||||
#define Element_StrokeQuad 3
|
||||
#define Element_FillQuad 4
|
||||
#define Element_StrokeCubic 5
|
||||
#define Element_FillCubic 6
|
||||
#define Element_Stroke 7
|
||||
#define Element_Fill 8
|
||||
#define Element_SetLineWidth 9
|
||||
#define Element_Transform 10
|
||||
#define Element_BeginClip 11
|
||||
#define Element_EndClip 12
|
||||
#define Element_FillImage 13
|
||||
#define Element_Line 1
|
||||
#define Element_Quad 2
|
||||
#define Element_Cubic 3
|
||||
#define Element_FillColor 4
|
||||
#define Element_SetLineWidth 5
|
||||
#define Element_Transform 6
|
||||
#define Element_BeginClip 7
|
||||
#define Element_EndClip 8
|
||||
#define Element_FillImage 9
|
||||
#define Element_size 36
|
||||
|
||||
ElementRef Element_index(ElementRef ref, uint index) {
|
||||
|
@ -210,10 +192,10 @@ CubicSeg CubicSeg_read(CubicSegRef ref) {
|
|||
return s;
|
||||
}
|
||||
|
||||
Fill Fill_read(FillRef ref) {
|
||||
FillColor FillColor_read(FillColorRef ref) {
|
||||
uint ix = ref.offset >> 2;
|
||||
uint raw0 = scene[ix + 0];
|
||||
Fill s;
|
||||
FillColor s;
|
||||
s.rgba_color = raw0;
|
||||
return s;
|
||||
}
|
||||
|
@ -228,14 +210,6 @@ FillImage FillImage_read(FillImageRef ref) {
|
|||
return s;
|
||||
}
|
||||
|
||||
Stroke Stroke_read(StrokeRef ref) {
|
||||
uint ix = ref.offset >> 2;
|
||||
uint raw0 = scene[ix + 0];
|
||||
Stroke s;
|
||||
s.rgba_color = raw0;
|
||||
return s;
|
||||
}
|
||||
|
||||
SetLineWidth SetLineWidth_read(SetLineWidthRef ref) {
|
||||
uint ix = ref.offset >> 2;
|
||||
uint raw0 = scene[ix + 0];
|
||||
|
@ -274,36 +248,20 @@ ElementTag Element_tag(ElementRef ref) {
|
|||
return ElementTag(tag_and_flags & 0xffff, tag_and_flags >> 16);
|
||||
}
|
||||
|
||||
LineSeg Element_StrokeLine_read(ElementRef ref) {
|
||||
LineSeg Element_Line_read(ElementRef ref) {
|
||||
return LineSeg_read(LineSegRef(ref.offset + 4));
|
||||
}
|
||||
|
||||
LineSeg Element_FillLine_read(ElementRef ref) {
|
||||
return LineSeg_read(LineSegRef(ref.offset + 4));
|
||||
}
|
||||
|
||||
QuadSeg Element_StrokeQuad_read(ElementRef ref) {
|
||||
QuadSeg Element_Quad_read(ElementRef ref) {
|
||||
return QuadSeg_read(QuadSegRef(ref.offset + 4));
|
||||
}
|
||||
|
||||
QuadSeg Element_FillQuad_read(ElementRef ref) {
|
||||
return QuadSeg_read(QuadSegRef(ref.offset + 4));
|
||||
}
|
||||
|
||||
CubicSeg Element_StrokeCubic_read(ElementRef ref) {
|
||||
CubicSeg Element_Cubic_read(ElementRef ref) {
|
||||
return CubicSeg_read(CubicSegRef(ref.offset + 4));
|
||||
}
|
||||
|
||||
CubicSeg Element_FillCubic_read(ElementRef ref) {
|
||||
return CubicSeg_read(CubicSegRef(ref.offset + 4));
|
||||
}
|
||||
|
||||
Stroke Element_Stroke_read(ElementRef ref) {
|
||||
return Stroke_read(StrokeRef(ref.offset + 4));
|
||||
}
|
||||
|
||||
Fill Element_Fill_read(ElementRef ref) {
|
||||
return Fill_read(FillRef(ref.offset + 4));
|
||||
FillColor Element_FillColor_read(ElementRef ref) {
|
||||
return FillColor_read(FillColorRef(ref.offset + 4));
|
||||
}
|
||||
|
||||
SetLineWidth Element_SetLineWidth_read(ElementRef ref) {
|
||||
|
|
|
@ -39,3 +39,12 @@ struct Config {
|
|||
Alloc anno_alloc;
|
||||
Alloc trans_alloc;
|
||||
};
|
||||
|
||||
// Fill modes.
|
||||
#define MODE_NONZERO 0
|
||||
#define MODE_STROKE 1
|
||||
|
||||
// fill_mode_from_flags extracts the fill mode from tag flags.
|
||||
uint fill_mode_from_flags(uint flags) {
|
||||
return flags & 0x1;
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@ use std::{borrow::Cow, ops::RangeBounds};
|
|||
use piet_gpu_types::encoder::{Encode, Encoder};
|
||||
|
||||
use piet_gpu_types::scene::{
|
||||
Clip, CubicSeg, Element, Fill, LineSeg, QuadSeg, SetLineWidth, Stroke, Transform,
|
||||
Clip, CubicSeg, Element, FillColor, LineSeg, QuadSeg, SetLineWidth, Transform,
|
||||
};
|
||||
|
||||
use piet::{
|
||||
|
@ -69,6 +69,13 @@ struct ClipElement {
|
|||
bbox: Option<Rect>,
|
||||
}
|
||||
|
||||
enum FillMode {
|
||||
// Fill path according to the non-zero winding rule.
|
||||
Nonzero = 0,
|
||||
// Fill stroked path.
|
||||
Stroke = 1,
|
||||
}
|
||||
|
||||
const TOLERANCE: f64 = 0.25;
|
||||
|
||||
impl PietGpuRenderContext {
|
||||
|
@ -143,8 +150,8 @@ impl RenderContext for PietGpuRenderContext {
|
|||
self.accumulate_bbox(|| shape.bounding_box() + Insets::uniform(width * 0.5));
|
||||
let path = shape.path_elements(TOLERANCE);
|
||||
self.encode_path(path, false);
|
||||
let stroke = Stroke { rgba_color };
|
||||
self.elements.push(Element::Stroke(stroke));
|
||||
let stroke = FillColor { rgba_color };
|
||||
self.elements.push(Element::FillColor(FillMode::Stroke as u16, stroke));
|
||||
self.path_count += 1;
|
||||
}
|
||||
_ => (),
|
||||
|
@ -168,8 +175,8 @@ impl RenderContext for PietGpuRenderContext {
|
|||
self.accumulate_bbox(|| shape.bounding_box());
|
||||
let path = shape.path_elements(TOLERANCE);
|
||||
self.encode_path(path, true);
|
||||
let fill = Fill { rgba_color };
|
||||
self.elements.push(Element::Fill(fill));
|
||||
let fill = FillColor { rgba_color };
|
||||
self.elements.push(Element::FillColor(FillMode::Nonzero as u16, fill));
|
||||
self.path_count += 1;
|
||||
}
|
||||
}
|
||||
|
@ -286,27 +293,27 @@ impl RenderContext for PietGpuRenderContext {
|
|||
impl PietGpuRenderContext {
|
||||
fn encode_line_seg(&mut self, seg: LineSeg, is_fill: bool) {
|
||||
if is_fill {
|
||||
self.elements.push(Element::FillLine(seg));
|
||||
self.elements.push(Element::Line(FillMode::Nonzero as u16, seg));
|
||||
} else {
|
||||
self.elements.push(Element::StrokeLine(seg));
|
||||
self.elements.push(Element::Line(FillMode::Stroke as u16, seg));
|
||||
}
|
||||
self.pathseg_count += 1;
|
||||
}
|
||||
|
||||
fn encode_quad_seg(&mut self, seg: QuadSeg, is_fill: bool) {
|
||||
if is_fill {
|
||||
self.elements.push(Element::FillQuad(seg));
|
||||
self.elements.push(Element::Quad(FillMode::Nonzero as u16, seg));
|
||||
} else {
|
||||
self.elements.push(Element::StrokeQuad(seg));
|
||||
self.elements.push(Element::Quad(FillMode::Stroke as u16, seg));
|
||||
}
|
||||
self.pathseg_count += 1;
|
||||
}
|
||||
|
||||
fn encode_cubic_seg(&mut self, seg: CubicSeg, is_fill: bool) {
|
||||
if is_fill {
|
||||
self.elements.push(Element::FillCubic(seg));
|
||||
self.elements.push(Element::Cubic(FillMode::Nonzero as u16, seg));
|
||||
} else {
|
||||
self.elements.push(Element::StrokeCubic(seg));
|
||||
self.elements.push(Element::Cubic(FillMode::Stroke as u16, seg));
|
||||
}
|
||||
self.pathseg_count += 1;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue