Run `rustfmt` on the renderer crate

This commit is contained in:
Patrick Walton 2019-04-29 16:45:29 -07:00
parent 8606cd013e
commit db8eb1c97c
10 changed files with 1108 additions and 632 deletions

View File

@ -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)]

View File

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

View File

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

View File

@ -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];

View File

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

View File

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

View File

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

View File

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