Introduce a `DenseTileMap<T>` type for better abstraction and SIMD use
This commit is contained in:
parent
9e38da25e1
commit
6a967c19f4
|
@ -16,7 +16,7 @@ use crate::scene::{self, Scene};
|
||||||
use crate::sorted_vector::SortedVector;
|
use crate::sorted_vector::SortedVector;
|
||||||
use crate::tiles::{self, Tiler};
|
use crate::tiles::{self, Tiler};
|
||||||
use crate::z_buffer::ZBuffer;
|
use crate::z_buffer::ZBuffer;
|
||||||
use pathfinder_geometry::basic::point::{Point2DF32, Point3DF32};
|
use pathfinder_geometry::basic::point::{Point2DF32, Point2DI32, Point3DF32};
|
||||||
use pathfinder_geometry::basic::rect::{RectF32, RectI32};
|
use pathfinder_geometry::basic::rect::{RectF32, RectI32};
|
||||||
use pathfinder_geometry::basic::transform2d::Transform2DF32;
|
use pathfinder_geometry::basic::transform2d::Transform2DF32;
|
||||||
use pathfinder_geometry::basic::transform3d::Perspective;
|
use pathfinder_geometry::basic::transform3d::Perspective;
|
||||||
|
@ -178,7 +178,7 @@ impl SceneAssemblyThread {
|
||||||
// Copy alpha tiles.
|
// Copy alpha tiles.
|
||||||
let mut current_pass = &mut self.info.as_mut().unwrap().current_pass;
|
let mut current_pass = &mut self.info.as_mut().unwrap().current_pass;
|
||||||
let mut object_tile_index_to_batch_alpha_tile_index = vec![u16::MAX; tile_count];
|
let mut object_tile_index_to_batch_alpha_tile_index = vec![u16::MAX; tile_count];
|
||||||
for (tile_index, tile_backdrop) in object.tile_backdrops.iter().cloned().enumerate() {
|
for (tile_index, tile_backdrop) in object.tile_backdrops.data.iter().cloned().enumerate() {
|
||||||
// Skip solid tiles.
|
// Skip solid tiles.
|
||||||
if object.solid_tiles[tile_index] {
|
if object.solid_tiles[tile_index] {
|
||||||
continue;
|
continue;
|
||||||
|
@ -198,8 +198,8 @@ impl SceneAssemblyThread {
|
||||||
|
|
||||||
// Remap and copy fills, culling as necessary.
|
// Remap and copy fills, culling as necessary.
|
||||||
for fill in &object.fills {
|
for fill in &object.fills {
|
||||||
let object_tile_index = object.tile_coords_to_index(fill.tile_x as i32,
|
let tile_coords = Point2DI32::new(fill.tile_x as i32, fill.tile_y as i32);
|
||||||
fill.tile_y as i32).unwrap();
|
let object_tile_index = object.tile_coords_to_index(tile_coords).unwrap();
|
||||||
let object_tile_index = object_tile_index as usize;
|
let object_tile_index = object_tile_index as usize;
|
||||||
let alpha_tile_index = object_tile_index_to_batch_alpha_tile_index[object_tile_index];
|
let alpha_tile_index = object_tile_index_to_batch_alpha_tile_index[object_tile_index];
|
||||||
current_pass.fills.push(FillBatchPrimitive {
|
current_pass.fills.push(FillBatchPrimitive {
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
//! Packed data ready to be sent to the GPU.
|
//! Packed data ready to be sent to the GPU.
|
||||||
|
|
||||||
use crate::scene::ObjectShader;
|
use crate::scene::ObjectShader;
|
||||||
|
use crate::tile_map::DenseTileMap;
|
||||||
use crate::tiles::{self, TILE_HEIGHT, TILE_WIDTH};
|
use crate::tiles::{self, TILE_HEIGHT, TILE_WIDTH};
|
||||||
use fixedbitset::FixedBitSet;
|
use fixedbitset::FixedBitSet;
|
||||||
use pathfinder_geometry::basic::line_segment::{LineSegmentF32, LineSegmentU4, LineSegmentU8};
|
use pathfinder_geometry::basic::line_segment::{LineSegmentF32, LineSegmentU4, LineSegmentU8};
|
||||||
|
@ -24,8 +25,7 @@ use std::ops::Add;
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct BuiltObject {
|
pub struct BuiltObject {
|
||||||
pub bounds: RectF32,
|
pub bounds: RectF32,
|
||||||
pub tile_rect: RectI32,
|
pub tile_backdrops: DenseTileMap<i16>,
|
||||||
pub tile_backdrops: Vec<i16>,
|
|
||||||
pub fills: Vec<FillObjectPrimitive>,
|
pub fills: Vec<FillObjectPrimitive>,
|
||||||
pub solid_tiles: FixedBitSet,
|
pub solid_tiles: FixedBitSet,
|
||||||
}
|
}
|
||||||
|
@ -95,23 +95,26 @@ impl BuiltObject {
|
||||||
let tile_rect = tiles::round_rect_out_to_tile_bounds(bounds);
|
let tile_rect = tiles::round_rect_out_to_tile_bounds(bounds);
|
||||||
|
|
||||||
// Allocate tiles.
|
// Allocate tiles.
|
||||||
let tile_count = tile_rect.size().x() as usize * tile_rect.size().y() as usize;
|
let tile_backdrops = DenseTileMap::new(tile_rect);
|
||||||
let tile_backdrops = vec![0; tile_count];
|
let mut solid_tiles = FixedBitSet::with_capacity(tile_backdrops.data.len());
|
||||||
let mut solid_tiles = FixedBitSet::with_capacity(tile_count);
|
|
||||||
solid_tiles.insert_range(..);
|
solid_tiles.insert_range(..);
|
||||||
|
|
||||||
BuiltObject { bounds, tile_rect, tile_backdrops, fills: vec![], solid_tiles }
|
BuiltObject { bounds, tile_backdrops, fills: vec![], solid_tiles }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn tile_rect(&self) -> RectI32 {
|
||||||
|
self.tile_backdrops.rect
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn tile_count(&self) -> u32 {
|
pub fn tile_count(&self) -> u32 {
|
||||||
self.tile_rect.size().x() as u32 * self.tile_rect.size().y() as u32
|
self.tile_backdrops.data.len() as u32
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(pcwalton): SIMD-ify `tile_x` and `tile_y`.
|
fn add_fill(&mut self, segment: &LineSegmentF32, tile_coords: Point2DI32) {
|
||||||
fn add_fill(&mut self, segment: &LineSegmentF32, tile_x: i32, tile_y: i32) {
|
|
||||||
//println!("add_fill({:?} ({}, {}))", segment, tile_x, tile_y);
|
//println!("add_fill({:?} ({}, {}))", segment, tile_x, tile_y);
|
||||||
let tile_index = match self.tile_coords_to_index(tile_x, tile_y) {
|
let tile_index = match self.tile_coords_to_index(tile_coords) {
|
||||||
None => return,
|
None => return,
|
||||||
Some(tile_index) => tile_index,
|
Some(tile_index) => tile_index,
|
||||||
};
|
};
|
||||||
|
@ -121,8 +124,8 @@ impl BuiltObject {
|
||||||
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 shuffle_mask = I32x4::new(0x0c08_0400, 0x0d05_0901, 0, 0).as_u8x16();
|
||||||
|
|
||||||
let tile_upper_left =
|
let tile_upper_left = tile_coords.to_f32().0.xyxy() * tile_size;
|
||||||
F32x4::new(tile_x as f32, tile_y as f32, tile_x as f32, tile_y as f32) * tile_size;
|
//F32x4::new(tile_x as f32, tile_y as f32, tile_x as f32, tile_y as f32) * tile_size;
|
||||||
|
|
||||||
let segment = (segment.0 - tile_upper_left) * F32x4::splat(256.0);
|
let segment = (segment.0 - tile_upper_left) * F32x4::splat(256.0);
|
||||||
let segment =
|
let segment =
|
||||||
|
@ -144,21 +147,18 @@ impl BuiltObject {
|
||||||
self.fills.push(FillObjectPrimitive {
|
self.fills.push(FillObjectPrimitive {
|
||||||
px,
|
px,
|
||||||
subpx,
|
subpx,
|
||||||
tile_x: tile_x as i16,
|
tile_x: tile_coords.x() as i16,
|
||||||
tile_y: tile_y as i16,
|
tile_y: tile_coords.y() as i16,
|
||||||
});
|
});
|
||||||
self.solid_tiles.set(tile_index as usize, false);
|
self.solid_tiles.set(tile_index as usize, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_active_fill(
|
pub fn add_active_fill(&mut self,
|
||||||
&mut self,
|
|
||||||
left: f32,
|
left: f32,
|
||||||
right: f32,
|
right: f32,
|
||||||
mut winding: i16,
|
mut winding: i16,
|
||||||
tile_x: i32,
|
tile_coords: Point2DI32) {
|
||||||
tile_y: i32,
|
let tile_origin_y = (tile_coords.y() * TILE_HEIGHT as i32) as f32;
|
||||||
) {
|
|
||||||
let tile_origin_y = (i32::from(tile_y) * TILE_HEIGHT as i32) as f32;
|
|
||||||
let left = Point2DF32::new(left, tile_origin_y);
|
let left = Point2DF32::new(left, tile_origin_y);
|
||||||
let right = Point2DF32::new(right, tile_origin_y);
|
let right = Point2DF32::new(right, tile_origin_y);
|
||||||
|
|
||||||
|
@ -176,7 +176,7 @@ impl BuiltObject {
|
||||||
tile_y);*/
|
tile_y);*/
|
||||||
|
|
||||||
while winding != 0 {
|
while winding != 0 {
|
||||||
self.add_fill(&segment, tile_x, tile_y);
|
self.add_fill(&segment, tile_coords);
|
||||||
if winding < 0 {
|
if winding < 0 {
|
||||||
winding += 1
|
winding += 1
|
||||||
} else {
|
} else {
|
||||||
|
@ -223,29 +223,18 @@ impl BuiltObject {
|
||||||
}
|
}
|
||||||
|
|
||||||
let fill_segment = LineSegmentF32::new(&fill_from, &fill_to);
|
let fill_segment = LineSegmentF32::new(&fill_from, &fill_to);
|
||||||
self.add_fill(&fill_segment, subsegment_tile_x, tile_y);
|
self.add_fill(&fill_segment, Point2DI32::new(subsegment_tile_x, tile_y));
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME(pcwalton): Use a `Point2DI32` instead?
|
|
||||||
pub fn tile_coords_to_index(&self, tile_x: i32, tile_y: i32) -> Option<u32> {
|
|
||||||
/*println!("tile_coords_to_index(x={}, y={}, tile_rect={:?})",
|
|
||||||
tile_x,
|
|
||||||
tile_y,
|
|
||||||
self.tile_rect);*/
|
|
||||||
if tile_x < self.tile_rect.min_x() || tile_x >= self.tile_rect.max_x() ||
|
|
||||||
tile_y < self.tile_rect.min_y() || tile_y >= self.tile_rect.max_y() {
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
Some((tile_y - self.tile_rect.min_y()) as u32 * self.tile_rect.size().x() as u32
|
|
||||||
+ (tile_x - self.tile_rect.min_x()) as u32)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn tile_coords_to_index(&self, coords: Point2DI32) -> Option<u32> {
|
||||||
|
self.tile_backdrops.coords_to_index(coords).map(|index| index as u32)
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn tile_index_to_coords(&self, tile_index: u32) -> Point2DI32 {
|
pub fn tile_index_to_coords(&self, tile_index: u32) -> Point2DI32 {
|
||||||
let (width, tile_index) = (self.tile_rect.size().x(), tile_index as i32);
|
self.tile_backdrops.index_to_coords(tile_index as usize)
|
||||||
self.tile_rect.origin() + Point2DI32::new(tile_index % width, tile_index / width)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,4 +18,5 @@ pub mod scene;
|
||||||
pub mod tiles;
|
pub mod tiles;
|
||||||
|
|
||||||
mod sorted_vector;
|
mod sorted_vector;
|
||||||
|
mod tile_map;
|
||||||
mod z_buffer;
|
mod z_buffer;
|
||||||
|
|
|
@ -12,7 +12,7 @@ use crate::gpu_data::BuiltObject;
|
||||||
use crate::sorted_vector::SortedVector;
|
use crate::sorted_vector::SortedVector;
|
||||||
use crate::z_buffer::ZBuffer;
|
use crate::z_buffer::ZBuffer;
|
||||||
use pathfinder_geometry::basic::line_segment::LineSegmentF32;
|
use pathfinder_geometry::basic::line_segment::LineSegmentF32;
|
||||||
use pathfinder_geometry::basic::point::Point2DF32;
|
use pathfinder_geometry::basic::point::{Point2DF32, Point2DI32};
|
||||||
use pathfinder_geometry::basic::rect::{RectF32, RectI32};
|
use pathfinder_geometry::basic::rect::{RectF32, RectI32};
|
||||||
use pathfinder_geometry::outline::{Contour, Outline, PointIndex};
|
use pathfinder_geometry::outline::{Contour, Outline, PointIndex};
|
||||||
use pathfinder_geometry::segment::Segment;
|
use pathfinder_geometry::segment::Segment;
|
||||||
|
@ -64,7 +64,7 @@ impl<'o, 'z> Tiler<'o, 'z> {
|
||||||
self.old_active_edges.clear();
|
self.old_active_edges.clear();
|
||||||
|
|
||||||
// Generate strips.
|
// Generate strips.
|
||||||
let tile_rect = self.built_object.tile_rect;
|
let tile_rect = self.built_object.tile_rect();
|
||||||
for strip_origin_y in tile_rect.min_y()..tile_rect.max_y() {
|
for strip_origin_y in tile_rect.min_y()..tile_rect.max_y() {
|
||||||
self.generate_strip(strip_origin_y);
|
self.generate_strip(strip_origin_y);
|
||||||
}
|
}
|
||||||
|
@ -95,7 +95,7 @@ impl<'o, 'z> Tiler<'o, 'z> {
|
||||||
|
|
||||||
fn cull(&self) {
|
fn cull(&self) {
|
||||||
for solid_tile_index in self.built_object.solid_tiles.ones() {
|
for solid_tile_index in self.built_object.solid_tiles.ones() {
|
||||||
if self.built_object.tile_backdrops[solid_tile_index] != 0 {
|
if self.built_object.tile_backdrops.data[solid_tile_index] != 0 {
|
||||||
let tile_coords = self.built_object.tile_index_to_coords(solid_tile_index as u32);
|
let tile_coords = self.built_object.tile_index_to_coords(solid_tile_index as u32);
|
||||||
self.z_buffer.update(tile_coords.x(), tile_coords.y(), self.object_index);
|
self.z_buffer.update(tile_coords.x(), tile_coords.y(), self.object_index);
|
||||||
}
|
}
|
||||||
|
@ -103,7 +103,7 @@ impl<'o, 'z> Tiler<'o, 'z> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn process_old_active_edges(&mut self, tile_y: i32) {
|
fn process_old_active_edges(&mut self, tile_y: i32) {
|
||||||
let mut current_tile_x = self.built_object.tile_rect.min_x();
|
let mut current_tile_x = self.built_object.tile_rect().min_x();
|
||||||
let mut current_subtile_x = 0.0;
|
let mut current_subtile_x = 0.0;
|
||||||
let mut current_winding = 0;
|
let mut current_winding = 0;
|
||||||
|
|
||||||
|
@ -149,13 +149,11 @@ impl<'o, 'z> Tiler<'o, 'z> {
|
||||||
let current_x =
|
let current_x =
|
||||||
(i32::from(current_tile_x) * TILE_WIDTH as i32) as f32 + current_subtile_x;
|
(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 tile_right_x = ((i32::from(current_tile_x) + 1) * TILE_WIDTH as i32) as f32;
|
||||||
self.built_object.add_active_fill(
|
let current_tile_coords = Point2DI32::new(current_tile_x, tile_y);
|
||||||
current_x,
|
self.built_object.add_active_fill(current_x,
|
||||||
tile_right_x,
|
tile_right_x,
|
||||||
current_winding,
|
current_winding,
|
||||||
current_tile_x,
|
current_tile_coords);
|
||||||
tile_y,
|
|
||||||
);
|
|
||||||
current_tile_x += 1;
|
current_tile_x += 1;
|
||||||
current_subtile_x = 0.0;
|
current_subtile_x = 0.0;
|
||||||
}
|
}
|
||||||
|
@ -163,9 +161,10 @@ impl<'o, 'z> Tiler<'o, 'z> {
|
||||||
// Move over to the correct tile, filling in as we go.
|
// Move over to the correct tile, filling in as we go.
|
||||||
while current_tile_x < segment_tile_x {
|
while current_tile_x < segment_tile_x {
|
||||||
//println!("... emitting backdrop {} @ tile {}", current_winding, current_tile_x);
|
//println!("... emitting backdrop {} @ tile {}", current_winding, current_tile_x);
|
||||||
if let Some(tile_index) =
|
let current_tile_coords = Point2DI32::new(current_tile_x, tile_y);
|
||||||
self.built_object.tile_coords_to_index(current_tile_x, tile_y) {
|
if let Some(tile_index) = self.built_object
|
||||||
self.built_object.tile_backdrops[tile_index as usize] = current_winding;
|
.tile_coords_to_index(current_tile_coords) {
|
||||||
|
self.built_object.tile_backdrops.data[tile_index as usize] = current_winding;
|
||||||
}
|
}
|
||||||
|
|
||||||
current_tile_x += 1;
|
current_tile_x += 1;
|
||||||
|
@ -180,13 +179,11 @@ impl<'o, 'z> Tiler<'o, 'z> {
|
||||||
if segment_subtile_x > current_subtile_x {
|
if segment_subtile_x > current_subtile_x {
|
||||||
let current_x =
|
let current_x =
|
||||||
(i32::from(current_tile_x) * TILE_WIDTH as i32) as f32 + current_subtile_x;
|
(i32::from(current_tile_x) * TILE_WIDTH as i32) as f32 + current_subtile_x;
|
||||||
self.built_object.add_active_fill(
|
let current_tile_coords = Point2DI32::new(current_tile_x, tile_y);
|
||||||
current_x,
|
self.built_object.add_active_fill(current_x,
|
||||||
segment_x,
|
segment_x,
|
||||||
current_winding,
|
current_winding,
|
||||||
current_tile_x,
|
current_tile_coords);
|
||||||
tile_y,
|
|
||||||
);
|
|
||||||
current_subtile_x = segment_subtile_x;
|
current_subtile_x = segment_subtile_x;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue