mirror of
https://github.com/italicsjenga/vello.git
synced 2025-01-10 20:51:29 +11:00
ensure consistent path segment transformation
As described in #62, the non-deterministic scene monoid may result in slightly different transformations for path segments in an otherwise closed path. This change ensures consistent transformation across paths in three steps. First, absolute transformations computed by the scene monoid is stored along with path segments and annotated elements. Second, elements.comp no longer transforms path segments. Instead, each segment is stored untransformed along with a reference to its absolute transformation. Finally, path_coarse performs the transformation of path segments. Because all segments in a path share a single transformation reference, the inconsistency in #62 is avoided. Fixes #62 Signed-off-by: Elias Naur <mail@eliasnaur.com>
This commit is contained in:
parent
ad444f615c
commit
07e07c7544
|
@ -9,6 +9,8 @@ piet_gpu! {
|
||||||
p2: [f32; 2],
|
p2: [f32; 2],
|
||||||
p3: [f32; 2],
|
p3: [f32; 2],
|
||||||
path_ix: u32,
|
path_ix: u32,
|
||||||
|
// trans_ix is 1-based, 0 means no transformation.
|
||||||
|
trans_ix: u32,
|
||||||
// A note: the layout of this struct is shared with
|
// A note: the layout of this struct is shared with
|
||||||
// PathStrokeCubic. In that case, we actually write
|
// PathStrokeCubic. In that case, we actually write
|
||||||
// [0.0, 0.0] as the stroke field, to minimize divergence.
|
// [0.0, 0.0] as the stroke field, to minimize divergence.
|
||||||
|
@ -19,6 +21,7 @@ piet_gpu! {
|
||||||
p2: [f32; 2],
|
p2: [f32; 2],
|
||||||
p3: [f32; 2],
|
p3: [f32; 2],
|
||||||
path_ix: u32,
|
path_ix: u32,
|
||||||
|
trans_ix: u32,
|
||||||
// halfwidth in both x and y for binning
|
// halfwidth in both x and y for binning
|
||||||
stroke: [f32; 2],
|
stroke: [f32; 2],
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@ piet_gpu! {
|
||||||
flags: u32,
|
flags: u32,
|
||||||
path_count: u32,
|
path_count: u32,
|
||||||
pathseg_count: u32,
|
pathseg_count: u32,
|
||||||
|
trans_count: u32,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,5 +18,9 @@ piet_gpu! {
|
||||||
y_edge: f32,
|
y_edge: f32,
|
||||||
next: Ref<TileSeg>,
|
next: Ref<TileSeg>,
|
||||||
}
|
}
|
||||||
|
struct TransformSeg {
|
||||||
|
mat: [f32; 4],
|
||||||
|
translate: [f32; 2],
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -248,10 +248,11 @@ fn main() -> Result<(), Error> {
|
||||||
}
|
}
|
||||||
let n_paths = ctx.path_count();
|
let n_paths = ctx.path_count();
|
||||||
let n_pathseg = ctx.pathseg_count();
|
let n_pathseg = ctx.pathseg_count();
|
||||||
|
let n_trans = ctx.trans_count();
|
||||||
let scene = ctx.get_scene_buf();
|
let scene = ctx.get_scene_buf();
|
||||||
//dump_scene(&scene);
|
//dump_scene(&scene);
|
||||||
|
|
||||||
let renderer = Renderer::new(&session, scene, n_paths, n_pathseg)?;
|
let renderer = Renderer::new(&session, scene, n_paths, n_pathseg, n_trans)?;
|
||||||
let image_buf =
|
let image_buf =
|
||||||
session.create_buffer((WIDTH * HEIGHT * 4) as u64, MemFlags::host_coherent())?;
|
session.create_buffer((WIDTH * HEIGHT * 4) as u64, MemFlags::host_coherent())?;
|
||||||
|
|
||||||
|
|
|
@ -40,9 +40,10 @@ fn main() -> Result<(), Error> {
|
||||||
render_scene(&mut ctx);
|
render_scene(&mut ctx);
|
||||||
let n_paths = ctx.path_count();
|
let n_paths = ctx.path_count();
|
||||||
let n_pathseg = ctx.pathseg_count();
|
let n_pathseg = ctx.pathseg_count();
|
||||||
|
let n_trans = ctx.pathseg_count();
|
||||||
let scene = ctx.get_scene_buf();
|
let scene = ctx.get_scene_buf();
|
||||||
|
|
||||||
let renderer = Renderer::new(&session, scene, n_paths, n_pathseg)?;
|
let renderer = Renderer::new(&session, scene, n_paths, n_pathseg, n_trans)?;
|
||||||
|
|
||||||
let mut submitted: Option<hub::SubmittedCmdBuf> = None;
|
let mut submitted: Option<hub::SubmittedCmdBuf> = None;
|
||||||
let mut last_frame_idx = 0;
|
let mut last_frame_idx = 0;
|
||||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -39,6 +39,7 @@ layout(set = 0, binding = 3) volatile buffer StateBuf {
|
||||||
#include "state.h"
|
#include "state.h"
|
||||||
#include "annotated.h"
|
#include "annotated.h"
|
||||||
#include "pathseg.h"
|
#include "pathseg.h"
|
||||||
|
#include "tile.h"
|
||||||
|
|
||||||
#define StateBuf_stride (4 + 2 * State_size)
|
#define StateBuf_stride (4 + 2 * State_size)
|
||||||
|
|
||||||
|
@ -91,6 +92,7 @@ State combine_state(State a, State b) {
|
||||||
c.flags |= (a.flags & FLAG_RESET_BBOX) >> 1;
|
c.flags |= (a.flags & FLAG_RESET_BBOX) >> 1;
|
||||||
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;
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -106,6 +108,7 @@ State map_element(ElementRef ref) {
|
||||||
c.flags = 0;
|
c.flags = 0;
|
||||||
c.path_count = 0;
|
c.path_count = 0;
|
||||||
c.pathseg_count = 0;
|
c.pathseg_count = 0;
|
||||||
|
c.trans_count = 0;
|
||||||
switch (tag) {
|
switch (tag) {
|
||||||
case Element_FillLine:
|
case Element_FillLine:
|
||||||
case Element_StrokeLine:
|
case Element_StrokeLine:
|
||||||
|
@ -146,6 +149,7 @@ State map_element(ElementRef ref) {
|
||||||
Transform t = Element_Transform_read(ref);
|
Transform t = Element_Transform_read(ref);
|
||||||
c.mat = t.mat;
|
c.mat = t.mat;
|
||||||
c.translate = t.translate;
|
c.translate = t.translate;
|
||||||
|
c.trans_count = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return c;
|
return c;
|
||||||
|
@ -205,6 +209,7 @@ void main() {
|
||||||
exclusive.flags = 0;
|
exclusive.flags = 0;
|
||||||
exclusive.path_count = 0;
|
exclusive.path_count = 0;
|
||||||
exclusive.pathseg_count = 0;
|
exclusive.pathseg_count = 0;
|
||||||
|
exclusive.trans_count = 0;
|
||||||
|
|
||||||
// Publish aggregate for this partition
|
// Publish aggregate for this partition
|
||||||
if (gl_LocalInvocationID.x == WG_SIZE - 1) {
|
if (gl_LocalInvocationID.x == WG_SIZE - 1) {
|
||||||
|
@ -290,14 +295,13 @@ void main() {
|
||||||
case Element_FillLine:
|
case Element_FillLine:
|
||||||
case Element_StrokeLine:
|
case Element_StrokeLine:
|
||||||
LineSeg line = Element_StrokeLine_read(this_ref);
|
LineSeg line = Element_StrokeLine_read(this_ref);
|
||||||
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;
|
PathStrokeCubic path_cubic;
|
||||||
path_cubic.p0 = p0;
|
path_cubic.p0 = line.p0;
|
||||||
path_cubic.p1 = mix(p0, p1, 1.0 / 3.0);
|
path_cubic.p1 = mix(line.p0, line.p1, 1.0 / 3.0);
|
||||||
path_cubic.p2 = mix(p1, p0, 1.0 / 3.0);
|
path_cubic.p2 = mix(line.p1, line.p0, 1.0 / 3.0);
|
||||||
path_cubic.p3 = p1;
|
path_cubic.p3 = line.p1;
|
||||||
path_cubic.path_ix = st.path_count;
|
path_cubic.path_ix = st.path_count;
|
||||||
|
path_cubic.trans_ix = st.trans_count;
|
||||||
if (tag == Element_StrokeLine) {
|
if (tag == Element_StrokeLine) {
|
||||||
path_cubic.stroke = get_linewidth(st);
|
path_cubic.stroke = get_linewidth(st);
|
||||||
} else {
|
} else {
|
||||||
|
@ -313,15 +317,12 @@ void main() {
|
||||||
case Element_FillQuad:
|
case Element_FillQuad:
|
||||||
case Element_StrokeQuad:
|
case Element_StrokeQuad:
|
||||||
QuadSeg quad = Element_StrokeQuad_read(this_ref);
|
QuadSeg quad = Element_StrokeQuad_read(this_ref);
|
||||||
p0 = st.mat.xy * quad.p0.x + st.mat.zw * quad.p0.y + st.translate;
|
path_cubic.p0 = quad.p0;
|
||||||
p1 = st.mat.xy * quad.p1.x + st.mat.zw * quad.p1.y + st.translate;
|
path_cubic.p1 = mix(quad.p1, quad.p0, 1.0 / 3.0);
|
||||||
vec2 p2 = st.mat.xy * quad.p2.x + st.mat.zw * quad.p2.y + st.translate;
|
path_cubic.p2 = mix(quad.p1, quad.p2, 1.0 / 3.0);
|
||||||
path_cubic;
|
path_cubic.p3 = quad.p2;
|
||||||
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;
|
path_cubic.path_ix = st.path_count;
|
||||||
|
path_cubic.trans_ix = st.trans_count;
|
||||||
if (tag == Element_StrokeQuad) {
|
if (tag == Element_StrokeQuad) {
|
||||||
path_cubic.stroke = get_linewidth(st);
|
path_cubic.stroke = get_linewidth(st);
|
||||||
} else {
|
} else {
|
||||||
|
@ -337,12 +338,12 @@ void main() {
|
||||||
case Element_FillCubic:
|
case Element_FillCubic:
|
||||||
case Element_StrokeCubic:
|
case Element_StrokeCubic:
|
||||||
CubicSeg cubic = Element_StrokeCubic_read(this_ref);
|
CubicSeg cubic = Element_StrokeCubic_read(this_ref);
|
||||||
path_cubic;
|
path_cubic.p0 = cubic.p0;
|
||||||
path_cubic.p0 = st.mat.xy * cubic.p0.x + st.mat.zw * cubic.p0.y + st.translate;
|
path_cubic.p1 = cubic.p1;
|
||||||
path_cubic.p1 = st.mat.xy * cubic.p1.x + st.mat.zw * cubic.p1.y + st.translate;
|
path_cubic.p2 = cubic.p2;
|
||||||
path_cubic.p2 = st.mat.xy * cubic.p2.x + st.mat.zw * cubic.p2.y + st.translate;
|
path_cubic.p3 = cubic.p3;
|
||||||
path_cubic.p3 = st.mat.xy * cubic.p3.x + st.mat.zw * cubic.p3.y + st.translate;
|
|
||||||
path_cubic.path_ix = st.path_count;
|
path_cubic.path_ix = st.path_count;
|
||||||
|
path_cubic.trans_ix = st.trans_count;
|
||||||
if (tag == Element_StrokeCubic) {
|
if (tag == Element_StrokeCubic) {
|
||||||
path_cubic.stroke = get_linewidth(st);
|
path_cubic.stroke = get_linewidth(st);
|
||||||
} else {
|
} else {
|
||||||
|
@ -388,6 +389,11 @@ void main() {
|
||||||
out_ref = AnnotatedRef(conf.anno_alloc.offset + (st.path_count - 1) * Annotated_size);
|
out_ref = AnnotatedRef(conf.anno_alloc.offset + (st.path_count - 1) * Annotated_size);
|
||||||
Annotated_EndClip_write(conf.anno_alloc, out_ref, anno_end_clip);
|
Annotated_EndClip_write(conf.anno_alloc, out_ref, anno_end_clip);
|
||||||
break;
|
break;
|
||||||
|
case Element_Transform:
|
||||||
|
TransformSeg transform = TransformSeg(st.mat, st.translate);
|
||||||
|
TransformSegRef trans_ref = TransformSegRef(conf.trans_alloc.offset + (st.trans_count - 1) * TransformSeg_size);
|
||||||
|
TransformSeg_write(conf.trans_alloc, trans_ref, transform);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Binary file not shown.
Binary file not shown.
|
@ -102,6 +102,17 @@ void main() {
|
||||||
case PathSeg_FillCubic:
|
case PathSeg_FillCubic:
|
||||||
case PathSeg_StrokeCubic:
|
case PathSeg_StrokeCubic:
|
||||||
PathStrokeCubic cubic = PathSeg_StrokeCubic_read(conf.pathseg_alloc, ref);
|
PathStrokeCubic cubic = PathSeg_StrokeCubic_read(conf.pathseg_alloc, ref);
|
||||||
|
|
||||||
|
uint trans_ix = cubic.trans_ix;
|
||||||
|
if (trans_ix > 0) {
|
||||||
|
TransformSegRef trans_ref = TransformSegRef(conf.trans_alloc.offset + (trans_ix - 1) * TransformSeg_size);
|
||||||
|
TransformSeg trans = TransformSeg_read(conf.trans_alloc, trans_ref);
|
||||||
|
cubic.p0 = trans.mat.xy * cubic.p0.x + trans.mat.zw * cubic.p0.y + trans.translate;
|
||||||
|
cubic.p1 = trans.mat.xy * cubic.p1.x + trans.mat.zw * cubic.p1.y + trans.translate;
|
||||||
|
cubic.p2 = trans.mat.xy * cubic.p2.x + trans.mat.zw * cubic.p2.y + trans.translate;
|
||||||
|
cubic.p3 = trans.mat.xy * cubic.p3.x + trans.mat.zw * cubic.p3.y + trans.translate;
|
||||||
|
}
|
||||||
|
|
||||||
vec2 err_v = 3.0 * (cubic.p2 - cubic.p1) + cubic.p0 - cubic.p3;
|
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;
|
float err = err_v.x * err_v.x + err_v.y * err_v.y;
|
||||||
// The number of quadratics.
|
// The number of quadratics.
|
||||||
|
|
Binary file not shown.
|
@ -20,9 +20,10 @@ struct PathFillCubic {
|
||||||
vec2 p2;
|
vec2 p2;
|
||||||
vec2 p3;
|
vec2 p3;
|
||||||
uint path_ix;
|
uint path_ix;
|
||||||
|
uint trans_ix;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define PathFillCubic_size 36
|
#define PathFillCubic_size 40
|
||||||
|
|
||||||
PathFillCubicRef PathFillCubic_index(PathFillCubicRef ref, uint index) {
|
PathFillCubicRef PathFillCubic_index(PathFillCubicRef ref, uint index) {
|
||||||
return PathFillCubicRef(ref.offset + index * PathFillCubic_size);
|
return PathFillCubicRef(ref.offset + index * PathFillCubic_size);
|
||||||
|
@ -34,10 +35,11 @@ struct PathStrokeCubic {
|
||||||
vec2 p2;
|
vec2 p2;
|
||||||
vec2 p3;
|
vec2 p3;
|
||||||
uint path_ix;
|
uint path_ix;
|
||||||
|
uint trans_ix;
|
||||||
vec2 stroke;
|
vec2 stroke;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define PathStrokeCubic_size 44
|
#define PathStrokeCubic_size 48
|
||||||
|
|
||||||
PathStrokeCubicRef PathStrokeCubic_index(PathStrokeCubicRef ref, uint index) {
|
PathStrokeCubicRef PathStrokeCubic_index(PathStrokeCubicRef ref, uint index) {
|
||||||
return PathStrokeCubicRef(ref.offset + index * PathStrokeCubic_size);
|
return PathStrokeCubicRef(ref.offset + index * PathStrokeCubic_size);
|
||||||
|
@ -46,7 +48,7 @@ PathStrokeCubicRef PathStrokeCubic_index(PathStrokeCubicRef ref, uint index) {
|
||||||
#define PathSeg_Nop 0
|
#define PathSeg_Nop 0
|
||||||
#define PathSeg_FillCubic 1
|
#define PathSeg_FillCubic 1
|
||||||
#define PathSeg_StrokeCubic 2
|
#define PathSeg_StrokeCubic 2
|
||||||
#define PathSeg_size 48
|
#define PathSeg_size 52
|
||||||
|
|
||||||
PathSegRef PathSeg_index(PathSegRef ref, uint index) {
|
PathSegRef PathSeg_index(PathSegRef ref, uint index) {
|
||||||
return PathSegRef(ref.offset + index * PathSeg_size);
|
return PathSegRef(ref.offset + index * PathSeg_size);
|
||||||
|
@ -63,12 +65,14 @@ PathFillCubic PathFillCubic_read(Alloc a, PathFillCubicRef ref) {
|
||||||
uint raw6 = read_mem(a, ix + 6);
|
uint raw6 = read_mem(a, ix + 6);
|
||||||
uint raw7 = read_mem(a, ix + 7);
|
uint raw7 = read_mem(a, ix + 7);
|
||||||
uint raw8 = read_mem(a, ix + 8);
|
uint raw8 = read_mem(a, ix + 8);
|
||||||
|
uint raw9 = read_mem(a, ix + 9);
|
||||||
PathFillCubic s;
|
PathFillCubic s;
|
||||||
s.p0 = vec2(uintBitsToFloat(raw0), uintBitsToFloat(raw1));
|
s.p0 = vec2(uintBitsToFloat(raw0), uintBitsToFloat(raw1));
|
||||||
s.p1 = vec2(uintBitsToFloat(raw2), uintBitsToFloat(raw3));
|
s.p1 = vec2(uintBitsToFloat(raw2), uintBitsToFloat(raw3));
|
||||||
s.p2 = vec2(uintBitsToFloat(raw4), uintBitsToFloat(raw5));
|
s.p2 = vec2(uintBitsToFloat(raw4), uintBitsToFloat(raw5));
|
||||||
s.p3 = vec2(uintBitsToFloat(raw6), uintBitsToFloat(raw7));
|
s.p3 = vec2(uintBitsToFloat(raw6), uintBitsToFloat(raw7));
|
||||||
s.path_ix = raw8;
|
s.path_ix = raw8;
|
||||||
|
s.trans_ix = raw9;
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -83,6 +87,7 @@ void PathFillCubic_write(Alloc a, PathFillCubicRef ref, PathFillCubic s) {
|
||||||
write_mem(a, ix + 6, floatBitsToUint(s.p3.x));
|
write_mem(a, ix + 6, floatBitsToUint(s.p3.x));
|
||||||
write_mem(a, ix + 7, floatBitsToUint(s.p3.y));
|
write_mem(a, ix + 7, floatBitsToUint(s.p3.y));
|
||||||
write_mem(a, ix + 8, s.path_ix);
|
write_mem(a, ix + 8, s.path_ix);
|
||||||
|
write_mem(a, ix + 9, s.trans_ix);
|
||||||
}
|
}
|
||||||
|
|
||||||
PathStrokeCubic PathStrokeCubic_read(Alloc a, PathStrokeCubicRef ref) {
|
PathStrokeCubic PathStrokeCubic_read(Alloc a, PathStrokeCubicRef ref) {
|
||||||
|
@ -98,13 +103,15 @@ PathStrokeCubic PathStrokeCubic_read(Alloc a, PathStrokeCubicRef ref) {
|
||||||
uint raw8 = read_mem(a, ix + 8);
|
uint raw8 = read_mem(a, ix + 8);
|
||||||
uint raw9 = read_mem(a, ix + 9);
|
uint raw9 = read_mem(a, ix + 9);
|
||||||
uint raw10 = read_mem(a, ix + 10);
|
uint raw10 = read_mem(a, ix + 10);
|
||||||
|
uint raw11 = read_mem(a, ix + 11);
|
||||||
PathStrokeCubic s;
|
PathStrokeCubic s;
|
||||||
s.p0 = vec2(uintBitsToFloat(raw0), uintBitsToFloat(raw1));
|
s.p0 = vec2(uintBitsToFloat(raw0), uintBitsToFloat(raw1));
|
||||||
s.p1 = vec2(uintBitsToFloat(raw2), uintBitsToFloat(raw3));
|
s.p1 = vec2(uintBitsToFloat(raw2), uintBitsToFloat(raw3));
|
||||||
s.p2 = vec2(uintBitsToFloat(raw4), uintBitsToFloat(raw5));
|
s.p2 = vec2(uintBitsToFloat(raw4), uintBitsToFloat(raw5));
|
||||||
s.p3 = vec2(uintBitsToFloat(raw6), uintBitsToFloat(raw7));
|
s.p3 = vec2(uintBitsToFloat(raw6), uintBitsToFloat(raw7));
|
||||||
s.path_ix = raw8;
|
s.path_ix = raw8;
|
||||||
s.stroke = vec2(uintBitsToFloat(raw9), uintBitsToFloat(raw10));
|
s.trans_ix = raw9;
|
||||||
|
s.stroke = vec2(uintBitsToFloat(raw10), uintBitsToFloat(raw11));
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -119,8 +126,9 @@ void PathStrokeCubic_write(Alloc a, PathStrokeCubicRef ref, PathStrokeCubic s) {
|
||||||
write_mem(a, ix + 6, floatBitsToUint(s.p3.x));
|
write_mem(a, ix + 6, floatBitsToUint(s.p3.x));
|
||||||
write_mem(a, ix + 7, floatBitsToUint(s.p3.y));
|
write_mem(a, ix + 7, floatBitsToUint(s.p3.y));
|
||||||
write_mem(a, ix + 8, s.path_ix);
|
write_mem(a, ix + 8, s.path_ix);
|
||||||
write_mem(a, ix + 9, floatBitsToUint(s.stroke.x));
|
write_mem(a, ix + 9, s.trans_ix);
|
||||||
write_mem(a, ix + 10, floatBitsToUint(s.stroke.y));
|
write_mem(a, ix + 10, floatBitsToUint(s.stroke.x));
|
||||||
|
write_mem(a, ix + 11, floatBitsToUint(s.stroke.y));
|
||||||
}
|
}
|
||||||
|
|
||||||
uint PathSeg_tag(Alloc a, PathSegRef ref) {
|
uint PathSeg_tag(Alloc a, PathSegRef ref) {
|
||||||
|
|
|
@ -35,4 +35,5 @@ struct Config {
|
||||||
Alloc ptcl_alloc;
|
Alloc ptcl_alloc;
|
||||||
Alloc pathseg_alloc;
|
Alloc pathseg_alloc;
|
||||||
Alloc anno_alloc;
|
Alloc anno_alloc;
|
||||||
|
Alloc trans_alloc;
|
||||||
};
|
};
|
||||||
|
|
|
@ -14,9 +14,10 @@ struct State {
|
||||||
uint flags;
|
uint flags;
|
||||||
uint path_count;
|
uint path_count;
|
||||||
uint pathseg_count;
|
uint pathseg_count;
|
||||||
|
uint trans_count;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define State_size 56
|
#define State_size 60
|
||||||
|
|
||||||
StateRef State_index(StateRef ref, uint index) {
|
StateRef State_index(StateRef ref, uint index) {
|
||||||
return StateRef(ref.offset + index * State_size);
|
return StateRef(ref.offset + index * State_size);
|
||||||
|
@ -38,6 +39,7 @@ State State_read(StateRef ref) {
|
||||||
uint raw11 = state[ix + 11];
|
uint raw11 = state[ix + 11];
|
||||||
uint raw12 = state[ix + 12];
|
uint raw12 = state[ix + 12];
|
||||||
uint raw13 = state[ix + 13];
|
uint raw13 = state[ix + 13];
|
||||||
|
uint raw14 = state[ix + 14];
|
||||||
State s;
|
State s;
|
||||||
s.mat = vec4(uintBitsToFloat(raw0), uintBitsToFloat(raw1), uintBitsToFloat(raw2), uintBitsToFloat(raw3));
|
s.mat = vec4(uintBitsToFloat(raw0), uintBitsToFloat(raw1), uintBitsToFloat(raw2), uintBitsToFloat(raw3));
|
||||||
s.translate = vec2(uintBitsToFloat(raw4), uintBitsToFloat(raw5));
|
s.translate = vec2(uintBitsToFloat(raw4), uintBitsToFloat(raw5));
|
||||||
|
@ -46,6 +48,7 @@ State State_read(StateRef ref) {
|
||||||
s.flags = raw11;
|
s.flags = raw11;
|
||||||
s.path_count = raw12;
|
s.path_count = raw12;
|
||||||
s.pathseg_count = raw13;
|
s.pathseg_count = raw13;
|
||||||
|
s.trans_count = raw14;
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -65,5 +68,6 @@ void State_write(StateRef ref, State s) {
|
||||||
state[ix + 11] = s.flags;
|
state[ix + 11] = s.flags;
|
||||||
state[ix + 12] = s.path_count;
|
state[ix + 12] = s.path_count;
|
||||||
state[ix + 13] = s.pathseg_count;
|
state[ix + 13] = s.pathseg_count;
|
||||||
|
state[ix + 14] = s.trans_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,10 @@ struct TileSegRef {
|
||||||
uint offset;
|
uint offset;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct TransformSegRef {
|
||||||
|
uint offset;
|
||||||
|
};
|
||||||
|
|
||||||
struct Path {
|
struct Path {
|
||||||
uvec4 bbox;
|
uvec4 bbox;
|
||||||
TileRef tiles;
|
TileRef tiles;
|
||||||
|
@ -49,6 +53,17 @@ TileSegRef TileSeg_index(TileSegRef ref, uint index) {
|
||||||
return TileSegRef(ref.offset + index * TileSeg_size);
|
return TileSegRef(ref.offset + index * TileSeg_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct TransformSeg {
|
||||||
|
vec4 mat;
|
||||||
|
vec2 translate;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define TransformSeg_size 24
|
||||||
|
|
||||||
|
TransformSegRef TransformSeg_index(TransformSegRef ref, uint index) {
|
||||||
|
return TransformSegRef(ref.offset + index * TransformSeg_size);
|
||||||
|
}
|
||||||
|
|
||||||
Path Path_read(Alloc a, PathRef ref) {
|
Path Path_read(Alloc a, PathRef ref) {
|
||||||
uint ix = ref.offset >> 2;
|
uint ix = ref.offset >> 2;
|
||||||
uint raw0 = read_mem(a, ix + 0);
|
uint raw0 = read_mem(a, ix + 0);
|
||||||
|
@ -109,3 +124,27 @@ void TileSeg_write(Alloc a, TileSegRef ref, TileSeg s) {
|
||||||
write_mem(a, ix + 5, s.next.offset);
|
write_mem(a, ix + 5, s.next.offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TransformSeg TransformSeg_read(Alloc a, TransformSegRef ref) {
|
||||||
|
uint ix = ref.offset >> 2;
|
||||||
|
uint raw0 = read_mem(a, ix + 0);
|
||||||
|
uint raw1 = read_mem(a, ix + 1);
|
||||||
|
uint raw2 = read_mem(a, ix + 2);
|
||||||
|
uint raw3 = read_mem(a, ix + 3);
|
||||||
|
uint raw4 = read_mem(a, ix + 4);
|
||||||
|
uint raw5 = read_mem(a, ix + 5);
|
||||||
|
TransformSeg s;
|
||||||
|
s.mat = vec4(uintBitsToFloat(raw0), uintBitsToFloat(raw1), uintBitsToFloat(raw2), uintBitsToFloat(raw3));
|
||||||
|
s.translate = vec2(uintBitsToFloat(raw4), uintBitsToFloat(raw5));
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TransformSeg_write(Alloc a, TransformSegRef ref, TransformSeg s) {
|
||||||
|
uint ix = ref.offset >> 2;
|
||||||
|
write_mem(a, ix + 0, floatBitsToUint(s.mat.x));
|
||||||
|
write_mem(a, ix + 1, floatBitsToUint(s.mat.y));
|
||||||
|
write_mem(a, ix + 2, floatBitsToUint(s.mat.z));
|
||||||
|
write_mem(a, ix + 3, floatBitsToUint(s.mat.w));
|
||||||
|
write_mem(a, ix + 4, floatBitsToUint(s.translate.x));
|
||||||
|
write_mem(a, ix + 5, floatBitsToUint(s.translate.y));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
Binary file not shown.
|
@ -201,14 +201,15 @@ impl Renderer {
|
||||||
scene: &[u8],
|
scene: &[u8],
|
||||||
n_paths: usize,
|
n_paths: usize,
|
||||||
n_pathseg: usize,
|
n_pathseg: usize,
|
||||||
|
n_trans: usize,
|
||||||
) -> Result<Self, Error> {
|
) -> Result<Self, Error> {
|
||||||
let host = MemFlags::host_coherent();
|
let host = MemFlags::host_coherent();
|
||||||
let dev = MemFlags::device_local();
|
let dev = MemFlags::device_local();
|
||||||
|
|
||||||
let n_elements = scene.len() / piet_gpu_types::scene::Element::fixed_size();
|
let n_elements = scene.len() / piet_gpu_types::scene::Element::fixed_size();
|
||||||
println!(
|
println!(
|
||||||
"scene: {} elements, {} paths, {} path_segments",
|
"scene: {} elements, {} paths, {} path_segments, {} transforms",
|
||||||
n_elements, n_paths, n_pathseg
|
n_elements, n_paths, n_pathseg, n_trans
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut scene_buf_host = session
|
let mut scene_buf_host = session
|
||||||
|
@ -222,15 +223,16 @@ impl Renderer {
|
||||||
let state_buf = session.create_buffer(1 * 1024 * 1024, dev)?;
|
let state_buf = session.create_buffer(1 * 1024 * 1024, dev)?;
|
||||||
let image_dev = session.create_image2d(WIDTH as u32, HEIGHT as u32, dev)?;
|
let image_dev = session.create_image2d(WIDTH as u32, HEIGHT as u32, dev)?;
|
||||||
|
|
||||||
const CONFIG_SIZE: u64 = 9*4; // Size of Config in setup.h.
|
const CONFIG_SIZE: u64 = 10*4; // Size of Config in setup.h.
|
||||||
let mut config_buf_host = session.create_buffer(CONFIG_SIZE, host)?;
|
let mut config_buf_host = session.create_buffer(CONFIG_SIZE, host)?;
|
||||||
let config_buf_dev = session.create_buffer(CONFIG_SIZE, dev)?;
|
let config_buf_dev = session.create_buffer(CONFIG_SIZE, dev)?;
|
||||||
|
|
||||||
// TODO: constants
|
// TODO: constants
|
||||||
const PATH_SIZE: usize = 12;
|
const PATH_SIZE: usize = 12;
|
||||||
const BIN_SIZE: usize = 8;
|
const BIN_SIZE: usize = 8;
|
||||||
const PATHSEG_SIZE: usize = 48;
|
const PATHSEG_SIZE: usize = 52;
|
||||||
const ANNO_SIZE: usize = 28;
|
const ANNO_SIZE: usize = 28;
|
||||||
|
const TRANS_SIZE: usize = 24;
|
||||||
let mut alloc = 0;
|
let mut alloc = 0;
|
||||||
let tile_base = alloc;
|
let tile_base = alloc;
|
||||||
alloc += ((n_paths + 3) & !3) * PATH_SIZE;
|
alloc += ((n_paths + 3) & !3) * PATH_SIZE;
|
||||||
|
@ -242,7 +244,9 @@ impl Renderer {
|
||||||
alloc += (n_pathseg * PATHSEG_SIZE + 3) & !3;
|
alloc += (n_pathseg * PATHSEG_SIZE + 3) & !3;
|
||||||
let anno_base = alloc;
|
let anno_base = alloc;
|
||||||
alloc += (n_paths * ANNO_SIZE + 3) & !3;
|
alloc += (n_paths * ANNO_SIZE + 3) & !3;
|
||||||
config_buf_host.write(&[n_paths as u32, n_pathseg as u32, WIDTH_IN_TILES as u32, HEIGHT_IN_TILES as u32, tile_base as u32, bin_base as u32, ptcl_base as u32, pathseg_base as u32, anno_base as u32])?;
|
let trans_base = alloc;
|
||||||
|
alloc += (n_trans * TRANS_SIZE + 3) & !3;
|
||||||
|
config_buf_host.write(&[n_paths as u32, n_pathseg as u32, WIDTH_IN_TILES as u32, HEIGHT_IN_TILES as u32, tile_base as u32, bin_base as u32, ptcl_base as u32, pathseg_base as u32, anno_base as u32, trans_base as u32])?;
|
||||||
|
|
||||||
let mut memory_buf_host = session.create_buffer(2*4, host)?;
|
let mut memory_buf_host = session.create_buffer(2*4, host)?;
|
||||||
let memory_buf_dev = session.create_buffer(128 * 1024 * 1024, dev)?;
|
let memory_buf_dev = session.create_buffer(128 * 1024 * 1024, dev)?;
|
||||||
|
|
|
@ -38,6 +38,8 @@ pub struct PietGpuRenderContext {
|
||||||
path_count: usize,
|
path_count: usize,
|
||||||
/// The count of path segment elements.
|
/// The count of path segment elements.
|
||||||
pathseg_count: usize,
|
pathseg_count: usize,
|
||||||
|
/// The count of transform elements.
|
||||||
|
trans_count: usize,
|
||||||
|
|
||||||
cur_transform: Affine,
|
cur_transform: Affine,
|
||||||
state_stack: Vec<State>,
|
state_stack: Vec<State>,
|
||||||
|
@ -82,6 +84,7 @@ impl PietGpuRenderContext {
|
||||||
stroke_width,
|
stroke_width,
|
||||||
path_count: 0,
|
path_count: 0,
|
||||||
pathseg_count: 0,
|
pathseg_count: 0,
|
||||||
|
trans_count: 0,
|
||||||
cur_transform: Affine::default(),
|
cur_transform: Affine::default(),
|
||||||
state_stack: Vec::new(),
|
state_stack: Vec::new(),
|
||||||
clip_stack: Vec::new(),
|
clip_stack: Vec::new(),
|
||||||
|
@ -100,6 +103,10 @@ impl PietGpuRenderContext {
|
||||||
pub fn pathseg_count(&self) -> usize {
|
pub fn pathseg_count(&self) -> usize {
|
||||||
self.pathseg_count
|
self.pathseg_count
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn trans_count(&self) -> usize {
|
||||||
|
self.trans_count
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RenderContext for PietGpuRenderContext {
|
impl RenderContext for PietGpuRenderContext {
|
||||||
|
@ -207,6 +214,7 @@ impl RenderContext for PietGpuRenderContext {
|
||||||
let a_inv = state.rel_transform.inverse();
|
let a_inv = state.rel_transform.inverse();
|
||||||
self.elements
|
self.elements
|
||||||
.push(Element::Transform(to_scene_transform(a_inv)));
|
.push(Element::Transform(to_scene_transform(a_inv)));
|
||||||
|
self.trans_count += 1;
|
||||||
}
|
}
|
||||||
self.cur_transform = state.transform;
|
self.cur_transform = state.transform;
|
||||||
for _ in 0..state.n_clip {
|
for _ in 0..state.n_clip {
|
||||||
|
@ -228,6 +236,7 @@ impl RenderContext for PietGpuRenderContext {
|
||||||
fn transform(&mut self, transform: Affine) {
|
fn transform(&mut self, transform: Affine) {
|
||||||
self.elements
|
self.elements
|
||||||
.push(Element::Transform(to_scene_transform(transform)));
|
.push(Element::Transform(to_scene_transform(transform)));
|
||||||
|
self.trans_count += 1;
|
||||||
if let Some(tos) = self.state_stack.last_mut() {
|
if let Some(tos) = self.state_stack.last_mut() {
|
||||||
tos.rel_transform *= transform;
|
tos.rel_transform *= transform;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue