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:
Elias Naur 2021-03-19 13:49:47 +01:00
parent bb61f875dc
commit eb37db1b05
5 changed files with 82 additions and 37 deletions

View file

@ -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),
} }
} }
} }

View file

@ -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.

View file

@ -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));
}

View file

@ -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);
} }
} }
} }