Run `rustfmt` on the renderer crate
This commit is contained in:
parent
8606cd013e
commit
db8eb1c97c
|
@ -37,10 +37,11 @@ pub struct SceneBuilder<'a> {
|
|||
}
|
||||
|
||||
impl<'a> SceneBuilder<'a> {
|
||||
pub fn new(scene: &'a Scene,
|
||||
pub fn new(
|
||||
scene: &'a Scene,
|
||||
built_options: &'a PreparedRenderOptions,
|
||||
listener: Box<dyn RenderCommandListener>)
|
||||
-> SceneBuilder<'a> {
|
||||
listener: Box<dyn RenderCommandListener>,
|
||||
) -> SceneBuilder<'a> {
|
||||
let effective_view_box = scene.effective_view_box(built_options);
|
||||
SceneBuilder {
|
||||
scene,
|
||||
|
@ -55,12 +56,17 @@ impl<'a> SceneBuilder<'a> {
|
|||
pub fn build_sequentially(&mut self) {
|
||||
let effective_view_box = self.scene.effective_view_box(self.built_options);
|
||||
let object_count = self.scene.objects.len();
|
||||
let alpha_tiles: Vec<_> = (0..object_count).into_iter().flat_map(|object_index| {
|
||||
self.build_object(object_index,
|
||||
let alpha_tiles: Vec<_> = (0..object_count)
|
||||
.into_iter()
|
||||
.flat_map(|object_index| {
|
||||
self.build_object(
|
||||
object_index,
|
||||
effective_view_box,
|
||||
&self.built_options,
|
||||
&self.scene)
|
||||
}).collect();
|
||||
&self.scene,
|
||||
)
|
||||
})
|
||||
.collect();
|
||||
|
||||
self.finish_building(alpha_tiles)
|
||||
}
|
||||
|
@ -68,36 +74,46 @@ impl<'a> SceneBuilder<'a> {
|
|||
pub fn build_in_parallel(&mut self) {
|
||||
let effective_view_box = self.scene.effective_view_box(self.built_options);
|
||||
let object_count = self.scene.objects.len();
|
||||
let alpha_tiles: Vec<_> = (0..object_count).into_par_iter().flat_map(|object_index| {
|
||||
self.build_object(object_index,
|
||||
let alpha_tiles: Vec<_> = (0..object_count)
|
||||
.into_par_iter()
|
||||
.flat_map(|object_index| {
|
||||
self.build_object(
|
||||
object_index,
|
||||
effective_view_box,
|
||||
&self.built_options,
|
||||
&self.scene)
|
||||
}).collect();
|
||||
&self.scene,
|
||||
)
|
||||
})
|
||||
.collect();
|
||||
|
||||
self.finish_building(alpha_tiles)
|
||||
}
|
||||
|
||||
fn build_object(&self,
|
||||
fn build_object(
|
||||
&self,
|
||||
object_index: usize,
|
||||
view_box: RectF32,
|
||||
built_options: &PreparedRenderOptions,
|
||||
scene: &Scene)
|
||||
-> Vec<AlphaTileBatchPrimitive> {
|
||||
scene: &Scene,
|
||||
) -> Vec<AlphaTileBatchPrimitive> {
|
||||
let object = &scene.objects[object_index];
|
||||
let outline = scene.apply_render_options(object.outline(), built_options);
|
||||
|
||||
let mut tiler = Tiler::new(self, &outline, view_box, object_index as u16);
|
||||
tiler.generate_tiles();
|
||||
|
||||
self.listener.send(RenderCommand::AddFills(tiler.built_object.fills));
|
||||
self.listener
|
||||
.send(RenderCommand::AddFills(tiler.built_object.fills));
|
||||
tiler.built_object.alpha_tiles
|
||||
}
|
||||
|
||||
fn cull_alpha_tiles(&self, alpha_tiles: &mut Vec<AlphaTileBatchPrimitive>) {
|
||||
for alpha_tile in alpha_tiles {
|
||||
let alpha_tile_coords = alpha_tile.tile_coords();
|
||||
if self.z_buffer.test(alpha_tile_coords, alpha_tile.object_index as u32) {
|
||||
if self
|
||||
.z_buffer
|
||||
.test(alpha_tile_coords, alpha_tile.object_index as u32)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -197,10 +213,20 @@ impl RenderTransform {
|
|||
}
|
||||
|
||||
let inverse_transform = perspective.transform.inverse();
|
||||
let clip_polygon = points.into_iter().map(|point| {
|
||||
inverse_transform.transform_point(point).perspective_divide().to_2d()
|
||||
}).collect();
|
||||
return PreparedRenderTransform::Perspective { perspective, clip_polygon, quad };
|
||||
let clip_polygon = points
|
||||
.into_iter()
|
||||
.map(|point| {
|
||||
inverse_transform
|
||||
.transform_point(point)
|
||||
.perspective_divide()
|
||||
.to_2d()
|
||||
})
|
||||
.collect();
|
||||
return PreparedRenderTransform::Perspective {
|
||||
perspective,
|
||||
clip_polygon,
|
||||
quad,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -223,7 +249,11 @@ impl PreparedRenderOptions {
|
|||
pub enum PreparedRenderTransform {
|
||||
None,
|
||||
Transform2D(Transform2DF32),
|
||||
Perspective { perspective: Perspective, clip_polygon: Vec<Point2DF32>, quad: [Point3DF32; 4] }
|
||||
Perspective {
|
||||
perspective: Perspective,
|
||||
clip_polygon: Vec<Point2DF32>,
|
||||
quad: [Point3DF32; 4],
|
||||
},
|
||||
}
|
||||
|
||||
impl PreparedRenderTransform {
|
||||
|
@ -236,9 +266,14 @@ impl PreparedRenderTransform {
|
|||
}
|
||||
}
|
||||
|
||||
impl<F> RenderCommandListener for F where F: Fn(RenderCommand) + Send + Sync {
|
||||
impl<F> RenderCommandListener for F
|
||||
where
|
||||
F: Fn(RenderCommand) + Send + Sync,
|
||||
{
|
||||
#[inline]
|
||||
fn send(&self, command: RenderCommand) { (*self)(command) }
|
||||
fn send(&self, command: RenderCommand) {
|
||||
(*self)(command)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Default)]
|
||||
|
|
|
@ -18,8 +18,8 @@
|
|||
use crate::gpu::renderer::RenderStats;
|
||||
use pathfinder_geometry::basic::point::Point2DI32;
|
||||
use pathfinder_geometry::basic::rect::RectI32;
|
||||
use pathfinder_gpu::Device;
|
||||
use pathfinder_gpu::resources::ResourceLoader;
|
||||
use pathfinder_gpu::Device;
|
||||
use pathfinder_ui::{FONT_ASCENT, LINE_HEIGHT, PADDING, UI, WINDOW_COLOR};
|
||||
use std::collections::VecDeque;
|
||||
use std::ops::{Add, Div};
|
||||
|
@ -30,27 +30,47 @@ const SAMPLE_BUFFER_SIZE: usize = 60;
|
|||
const PERF_WINDOW_WIDTH: i32 = 375;
|
||||
const PERF_WINDOW_HEIGHT: i32 = LINE_HEIGHT * 6 + PADDING + 2;
|
||||
|
||||
pub struct DebugUI<D> where D: Device {
|
||||
pub struct DebugUI<D>
|
||||
where
|
||||
D: Device,
|
||||
{
|
||||
pub ui: UI<D>,
|
||||
|
||||
cpu_samples: SampleBuffer<CPUSample>,
|
||||
gpu_samples: SampleBuffer<GPUSample>,
|
||||
}
|
||||
|
||||
impl<D> DebugUI<D> where D: Device {
|
||||
pub fn new(device: &D, resources: &dyn ResourceLoader, framebuffer_size: Point2DI32)
|
||||
-> DebugUI<D> {
|
||||
impl<D> DebugUI<D>
|
||||
where
|
||||
D: Device,
|
||||
{
|
||||
pub fn new(
|
||||
device: &D,
|
||||
resources: &dyn ResourceLoader,
|
||||
framebuffer_size: Point2DI32,
|
||||
) -> DebugUI<D> {
|
||||
let ui = UI::new(device, resources, framebuffer_size);
|
||||
DebugUI { ui, cpu_samples: SampleBuffer::new(), gpu_samples: SampleBuffer::new() }
|
||||
DebugUI {
|
||||
ui,
|
||||
cpu_samples: SampleBuffer::new(),
|
||||
gpu_samples: SampleBuffer::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_sample(&mut self,
|
||||
pub fn add_sample(
|
||||
&mut self,
|
||||
stats: RenderStats,
|
||||
tile_time: Duration,
|
||||
rendering_time: Option<Duration>) {
|
||||
self.cpu_samples.push(CPUSample { stats, elapsed: tile_time });
|
||||
rendering_time: Option<Duration>,
|
||||
) {
|
||||
self.cpu_samples.push(CPUSample {
|
||||
stats,
|
||||
elapsed: tile_time,
|
||||
});
|
||||
if let Some(rendering_time) = rendering_time {
|
||||
self.gpu_samples.push(GPUSample { elapsed: rendering_time });
|
||||
self.gpu_samples.push(GPUSample {
|
||||
elapsed: rendering_time,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -59,50 +79,80 @@ impl<D> DebugUI<D> where D: Device {
|
|||
let framebuffer_size = self.ui.framebuffer_size();
|
||||
let bottom = framebuffer_size.y() - PADDING;
|
||||
let window_rect = RectI32::new(
|
||||
Point2DI32::new(framebuffer_size.x() - PADDING - PERF_WINDOW_WIDTH,
|
||||
bottom - PERF_WINDOW_HEIGHT),
|
||||
Point2DI32::new(PERF_WINDOW_WIDTH, PERF_WINDOW_HEIGHT));
|
||||
self.ui.draw_solid_rounded_rect(device, window_rect, WINDOW_COLOR);
|
||||
Point2DI32::new(
|
||||
framebuffer_size.x() - PADDING - PERF_WINDOW_WIDTH,
|
||||
bottom - PERF_WINDOW_HEIGHT,
|
||||
),
|
||||
Point2DI32::new(PERF_WINDOW_WIDTH, PERF_WINDOW_HEIGHT),
|
||||
);
|
||||
self.ui
|
||||
.draw_solid_rounded_rect(device, window_rect, WINDOW_COLOR);
|
||||
let origin = window_rect.origin() + Point2DI32::new(PADDING, PADDING + FONT_ASCENT);
|
||||
|
||||
let mean_cpu_sample = self.cpu_samples.mean();
|
||||
self.ui.draw_text(device,
|
||||
self.ui.draw_text(
|
||||
device,
|
||||
&format!("Objects: {}", mean_cpu_sample.stats.object_count),
|
||||
origin,
|
||||
false);
|
||||
self.ui.draw_text(device,
|
||||
false,
|
||||
);
|
||||
self.ui.draw_text(
|
||||
device,
|
||||
&format!("Solid Tiles: {}", mean_cpu_sample.stats.solid_tile_count),
|
||||
origin + Point2DI32::new(0, LINE_HEIGHT * 1),
|
||||
false);
|
||||
self.ui.draw_text(device,
|
||||
false,
|
||||
);
|
||||
self.ui.draw_text(
|
||||
device,
|
||||
&format!("Alpha Tiles: {}", mean_cpu_sample.stats.alpha_tile_count),
|
||||
origin + Point2DI32::new(0, LINE_HEIGHT * 2),
|
||||
false);
|
||||
self.ui.draw_text(device,
|
||||
false,
|
||||
);
|
||||
self.ui.draw_text(
|
||||
device,
|
||||
&format!("Fills: {}", mean_cpu_sample.stats.fill_count),
|
||||
origin + Point2DI32::new(0, LINE_HEIGHT * 3),
|
||||
false);
|
||||
false,
|
||||
);
|
||||
|
||||
self.ui.draw_text(device,
|
||||
&format!("CPU Time: {:.3} ms", duration_to_ms(mean_cpu_sample.elapsed)),
|
||||
self.ui.draw_text(
|
||||
device,
|
||||
&format!(
|
||||
"CPU Time: {:.3} ms",
|
||||
duration_to_ms(mean_cpu_sample.elapsed)
|
||||
),
|
||||
origin + Point2DI32::new(0, LINE_HEIGHT * 4),
|
||||
false);
|
||||
false,
|
||||
);
|
||||
|
||||
let mean_gpu_sample = self.gpu_samples.mean();
|
||||
self.ui.draw_text(device,
|
||||
&format!("GPU Time: {:.3} ms", duration_to_ms(mean_gpu_sample.elapsed)),
|
||||
self.ui.draw_text(
|
||||
device,
|
||||
&format!(
|
||||
"GPU Time: {:.3} ms",
|
||||
duration_to_ms(mean_gpu_sample.elapsed)
|
||||
),
|
||||
origin + Point2DI32::new(0, LINE_HEIGHT * 5),
|
||||
false);
|
||||
false,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
struct SampleBuffer<S> where S: Add<S, Output=S> + Div<usize, Output=S> + Clone + Default {
|
||||
struct SampleBuffer<S>
|
||||
where
|
||||
S: Add<S, Output = S> + Div<usize, Output = S> + Clone + Default,
|
||||
{
|
||||
samples: VecDeque<S>,
|
||||
}
|
||||
|
||||
impl<S> SampleBuffer<S> where S: Add<S, Output=S> + Div<usize, Output=S> + Clone + Default {
|
||||
impl<S> SampleBuffer<S>
|
||||
where
|
||||
S: Add<S, Output = S> + Div<usize, Output = S> + Clone + Default,
|
||||
{
|
||||
fn new() -> SampleBuffer<S> {
|
||||
SampleBuffer { samples: VecDeque::with_capacity(SAMPLE_BUFFER_SIZE) }
|
||||
SampleBuffer {
|
||||
samples: VecDeque::with_capacity(SAMPLE_BUFFER_SIZE),
|
||||
}
|
||||
}
|
||||
|
||||
fn push(&mut self, time: S) {
|
||||
|
@ -135,14 +185,20 @@ struct CPUSample {
|
|||
impl Add<CPUSample> for CPUSample {
|
||||
type Output = CPUSample;
|
||||
fn add(self, other: CPUSample) -> CPUSample {
|
||||
CPUSample { elapsed: self.elapsed + other.elapsed, stats: self.stats + other.stats }
|
||||
CPUSample {
|
||||
elapsed: self.elapsed + other.elapsed,
|
||||
stats: self.stats + other.stats,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Div<usize> for CPUSample {
|
||||
type Output = CPUSample;
|
||||
fn div(self, divisor: usize) -> CPUSample {
|
||||
CPUSample { elapsed: self.elapsed / (divisor as u32), stats: self.stats / divisor }
|
||||
CPUSample {
|
||||
elapsed: self.elapsed / (divisor as u32),
|
||||
stats: self.stats / divisor,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -154,14 +210,18 @@ struct GPUSample {
|
|||
impl Add<GPUSample> for GPUSample {
|
||||
type Output = GPUSample;
|
||||
fn add(self, other: GPUSample) -> GPUSample {
|
||||
GPUSample { elapsed: self.elapsed + other.elapsed }
|
||||
GPUSample {
|
||||
elapsed: self.elapsed + other.elapsed,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Div<usize> for GPUSample {
|
||||
type Output = GPUSample;
|
||||
fn div(self, divisor: usize) -> GPUSample {
|
||||
GPUSample { elapsed: self.elapsed / (divisor as u32) }
|
||||
GPUSample {
|
||||
elapsed: self.elapsed / (divisor as u32),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -86,7 +86,12 @@ impl BuiltObject {
|
|||
pub(crate) fn new(bounds: RectF32) -> BuiltObject {
|
||||
let tile_rect = tiles::round_rect_out_to_tile_bounds(bounds);
|
||||
let tiles = DenseTileMap::new(tile_rect);
|
||||
BuiltObject { bounds, fills: vec![], alpha_tiles: vec![], tiles }
|
||||
BuiltObject {
|
||||
bounds,
|
||||
fills: vec![],
|
||||
alpha_tiles: vec![],
|
||||
tiles,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
@ -94,10 +99,12 @@ impl BuiltObject {
|
|||
self.tiles.rect
|
||||
}
|
||||
|
||||
fn add_fill(&mut self,
|
||||
fn add_fill(
|
||||
&mut self,
|
||||
builder: &SceneBuilder,
|
||||
segment: &LineSegmentF32,
|
||||
tile_coords: Point2DI32) {
|
||||
tile_coords: Point2DI32,
|
||||
) {
|
||||
debug!("add_fill({:?} ({:?}))", segment, tile_coords);
|
||||
|
||||
// Ensure this fill is in bounds. If not, cull it.
|
||||
|
@ -107,22 +114,30 @@ impl BuiltObject {
|
|||
|
||||
debug_assert_eq!(TILE_WIDTH, TILE_HEIGHT);
|
||||
let tile_size = F32x4::splat(TILE_WIDTH as f32);
|
||||
let (min, max) = (F32x4::default(), F32x4::splat((TILE_WIDTH * 256 - 1) as f32));
|
||||
let (min, max) = (
|
||||
F32x4::default(),
|
||||
F32x4::splat((TILE_WIDTH * 256 - 1) as f32),
|
||||
);
|
||||
let shuffle_mask = I32x4::new(0x0c08_0400, 0x0d05_0901, 0, 0).as_u8x16();
|
||||
|
||||
let tile_upper_left = tile_coords.to_f32().0.xyxy() * tile_size;
|
||||
|
||||
let segment = (segment.0 - tile_upper_left) * F32x4::splat(256.0);
|
||||
let segment =
|
||||
segment.clamp(min, max).to_i32x4().as_u8x16().shuffle(shuffle_mask).as_i32x4();
|
||||
let segment = segment
|
||||
.clamp(min, max)
|
||||
.to_i32x4()
|
||||
.as_u8x16()
|
||||
.shuffle(shuffle_mask)
|
||||
.as_i32x4();
|
||||
|
||||
// Unpack whole and fractional pixels.
|
||||
let px = LineSegmentU4((segment[1] | (segment[1] >> 12)) as u16);
|
||||
let subpx = LineSegmentU8(segment[0] as u32);
|
||||
|
||||
// Cull degenerate fills.
|
||||
if (px.0 & 0xf) as u8 == ((px.0 >> 8) & 0xf) as u8 &&
|
||||
(subpx.0 & 0xff) as u8 == ((subpx.0 >> 16) & 0xff) as u8 {
|
||||
if (px.0 & 0xf) as u8 == ((px.0 >> 8) & 0xf) as u8
|
||||
&& (subpx.0 & 0xff) as u8 == ((subpx.0 >> 16) & 0xff) as u8
|
||||
{
|
||||
debug!("... culling!");
|
||||
return;
|
||||
}
|
||||
|
@ -131,29 +146,39 @@ impl BuiltObject {
|
|||
let alpha_tile_index = self.get_or_allocate_alpha_tile_index(builder, tile_coords);
|
||||
|
||||
debug!("... OK, pushing");
|
||||
self.fills.push(FillBatchPrimitive { px, subpx, alpha_tile_index });
|
||||
self.fills.push(FillBatchPrimitive {
|
||||
px,
|
||||
subpx,
|
||||
alpha_tile_index,
|
||||
});
|
||||
}
|
||||
|
||||
fn get_or_allocate_alpha_tile_index(&mut self, builder: &SceneBuilder, tile_coords: Point2DI32)
|
||||
-> u16 {
|
||||
fn get_or_allocate_alpha_tile_index(
|
||||
&mut self,
|
||||
builder: &SceneBuilder,
|
||||
tile_coords: Point2DI32,
|
||||
) -> u16 {
|
||||
let local_tile_index = self.tiles.coords_to_index_unchecked(tile_coords);
|
||||
let alpha_tile_index = self.tiles.data[local_tile_index].alpha_tile_index;
|
||||
if alpha_tile_index != !0 {
|
||||
return alpha_tile_index;
|
||||
}
|
||||
|
||||
let alpha_tile_index = builder.next_alpha_tile_index
|
||||
let alpha_tile_index = builder
|
||||
.next_alpha_tile_index
|
||||
.fetch_add(1, Ordering::Relaxed) as u16;
|
||||
self.tiles.data[local_tile_index].alpha_tile_index = alpha_tile_index;
|
||||
alpha_tile_index
|
||||
}
|
||||
|
||||
pub(crate) fn add_active_fill(&mut self,
|
||||
pub(crate) fn add_active_fill(
|
||||
&mut self,
|
||||
builder: &SceneBuilder,
|
||||
left: f32,
|
||||
right: f32,
|
||||
mut winding: i32,
|
||||
tile_coords: Point2DI32) {
|
||||
tile_coords: Point2DI32,
|
||||
) {
|
||||
let tile_origin_y = (tile_coords.y() * TILE_HEIGHT as i32) as f32;
|
||||
let left = Point2DF32::new(left, tile_origin_y);
|
||||
let right = Point2DF32::new(right, tile_origin_y);
|
||||
|
@ -164,11 +189,13 @@ impl BuiltObject {
|
|||
LineSegmentF32::new(&right, &left)
|
||||
};
|
||||
|
||||
debug!("... emitting active fill {} -> {} winding {} @ tile {:?}",
|
||||
debug!(
|
||||
"... emitting active fill {} -> {} winding {} @ tile {:?}",
|
||||
left.x(),
|
||||
right.x(),
|
||||
winding,
|
||||
tile_coords);
|
||||
tile_coords
|
||||
);
|
||||
|
||||
while winding != 0 {
|
||||
self.add_fill(builder, &segment, tile_coords);
|
||||
|
@ -180,15 +207,19 @@ impl BuiltObject {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn generate_fill_primitives_for_line(&mut self,
|
||||
pub(crate) fn generate_fill_primitives_for_line(
|
||||
&mut self,
|
||||
builder: &SceneBuilder,
|
||||
mut segment: LineSegmentF32,
|
||||
tile_y: i32) {
|
||||
debug!("... generate_fill_primitives_for_line(): segment={:?} tile_y={} ({}-{})",
|
||||
tile_y: i32,
|
||||
) {
|
||||
debug!(
|
||||
"... generate_fill_primitives_for_line(): segment={:?} tile_y={} ({}-{})",
|
||||
segment,
|
||||
tile_y,
|
||||
tile_y as f32 * TILE_HEIGHT as f32,
|
||||
(tile_y + 1) as f32 * TILE_HEIGHT as f32);
|
||||
(tile_y + 1) as f32 * TILE_HEIGHT as f32
|
||||
);
|
||||
|
||||
let winding = segment.from_x() > segment.to_x();
|
||||
let (segment_left, segment_right) = if !winding {
|
||||
|
@ -201,10 +232,12 @@ impl BuiltObject {
|
|||
let segment_tile_left = f32::floor(segment_left) as i32 / TILE_WIDTH as i32;
|
||||
let segment_tile_right =
|
||||
util::alignup_i32(f32::ceil(segment_right) as i32, TILE_WIDTH as i32);
|
||||
debug!("segment_tile_left={} segment_tile_right={} tile_rect={:?}",
|
||||
debug!(
|
||||
"segment_tile_left={} segment_tile_right={} tile_rect={:?}",
|
||||
segment_tile_left,
|
||||
segment_tile_right,
|
||||
self.tile_rect());
|
||||
self.tile_rect()
|
||||
);
|
||||
|
||||
for subsegment_tile_x in segment_tile_left..segment_tile_right {
|
||||
let (mut fill_from, mut fill_to) = (segment.from(), segment.to());
|
||||
|
@ -242,7 +275,10 @@ impl BuiltObject {
|
|||
impl Default for TileObjectPrimitive {
|
||||
#[inline]
|
||||
fn default() -> TileObjectPrimitive {
|
||||
TileObjectPrimitive { backdrop: 0, alpha_tile_index: !0 }
|
||||
TileObjectPrimitive {
|
||||
backdrop: 0,
|
||||
alpha_tile_index: !0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -255,8 +291,12 @@ impl TileObjectPrimitive {
|
|||
|
||||
impl AlphaTileBatchPrimitive {
|
||||
#[inline]
|
||||
pub fn new(tile_coords: Point2DI32, backdrop: i8, object_index: u16, tile_index: u16)
|
||||
-> AlphaTileBatchPrimitive {
|
||||
pub fn new(
|
||||
tile_coords: Point2DI32,
|
||||
backdrop: i8,
|
||||
object_index: u16,
|
||||
tile_index: u16,
|
||||
) -> AlphaTileBatchPrimitive {
|
||||
AlphaTileBatchPrimitive {
|
||||
tile_x_lo: (tile_coords.x() & 0xff) as u8,
|
||||
tile_y_lo: (tile_coords.y() & 0xff) as u8,
|
||||
|
@ -269,8 +309,10 @@ impl AlphaTileBatchPrimitive {
|
|||
|
||||
#[inline]
|
||||
pub fn tile_coords(&self) -> Point2DI32 {
|
||||
Point2DI32::new((self.tile_x_lo as i32) | (((self.tile_hi & 0xf) as i32) << 8),
|
||||
(self.tile_y_lo as i32) | (((self.tile_hi & 0xf0) as i32) << 4))
|
||||
Point2DI32::new(
|
||||
(self.tile_x_lo as i32) | (((self.tile_hi & 0xf) as i32) << 8),
|
||||
(self.tile_y_lo as i32) | (((self.tile_hi & 0xf0) as i32) << 4),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -279,12 +321,8 @@ impl Debug for RenderCommand {
|
|||
match *self {
|
||||
RenderCommand::AddFills(ref fills) => write!(formatter, "AddFills(x{})", fills.len()),
|
||||
RenderCommand::FlushFills => write!(formatter, "FlushFills"),
|
||||
RenderCommand::AlphaTile(ref tiles) => {
|
||||
write!(formatter, "AlphaTile(x{})", tiles.len())
|
||||
}
|
||||
RenderCommand::SolidTile(ref tiles) => {
|
||||
write!(formatter, "SolidTile(x{})", tiles.len())
|
||||
}
|
||||
RenderCommand::AlphaTile(ref tiles) => write!(formatter, "AlphaTile(x{})", tiles.len()),
|
||||
RenderCommand::SolidTile(ref tiles) => write!(formatter, "SolidTile(x{})", tiles.len()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,12 +18,10 @@ pub struct DefringingKernel(pub [f32; 4]);
|
|||
|
||||
/// This intentionally does not precisely match what Core Graphics does (a
|
||||
/// Lanczos function), because we don't want any ringing artefacts.
|
||||
pub static DEFRINGING_KERNEL_CORE_GRAPHICS: DefringingKernel = DefringingKernel([
|
||||
0.033165660, 0.102074051, 0.221434336, 0.286651906
|
||||
]);
|
||||
pub static DEFRINGING_KERNEL_FREETYPE: DefringingKernel = DefringingKernel([
|
||||
0.0, 0.031372549, 0.301960784, 0.337254902
|
||||
]);
|
||||
pub static DEFRINGING_KERNEL_CORE_GRAPHICS: DefringingKernel =
|
||||
DefringingKernel([0.033165660, 0.102074051, 0.221434336, 0.286651906]);
|
||||
pub static DEFRINGING_KERNEL_FREETYPE: DefringingKernel =
|
||||
DefringingKernel([0.0, 0.031372549, 0.301960784, 0.337254902]);
|
||||
|
||||
/// Should match macOS 10.13 High Sierra.
|
||||
pub static STEM_DARKENING_FACTORS: [f32; 2] = [0.0121, 0.0121 * 1.25];
|
||||
|
|
|
@ -61,21 +61,31 @@ impl Scene {
|
|||
}
|
||||
|
||||
fn build_shaders(&self) -> Vec<ObjectShader> {
|
||||
self.objects.iter().map(|object| {
|
||||
self.objects
|
||||
.iter()
|
||||
.map(|object| {
|
||||
let paint = &self.paints[object.paint.0 as usize];
|
||||
ObjectShader { fill_color: paint.color }
|
||||
}).collect()
|
||||
ObjectShader {
|
||||
fill_color: paint.color,
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub(crate) fn apply_render_options(&self,
|
||||
pub(crate) fn apply_render_options(
|
||||
&self,
|
||||
original_outline: &Outline,
|
||||
options: &PreparedRenderOptions)
|
||||
-> Outline {
|
||||
options: &PreparedRenderOptions,
|
||||
) -> Outline {
|
||||
let effective_view_box = self.effective_view_box(options);
|
||||
|
||||
let mut outline;
|
||||
match options.transform {
|
||||
PreparedRenderTransform::Perspective { ref perspective, ref clip_polygon, .. } => {
|
||||
PreparedRenderTransform::Perspective {
|
||||
ref perspective,
|
||||
ref clip_polygon,
|
||||
..
|
||||
} => {
|
||||
if original_outline.is_outside_polygon(clip_polygon) {
|
||||
outline = Outline::new();
|
||||
} else {
|
||||
|
@ -96,8 +106,8 @@ impl Scene {
|
|||
PreparedRenderTransform::Perspective { .. } => unreachable!(),
|
||||
};
|
||||
if options.subpixel_aa_enabled {
|
||||
transform = transform.post_mul(&Transform2DF32::from_scale(
|
||||
&Point2DF32::new(3.0, 1.0)))
|
||||
transform = transform
|
||||
.post_mul(&Transform2DF32::from_scale(&Point2DF32::new(3.0, 1.0)))
|
||||
}
|
||||
outline.transform(&transform);
|
||||
}
|
||||
|
@ -120,7 +130,12 @@ impl Scene {
|
|||
return None;
|
||||
}
|
||||
let first_paint_id = self.objects[0].paint;
|
||||
if self.objects.iter().skip(1).any(|object| object.paint != first_paint_id) {
|
||||
if self
|
||||
.objects
|
||||
.iter()
|
||||
.skip(1)
|
||||
.any(|object| object.paint != first_paint_id)
|
||||
{
|
||||
return None;
|
||||
}
|
||||
Some(self.paints[first_paint_id.0 as usize].color)
|
||||
|
@ -138,19 +153,25 @@ impl Scene {
|
|||
|
||||
impl Debug for Scene {
|
||||
fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
|
||||
writeln!(formatter,
|
||||
writeln!(
|
||||
formatter,
|
||||
"<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"{} {} {} {}\">",
|
||||
self.view_box.origin().x(),
|
||||
self.view_box.origin().y(),
|
||||
self.view_box.size().x(),
|
||||
self.view_box.size().y())?;
|
||||
self.view_box.size().y()
|
||||
)?;
|
||||
for object in &self.objects {
|
||||
let paint = &self.paints[object.paint.0 as usize];
|
||||
write!(formatter, " <path")?;
|
||||
if !object.name.is_empty() {
|
||||
write!(formatter, " id=\"{}\"", object.name)?;
|
||||
}
|
||||
writeln!(formatter, " fill=\"{:?}\" d=\"{:?}\" />", paint.color, object.outline)?;
|
||||
writeln!(
|
||||
formatter,
|
||||
" fill=\"{:?}\" d=\"{:?}\" />",
|
||||
paint.color, object.outline
|
||||
)?;
|
||||
}
|
||||
writeln!(formatter, "</svg>")?;
|
||||
Ok(())
|
||||
|
@ -180,9 +201,13 @@ pub enum PathObjectKind {
|
|||
|
||||
impl PathObject {
|
||||
#[inline]
|
||||
pub fn new(outline: Outline, paint: PaintId, name: String, kind: PathObjectKind)
|
||||
-> PathObject {
|
||||
PathObject { outline, paint, name, kind }
|
||||
pub fn new(outline: Outline, paint: PaintId, name: String, kind: PathObjectKind) -> PathObject {
|
||||
PathObject {
|
||||
outline,
|
||||
paint,
|
||||
name,
|
||||
kind,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
|
|
@ -19,31 +19,46 @@ pub struct DenseTileMap<T> {
|
|||
|
||||
impl<T> DenseTileMap<T> {
|
||||
#[inline]
|
||||
pub fn new(rect: RectI32) -> DenseTileMap<T> where T: Copy + Clone + Default {
|
||||
pub fn new(rect: RectI32) -> DenseTileMap<T>
|
||||
where
|
||||
T: Copy + Clone + Default,
|
||||
{
|
||||
let length = rect.size().x() as usize * rect.size().y() as usize;
|
||||
DenseTileMap { data: vec![T::default(); length], rect }
|
||||
DenseTileMap {
|
||||
data: vec![T::default(); length],
|
||||
rect,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn from_builder<F>(build: F, rect: RectI32) -> DenseTileMap<T> where F: FnMut(usize) -> T {
|
||||
pub fn from_builder<F>(build: F, rect: RectI32) -> DenseTileMap<T>
|
||||
where
|
||||
F: FnMut(usize) -> T,
|
||||
{
|
||||
let length = rect.size().x() as usize * rect.size().y() as usize;
|
||||
DenseTileMap { data: (0..length).map(build).collect(), rect }
|
||||
DenseTileMap {
|
||||
data: (0..length).map(build).collect(),
|
||||
rect,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn coords_to_index(&self, coords: Point2DI32) -> Option<usize> {
|
||||
// TODO(pcwalton): SIMD?
|
||||
if coords.x() < self.rect.min_x() || coords.x() >= self.rect.max_x() ||
|
||||
coords.y() < self.rect.min_y() || coords.y() >= self.rect.max_y() {
|
||||
return None
|
||||
if coords.x() < self.rect.min_x()
|
||||
|| coords.x() >= self.rect.max_x()
|
||||
|| coords.y() < self.rect.min_y()
|
||||
|| coords.y() >= self.rect.max_y()
|
||||
{
|
||||
return None;
|
||||
}
|
||||
Some(self.coords_to_index_unchecked(coords))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn coords_to_index_unchecked(&self, coords: Point2DI32) -> usize {
|
||||
(coords.y() - self.rect.min_y()) as usize * self.rect.size().x() as usize +
|
||||
(coords.x() - self.rect.min_x()) as usize
|
||||
(coords.y() - self.rect.min_y()) as usize * self.rect.size().x() as usize
|
||||
+ (coords.x() - self.rect.min_x()) as usize
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
|
|
@ -38,12 +38,16 @@ pub(crate) struct Tiler<'a> {
|
|||
|
||||
impl<'a> Tiler<'a> {
|
||||
#[allow(clippy::or_fun_call)]
|
||||
pub(crate) fn new(builder: &'a SceneBuilder<'a>,
|
||||
pub(crate) fn new(
|
||||
builder: &'a SceneBuilder<'a>,
|
||||
outline: &'a Outline,
|
||||
view_box: RectF32,
|
||||
object_index: u16)
|
||||
-> Tiler<'a> {
|
||||
let bounds = outline.bounds().intersection(view_box).unwrap_or(RectF32::default());
|
||||
object_index: u16,
|
||||
) -> Tiler<'a> {
|
||||
let bounds = outline
|
||||
.bounds()
|
||||
.intersection(view_box)
|
||||
.unwrap_or(RectF32::default());
|
||||
let built_object = BuiltObject::new(bounds);
|
||||
|
||||
Tiler {
|
||||
|
@ -100,7 +104,9 @@ impl<'a> Tiler<'a> {
|
|||
|
||||
fn pack_and_cull(&mut self) {
|
||||
for (tile_index, tile) in self.built_object.tiles.data.iter().enumerate() {
|
||||
let tile_coords = self.built_object.local_tile_index_to_coords(tile_index as u32);
|
||||
let tile_coords = self
|
||||
.built_object
|
||||
.local_tile_index_to_coords(tile_index as u32);
|
||||
if tile.is_solid() {
|
||||
if tile.backdrop != 0 {
|
||||
self.builder.z_buffer.update(tile_coords, self.object_index);
|
||||
|
@ -108,10 +114,12 @@ impl<'a> Tiler<'a> {
|
|||
continue;
|
||||
}
|
||||
|
||||
let alpha_tile = AlphaTileBatchPrimitive::new(tile_coords,
|
||||
let alpha_tile = AlphaTileBatchPrimitive::new(
|
||||
tile_coords,
|
||||
tile.backdrop,
|
||||
self.object_index,
|
||||
tile.alpha_tile_index as u16);
|
||||
tile.alpha_tile_index as u16,
|
||||
);
|
||||
self.built_object.alpha_tiles.push(alpha_tile);
|
||||
}
|
||||
}
|
||||
|
@ -142,7 +150,8 @@ impl<'a> Tiler<'a> {
|
|||
-1
|
||||
};
|
||||
|
||||
debug!("tile Y {}({}): segment_x={} edge_winding={} current_tile_x={} \
|
||||
debug!(
|
||||
"tile Y {}({}): segment_x={} edge_winding={} current_tile_x={} \
|
||||
current_subtile_x={} current_winding={}",
|
||||
tile_y,
|
||||
tile_top,
|
||||
|
@ -150,8 +159,12 @@ impl<'a> Tiler<'a> {
|
|||
edge_winding,
|
||||
current_tile_x,
|
||||
current_subtile_x,
|
||||
current_winding);
|
||||
debug!("... segment={:#?} crossing={:?}", active_edge.segment, active_edge.crossing);
|
||||
current_winding
|
||||
);
|
||||
debug!(
|
||||
"... segment={:#?} crossing={:?}",
|
||||
active_edge.segment, active_edge.crossing
|
||||
);
|
||||
|
||||
// FIXME(pcwalton): Remove this debug code!
|
||||
debug_assert!(segment_x >= last_segment_x);
|
||||
|
@ -164,21 +177,28 @@ impl<'a> Tiler<'a> {
|
|||
(i32::from(current_tile_x) * TILE_WIDTH as i32) as f32 + current_subtile_x;
|
||||
let tile_right_x = ((i32::from(current_tile_x) + 1) * TILE_WIDTH as i32) as f32;
|
||||
let current_tile_coords = Point2DI32::new(current_tile_x, tile_y);
|
||||
self.built_object.add_active_fill(self.builder,
|
||||
self.built_object.add_active_fill(
|
||||
self.builder,
|
||||
current_x,
|
||||
tile_right_x,
|
||||
current_winding,
|
||||
current_tile_coords);
|
||||
current_tile_coords,
|
||||
);
|
||||
current_tile_x += 1;
|
||||
current_subtile_x = 0.0;
|
||||
}
|
||||
|
||||
// Move over to the correct tile, filling in as we go.
|
||||
while current_tile_x < segment_tile_x {
|
||||
debug!("... emitting backdrop {} @ tile {}", current_winding, current_tile_x);
|
||||
debug!(
|
||||
"... emitting backdrop {} @ tile {}",
|
||||
current_winding, current_tile_x
|
||||
);
|
||||
let current_tile_coords = Point2DI32::new(current_tile_x, tile_y);
|
||||
if let Some(tile_index) = self.built_object
|
||||
.tile_coords_to_local_index(current_tile_coords) {
|
||||
if let Some(tile_index) = self
|
||||
.built_object
|
||||
.tile_coords_to_local_index(current_tile_coords)
|
||||
{
|
||||
// FIXME(pcwalton): Handle winding overflow.
|
||||
self.built_object.tiles.data[tile_index as usize].backdrop =
|
||||
current_winding as i8;
|
||||
|
@ -196,11 +216,13 @@ impl<'a> Tiler<'a> {
|
|||
let current_x =
|
||||
(i32::from(current_tile_x) * TILE_WIDTH as i32) as f32 + current_subtile_x;
|
||||
let current_tile_coords = Point2DI32::new(current_tile_x, tile_y);
|
||||
self.built_object.add_active_fill(self.builder,
|
||||
self.built_object.add_active_fill(
|
||||
self.builder,
|
||||
current_x,
|
||||
segment_x,
|
||||
current_winding,
|
||||
current_tile_coords);
|
||||
current_tile_coords,
|
||||
);
|
||||
current_subtile_x = segment_subtile_x;
|
||||
}
|
||||
|
||||
|
@ -229,7 +251,8 @@ impl<'a> Tiler<'a> {
|
|||
let prev_endpoint_index = contour.prev_endpoint_index_of(point_index.point());
|
||||
let next_endpoint_index = contour.next_endpoint_index_of(point_index.point());
|
||||
|
||||
debug!("adding new active edge, tile_y={} point_index={} prev={} next={} pos={:?} \
|
||||
debug!(
|
||||
"adding new active edge, tile_y={} point_index={} prev={} next={} pos={:?} \
|
||||
prevpos={:?} nextpos={:?}",
|
||||
tile_y,
|
||||
point_index.point(),
|
||||
|
@ -237,7 +260,8 @@ impl<'a> Tiler<'a> {
|
|||
next_endpoint_index,
|
||||
contour.position_of(point_index.point()),
|
||||
contour.position_of(prev_endpoint_index),
|
||||
contour.position_of(next_endpoint_index));
|
||||
contour.position_of(next_endpoint_index)
|
||||
);
|
||||
|
||||
if contour.point_is_logically_above(point_index.point(), prev_endpoint_index) {
|
||||
debug!("... adding prev endpoint");
|
||||
|
@ -260,7 +284,11 @@ impl<'a> Tiler<'a> {
|
|||
}
|
||||
|
||||
if contour.point_is_logically_above(point_index.point(), next_endpoint_index) {
|
||||
debug!("... adding next endpoint {} -> {}", point_index.point(), next_endpoint_index);
|
||||
debug!(
|
||||
"... adding next endpoint {} -> {}",
|
||||
point_index.point(),
|
||||
next_endpoint_index
|
||||
);
|
||||
|
||||
process_active_segment(
|
||||
contour,
|
||||
|
@ -311,7 +339,10 @@ impl<'a> Tiler<'a> {
|
|||
}
|
||||
|
||||
pub fn round_rect_out_to_tile_bounds(rect: RectF32) -> RectI32 {
|
||||
rect.scale_xy(Point2DF32::new(1.0 / TILE_WIDTH as f32, 1.0 / TILE_HEIGHT as f32))
|
||||
rect.scale_xy(Point2DF32::new(
|
||||
1.0 / TILE_WIDTH as f32,
|
||||
1.0 / TILE_HEIGHT as f32,
|
||||
))
|
||||
.round_out()
|
||||
.to_i32()
|
||||
}
|
||||
|
@ -378,17 +409,18 @@ impl ActiveEdge {
|
|||
|
||||
fn process(&mut self, builder: &SceneBuilder, built_object: &mut BuiltObject, tile_y: i32) {
|
||||
let tile_bottom = ((i32::from(tile_y) + 1) * TILE_HEIGHT as i32) as f32;
|
||||
debug!("process_active_edge({:#?}, tile_y={}({}))", self, tile_y, tile_bottom);
|
||||
debug!(
|
||||
"process_active_edge({:#?}, tile_y={}({}))",
|
||||
self, tile_y, tile_bottom
|
||||
);
|
||||
|
||||
let mut segment = self.segment;
|
||||
let winding = segment.baseline.y_winding();
|
||||
|
||||
if segment.is_line() {
|
||||
let line_segment = segment.as_line_segment();
|
||||
self.segment = match self.process_line_segment(&line_segment,
|
||||
builder,
|
||||
built_object,
|
||||
tile_y) {
|
||||
self.segment =
|
||||
match self.process_line_segment(&line_segment, builder, built_object, tile_y) {
|
||||
Some(lower_part) => Segment::line(&lower_part),
|
||||
None => Segment::none(),
|
||||
};
|
||||
|
@ -405,8 +437,10 @@ impl ActiveEdge {
|
|||
let first_line_segment =
|
||||
LineSegmentF32::new(&self.crossing, &segment.baseline.upper_point())
|
||||
.orient(winding);
|
||||
if self.process_line_segment(&first_line_segment, builder, built_object, tile_y)
|
||||
.is_some() {
|
||||
if self
|
||||
.process_line_segment(&first_line_segment, builder, built_object, tile_y)
|
||||
.is_some()
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -417,7 +451,10 @@ impl ActiveEdge {
|
|||
let mut before_segment = oriented_segment;
|
||||
let mut after_segment = None;
|
||||
|
||||
while !before_segment.as_cubic_segment().is_flat(FLATTENING_TOLERANCE) {
|
||||
while !before_segment
|
||||
.as_cubic_segment()
|
||||
.is_flat(FLATTENING_TOLERANCE)
|
||||
{
|
||||
let next_t = 0.5 * split_t;
|
||||
let (before, after) = oriented_segment.as_cubic_segment().split(next_t);
|
||||
before_segment = before;
|
||||
|
@ -425,14 +462,11 @@ impl ActiveEdge {
|
|||
split_t = next_t;
|
||||
}
|
||||
|
||||
debug!("... tile_y={} winding={} segment={:?} t={} before_segment={:?}
|
||||
debug!(
|
||||
"... tile_y={} winding={} segment={:?} t={} before_segment={:?}
|
||||
after_segment={:?}",
|
||||
tile_y,
|
||||
winding,
|
||||
segment,
|
||||
split_t,
|
||||
before_segment,
|
||||
after_segment);
|
||||
tile_y, winding, segment, split_t, before_segment, after_segment
|
||||
);
|
||||
|
||||
let line = before_segment.baseline.orient(winding);
|
||||
match self.process_line_segment(&line, builder, built_object, tile_y) {
|
||||
|
@ -461,10 +495,10 @@ impl ActiveEdge {
|
|||
tile_y: i32,
|
||||
) -> Option<LineSegmentF32> {
|
||||
let tile_bottom = ((i32::from(tile_y) + 1) * TILE_HEIGHT as i32) as f32;
|
||||
debug!("process_line_segment({:?}, tile_y={}) tile_bottom={}",
|
||||
line_segment,
|
||||
tile_y,
|
||||
tile_bottom);
|
||||
debug!(
|
||||
"process_line_segment({:?}, tile_y={}) tile_bottom={}",
|
||||
line_segment, tile_y, tile_bottom
|
||||
);
|
||||
|
||||
if line_segment.max_y() <= tile_bottom {
|
||||
built_object.generate_fill_primitives_for_line(builder, *line_segment, tile_y);
|
||||
|
|
|
@ -25,7 +25,9 @@ pub struct ZBuffer {
|
|||
impl ZBuffer {
|
||||
pub fn new(view_box: RectF32) -> ZBuffer {
|
||||
let tile_rect = tiles::round_rect_out_to_tile_bounds(view_box);
|
||||
ZBuffer { buffer: DenseTileMap::from_builder(|_| AtomicUsize::new(0), tile_rect) }
|
||||
ZBuffer {
|
||||
buffer: DenseTileMap::from_builder(|_| AtomicUsize::new(0), tile_rect),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn test(&self, coords: Point2DI32, object_index: u32) -> bool {
|
||||
|
|
Loading…
Reference in New Issue