mirror of
https://github.com/italicsjenga/vello.git
synced 2025-01-10 20:51:29 +11:00
replace per-element fill mode flags with a SetFillMode element
Fixes #70 Signed-off-by: Elias Naur <mail@eliasnaur.com>
This commit is contained in:
parent
bb61f875dc
commit
eb37db1b05
|
@ -1,7 +1,7 @@
|
||||||
use piet_gpu_derive::piet_gpu;
|
use piet_gpu_derive::piet_gpu;
|
||||||
|
|
||||||
pub use self::scene::{
|
pub use self::scene::{
|
||||||
Clip, CubicSeg, Element, FillColor, LineSeg, QuadSeg, SetLineWidth, Transform,
|
Clip, CubicSeg, Element, FillColor, LineSeg, QuadSeg, SetFillMode, SetLineWidth, Transform,
|
||||||
};
|
};
|
||||||
|
|
||||||
piet_gpu! {
|
piet_gpu! {
|
||||||
|
@ -40,19 +40,23 @@ piet_gpu! {
|
||||||
bbox: [f32; 4],
|
bbox: [f32; 4],
|
||||||
// TODO: add alpha?
|
// TODO: add alpha?
|
||||||
}
|
}
|
||||||
|
struct SetFillMode {
|
||||||
|
fill_mode: u32,
|
||||||
|
}
|
||||||
enum Element {
|
enum Element {
|
||||||
Nop,
|
Nop,
|
||||||
|
|
||||||
Line(TagFlags, LineSeg),
|
Line(LineSeg),
|
||||||
Quad(TagFlags, QuadSeg),
|
Quad(QuadSeg),
|
||||||
Cubic(TagFlags, CubicSeg),
|
Cubic(CubicSeg),
|
||||||
|
|
||||||
FillColor(TagFlags, FillColor),
|
FillColor(FillColor),
|
||||||
SetLineWidth(SetLineWidth),
|
SetLineWidth(SetLineWidth),
|
||||||
Transform(Transform),
|
Transform(Transform),
|
||||||
BeginClip(Clip),
|
BeginClip(Clip),
|
||||||
EndClip(Clip),
|
EndClip(Clip),
|
||||||
FillImage(FillImage),
|
FillImage(FillImage),
|
||||||
|
SetFillMode(SetFillMode),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -63,6 +63,11 @@ uint state_flag_index(uint partition_ix) {
|
||||||
#define FLAG_SET_LINEWIDTH 1
|
#define FLAG_SET_LINEWIDTH 1
|
||||||
#define FLAG_SET_BBOX 2
|
#define FLAG_SET_BBOX 2
|
||||||
#define FLAG_RESET_BBOX 4
|
#define FLAG_RESET_BBOX 4
|
||||||
|
#define FLAG_SET_FILL_MODE 8
|
||||||
|
// Fill modes take up the next bit. Non-zero fill is 0, stroke is 1.
|
||||||
|
#define LG_FILL_MODE 4
|
||||||
|
#define FILL_MODE_BITS 1
|
||||||
|
#define FILL_MODE_MASK (FILL_MODE_BITS << LG_FILL_MODE)
|
||||||
|
|
||||||
// This is almost like a monoid (the interaction between transformation and
|
// This is almost like a monoid (the interaction between transformation and
|
||||||
// bounding boxes is approximate)
|
// bounding boxes is approximate)
|
||||||
|
@ -88,8 +93,11 @@ 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.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.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.linewidth = (b.flags & FLAG_SET_LINEWIDTH) == 0 ? a.linewidth : b.linewidth;
|
||||||
c.flags = (a.flags & (FLAG_SET_LINEWIDTH | FLAG_SET_BBOX)) | b.flags;
|
c.flags = (a.flags & (FLAG_SET_LINEWIDTH | FLAG_SET_BBOX | FLAG_SET_FILL_MODE)) | b.flags;
|
||||||
c.flags |= (a.flags & FLAG_RESET_BBOX) >> 1;
|
c.flags |= (a.flags & FLAG_RESET_BBOX) >> 1;
|
||||||
|
uint fill_mode = (b.flags & FLAG_SET_FILL_MODE) == 0 ? a.flags : b.flags;
|
||||||
|
fill_mode &= FILL_MODE_MASK;
|
||||||
|
c.flags = (c.flags & ~FILL_MODE_MASK) | fill_mode;
|
||||||
c.path_count = a.path_count + b.path_count;
|
c.path_count = a.path_count + b.path_count;
|
||||||
c.pathseg_count = a.pathseg_count + b.pathseg_count;
|
c.pathseg_count = a.pathseg_count + b.pathseg_count;
|
||||||
c.trans_count = a.trans_count + b.trans_count;
|
c.trans_count = a.trans_count + b.trans_count;
|
||||||
|
@ -148,6 +156,10 @@ State map_element(ElementRef ref) {
|
||||||
c.translate = t.translate;
|
c.translate = t.translate;
|
||||||
c.trans_count = 1;
|
c.trans_count = 1;
|
||||||
break;
|
break;
|
||||||
|
case Element_SetFillMode:
|
||||||
|
SetFillMode fm = Element_SetFillMode_read(ref);
|
||||||
|
c.flags = FLAG_SET_FILL_MODE | (fm.fill_mode << LG_FILL_MODE);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
@ -288,7 +300,7 @@ void main() {
|
||||||
// registers (though register pressure is an issue).
|
// registers (though register pressure is an issue).
|
||||||
ElementRef this_ref = Element_index(ref, i);
|
ElementRef this_ref = Element_index(ref, i);
|
||||||
ElementTag tag = Element_tag(this_ref);
|
ElementTag tag = Element_tag(this_ref);
|
||||||
uint fill_mode = fill_mode_from_flags(tag.flags);
|
uint fill_mode = fill_mode_from_flags(st.flags >> LG_FILL_MODE);
|
||||||
bool is_stroke = fill_mode == MODE_STROKE;
|
bool is_stroke = fill_mode == MODE_STROKE;
|
||||||
switch (tag.tag) {
|
switch (tag.tag) {
|
||||||
case Element_Line:
|
case Element_Line:
|
||||||
|
|
Binary file not shown.
|
@ -34,6 +34,10 @@ struct ClipRef {
|
||||||
uint offset;
|
uint offset;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct SetFillModeRef {
|
||||||
|
uint offset;
|
||||||
|
};
|
||||||
|
|
||||||
struct ElementRef {
|
struct ElementRef {
|
||||||
uint offset;
|
uint offset;
|
||||||
};
|
};
|
||||||
|
@ -126,6 +130,16 @@ ClipRef Clip_index(ClipRef ref, uint index) {
|
||||||
return ClipRef(ref.offset + index * Clip_size);
|
return ClipRef(ref.offset + index * Clip_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct SetFillMode {
|
||||||
|
uint fill_mode;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define SetFillMode_size 4
|
||||||
|
|
||||||
|
SetFillModeRef SetFillMode_index(SetFillModeRef ref, uint index) {
|
||||||
|
return SetFillModeRef(ref.offset + index * SetFillMode_size);
|
||||||
|
}
|
||||||
|
|
||||||
#define Element_Nop 0
|
#define Element_Nop 0
|
||||||
#define Element_Line 1
|
#define Element_Line 1
|
||||||
#define Element_Quad 2
|
#define Element_Quad 2
|
||||||
|
@ -136,6 +150,7 @@ ClipRef Clip_index(ClipRef ref, uint index) {
|
||||||
#define Element_BeginClip 7
|
#define Element_BeginClip 7
|
||||||
#define Element_EndClip 8
|
#define Element_EndClip 8
|
||||||
#define Element_FillImage 9
|
#define Element_FillImage 9
|
||||||
|
#define Element_SetFillMode 10
|
||||||
#define Element_size 36
|
#define Element_size 36
|
||||||
|
|
||||||
ElementRef Element_index(ElementRef ref, uint index) {
|
ElementRef Element_index(ElementRef ref, uint index) {
|
||||||
|
@ -243,6 +258,14 @@ Clip Clip_read(ClipRef ref) {
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SetFillMode SetFillMode_read(SetFillModeRef ref) {
|
||||||
|
uint ix = ref.offset >> 2;
|
||||||
|
uint raw0 = scene[ix + 0];
|
||||||
|
SetFillMode s;
|
||||||
|
s.fill_mode = raw0;
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
ElementTag Element_tag(ElementRef ref) {
|
ElementTag Element_tag(ElementRef ref) {
|
||||||
uint tag_and_flags = scene[ref.offset >> 2];
|
uint tag_and_flags = scene[ref.offset >> 2];
|
||||||
return ElementTag(tag_and_flags & 0xffff, tag_and_flags >> 16);
|
return ElementTag(tag_and_flags & 0xffff, tag_and_flags >> 16);
|
||||||
|
@ -284,3 +307,7 @@ FillImage Element_FillImage_read(ElementRef ref) {
|
||||||
return FillImage_read(FillImageRef(ref.offset + 4));
|
return FillImage_read(FillImageRef(ref.offset + 4));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SetFillMode Element_SetFillMode_read(ElementRef ref) {
|
||||||
|
return SetFillMode_read(SetFillModeRef(ref.offset + 4));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@ use std::{borrow::Cow, ops::RangeBounds};
|
||||||
use piet_gpu_types::encoder::{Encode, Encoder};
|
use piet_gpu_types::encoder::{Encode, Encoder};
|
||||||
|
|
||||||
use piet_gpu_types::scene::{
|
use piet_gpu_types::scene::{
|
||||||
Clip, CubicSeg, Element, FillColor, LineSeg, QuadSeg, SetLineWidth, Transform,
|
Clip, CubicSeg, Element, FillColor, SetFillMode, LineSeg, QuadSeg, SetLineWidth, Transform,
|
||||||
};
|
};
|
||||||
|
|
||||||
use piet::{
|
use piet::{
|
||||||
|
@ -32,6 +32,7 @@ pub struct PietGpuRenderContext {
|
||||||
// Will probably need direct accesss to hal Device to create images etc.
|
// Will probably need direct accesss to hal Device to create images etc.
|
||||||
inner_text: PietGpuText,
|
inner_text: PietGpuText,
|
||||||
stroke_width: f32,
|
stroke_width: f32,
|
||||||
|
fill_mode: FillMode,
|
||||||
// We're tallying these cpu-side for expedience, but will probably
|
// We're tallying these cpu-side for expedience, but will probably
|
||||||
// move this to some kind of readback from element processing.
|
// move this to some kind of readback from element processing.
|
||||||
/// The count of elements that make it through to coarse rasterization.
|
/// The count of elements that make it through to coarse rasterization.
|
||||||
|
@ -69,6 +70,7 @@ struct ClipElement {
|
||||||
bbox: Option<Rect>,
|
bbox: Option<Rect>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone,Copy,PartialEq)]
|
||||||
enum FillMode {
|
enum FillMode {
|
||||||
// Fill path according to the non-zero winding rule.
|
// Fill path according to the non-zero winding rule.
|
||||||
Nonzero = 0,
|
Nonzero = 0,
|
||||||
|
@ -89,6 +91,7 @@ impl PietGpuRenderContext {
|
||||||
elements,
|
elements,
|
||||||
inner_text,
|
inner_text,
|
||||||
stroke_width,
|
stroke_width,
|
||||||
|
fill_mode: FillMode::Nonzero,
|
||||||
path_count: 0,
|
path_count: 0,
|
||||||
pathseg_count: 0,
|
pathseg_count: 0,
|
||||||
trans_count: 0,
|
trans_count: 0,
|
||||||
|
@ -116,6 +119,14 @@ 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.fill_mode = fill_mode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl RenderContext for PietGpuRenderContext {
|
impl RenderContext for PietGpuRenderContext {
|
||||||
type Brush = PietGpuBrush;
|
type Brush = PietGpuBrush;
|
||||||
type Image = PietGpuImage;
|
type Image = PietGpuImage;
|
||||||
|
@ -143,6 +154,7 @@ impl RenderContext for PietGpuRenderContext {
|
||||||
.push(Element::SetLineWidth(SetLineWidth { width: width_f32 }));
|
.push(Element::SetLineWidth(SetLineWidth { width: width_f32 }));
|
||||||
self.stroke_width = width_f32;
|
self.stroke_width = width_f32;
|
||||||
}
|
}
|
||||||
|
set_fill_mode(self, FillMode::Stroke);
|
||||||
let brush = brush.make_brush(self, || shape.bounding_box()).into_owned();
|
let brush = brush.make_brush(self, || shape.bounding_box()).into_owned();
|
||||||
match brush {
|
match brush {
|
||||||
PietGpuBrush::Solid(rgba_color) => {
|
PietGpuBrush::Solid(rgba_color) => {
|
||||||
|
@ -151,7 +163,7 @@ impl RenderContext for PietGpuRenderContext {
|
||||||
let path = shape.path_elements(TOLERANCE);
|
let path = shape.path_elements(TOLERANCE);
|
||||||
self.encode_path(path, false);
|
self.encode_path(path, false);
|
||||||
let stroke = FillColor { rgba_color };
|
let stroke = FillColor { rgba_color };
|
||||||
self.elements.push(Element::FillColor(FillMode::Stroke as u16, stroke));
|
self.elements.push(Element::FillColor(stroke));
|
||||||
self.path_count += 1;
|
self.path_count += 1;
|
||||||
}
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
|
@ -174,9 +186,10 @@ impl RenderContext for PietGpuRenderContext {
|
||||||
// Perhaps that should be added to kurbo.
|
// Perhaps that should be added to kurbo.
|
||||||
self.accumulate_bbox(|| shape.bounding_box());
|
self.accumulate_bbox(|| shape.bounding_box());
|
||||||
let path = shape.path_elements(TOLERANCE);
|
let path = shape.path_elements(TOLERANCE);
|
||||||
|
set_fill_mode(self, FillMode::Nonzero);
|
||||||
self.encode_path(path, true);
|
self.encode_path(path, true);
|
||||||
let fill = FillColor { rgba_color };
|
let fill = FillColor { rgba_color };
|
||||||
self.elements.push(Element::FillColor(FillMode::Nonzero as u16, fill));
|
self.elements.push(Element::FillColor(fill));
|
||||||
self.path_count += 1;
|
self.path_count += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -184,6 +197,7 @@ impl RenderContext for PietGpuRenderContext {
|
||||||
fn fill_even_odd(&mut self, _shape: impl Shape, _brush: &impl IntoBrush<Self>) {}
|
fn fill_even_odd(&mut self, _shape: impl Shape, _brush: &impl IntoBrush<Self>) {}
|
||||||
|
|
||||||
fn clip(&mut self, shape: impl Shape) {
|
fn clip(&mut self, shape: impl Shape) {
|
||||||
|
set_fill_mode(self, FillMode::Nonzero);
|
||||||
let path = shape.path_elements(TOLERANCE);
|
let path = shape.path_elements(TOLERANCE);
|
||||||
self.encode_path(path, true);
|
self.encode_path(path, true);
|
||||||
let begin_ix = self.elements.len();
|
let begin_ix = self.elements.len();
|
||||||
|
@ -291,30 +305,18 @@ impl RenderContext for PietGpuRenderContext {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PietGpuRenderContext {
|
impl PietGpuRenderContext {
|
||||||
fn encode_line_seg(&mut self, seg: LineSeg, is_fill: bool) {
|
fn encode_line_seg(&mut self, seg: LineSeg) {
|
||||||
if is_fill {
|
self.elements.push(Element::Line(seg));
|
||||||
self.elements.push(Element::Line(FillMode::Nonzero as u16, seg));
|
|
||||||
} else {
|
|
||||||
self.elements.push(Element::Line(FillMode::Stroke as u16, seg));
|
|
||||||
}
|
|
||||||
self.pathseg_count += 1;
|
self.pathseg_count += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn encode_quad_seg(&mut self, seg: QuadSeg, is_fill: bool) {
|
fn encode_quad_seg(&mut self, seg: QuadSeg) {
|
||||||
if is_fill {
|
self.elements.push(Element::Quad(seg));
|
||||||
self.elements.push(Element::Quad(FillMode::Nonzero as u16, seg));
|
|
||||||
} else {
|
|
||||||
self.elements.push(Element::Quad(FillMode::Stroke as u16, seg));
|
|
||||||
}
|
|
||||||
self.pathseg_count += 1;
|
self.pathseg_count += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn encode_cubic_seg(&mut self, seg: CubicSeg, is_fill: bool) {
|
fn encode_cubic_seg(&mut self, seg: CubicSeg) {
|
||||||
if is_fill {
|
self.elements.push(Element::Cubic(seg));
|
||||||
self.elements.push(Element::Cubic(FillMode::Nonzero as u16, seg));
|
|
||||||
} else {
|
|
||||||
self.elements.push(Element::Cubic(FillMode::Stroke as u16, seg));
|
|
||||||
}
|
|
||||||
self.pathseg_count += 1;
|
self.pathseg_count += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -327,13 +329,13 @@ impl PietGpuRenderContext {
|
||||||
}
|
}
|
||||||
_ => None
|
_ => None
|
||||||
}.into_iter().chain(Some(el))
|
}.into_iter().chain(Some(el))
|
||||||
}).chain(Some(PathEl::ClosePath)), is_fill)
|
}).chain(Some(PathEl::ClosePath)))
|
||||||
} else {
|
} else {
|
||||||
self.encode_path_inner(path, is_fill)
|
self.encode_path_inner(path)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn encode_path_inner(&mut self, path: impl Iterator<Item = PathEl>, is_fill: bool) {
|
fn encode_path_inner(&mut self, path: impl Iterator<Item = PathEl>) {
|
||||||
let flatten = false;
|
let flatten = false;
|
||||||
if flatten {
|
if flatten {
|
||||||
let mut start_pt = None;
|
let mut start_pt = None;
|
||||||
|
@ -351,7 +353,7 @@ impl PietGpuRenderContext {
|
||||||
p0: last_pt.unwrap(),
|
p0: last_pt.unwrap(),
|
||||||
p1: scene_pt,
|
p1: scene_pt,
|
||||||
};
|
};
|
||||||
self.encode_line_seg(seg, is_fill);
|
self.encode_line_seg(seg);
|
||||||
last_pt = Some(scene_pt);
|
last_pt = Some(scene_pt);
|
||||||
}
|
}
|
||||||
PathEl::ClosePath => {
|
PathEl::ClosePath => {
|
||||||
|
@ -361,7 +363,7 @@ impl PietGpuRenderContext {
|
||||||
p0: last,
|
p0: last,
|
||||||
p1: start,
|
p1: start,
|
||||||
};
|
};
|
||||||
self.encode_line_seg(seg, is_fill);
|
self.encode_line_seg(seg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -385,7 +387,7 @@ impl PietGpuRenderContext {
|
||||||
p0: last_pt.unwrap(),
|
p0: last_pt.unwrap(),
|
||||||
p1: scene_pt,
|
p1: scene_pt,
|
||||||
};
|
};
|
||||||
self.encode_line_seg(seg, is_fill);
|
self.encode_line_seg(seg);
|
||||||
last_pt = Some(scene_pt);
|
last_pt = Some(scene_pt);
|
||||||
}
|
}
|
||||||
PathEl::QuadTo(p1, p2) => {
|
PathEl::QuadTo(p1, p2) => {
|
||||||
|
@ -396,7 +398,7 @@ impl PietGpuRenderContext {
|
||||||
p1: scene_p1,
|
p1: scene_p1,
|
||||||
p2: scene_p2,
|
p2: scene_p2,
|
||||||
};
|
};
|
||||||
self.encode_quad_seg(seg, is_fill);
|
self.encode_quad_seg(seg);
|
||||||
last_pt = Some(scene_p2);
|
last_pt = Some(scene_p2);
|
||||||
}
|
}
|
||||||
PathEl::CurveTo(p1, p2, p3) => {
|
PathEl::CurveTo(p1, p2, p3) => {
|
||||||
|
@ -409,7 +411,7 @@ impl PietGpuRenderContext {
|
||||||
p2: scene_p2,
|
p2: scene_p2,
|
||||||
p3: scene_p3,
|
p3: scene_p3,
|
||||||
};
|
};
|
||||||
self.encode_cubic_seg(seg, is_fill);
|
self.encode_cubic_seg(seg);
|
||||||
last_pt = Some(scene_p3);
|
last_pt = Some(scene_p3);
|
||||||
}
|
}
|
||||||
PathEl::ClosePath => {
|
PathEl::ClosePath => {
|
||||||
|
@ -419,7 +421,7 @@ impl PietGpuRenderContext {
|
||||||
p0: last,
|
p0: last,
|
||||||
p1: start,
|
p1: start,
|
||||||
};
|
};
|
||||||
self.encode_line_seg(seg, is_fill);
|
self.encode_line_seg(seg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue