diff --git a/geometry/src/basic/point.rs b/geometry/src/basic/point.rs index 47b69c63..e7a9985d 100644 --- a/geometry/src/basic/point.rs +++ b/geometry/src/basic/point.rs @@ -11,11 +11,10 @@ //! A SIMD-optimized point type. use euclid::Point2D; -use pathfinder_simd::default::F32x4; +use pathfinder_simd::default::{F32x4, I32x4}; use std::ops::{Add, AddAssign, Mul, Sub}; -// 2D points. - +/// 2D points with 32-bit floating point coordinates. #[derive(Clone, Copy, Debug, Default)] pub struct Point2DF32(pub F32x4); @@ -89,6 +88,16 @@ impl Point2DF32 { pub fn scale(&self, x: f32) -> Point2DF32 { Point2DF32(self.0 * F32x4::splat(x)) } + + #[inline] + pub fn floor(&self) -> Point2DF32 { + Point2DF32(self.0.floor()) + } + + #[inline] + pub fn ceil(&self) -> Point2DF32 { + Point2DF32(self.0.ceil()) + } } impl PartialEq for Point2DF32 { @@ -123,8 +132,43 @@ impl Mul for Point2DF32 { } } -// 3D homogeneous points. +/// 2D points with 32-bit signed integer coordinates. +#[derive(Clone, Copy, Debug, Default)] +pub struct Point2DI32(pub I32x4); +impl Point2DI32 { + #[inline] + pub fn new(x: i32, y: i32) -> Point2DI32 { + Point2DI32(I32x4::new(x, y, 0, 0)) + } + + #[inline] + pub fn splat(value: i32) -> Point2DI32 { + Point2DI32(I32x4::splat(value)) + } + + #[inline] + pub fn x(&self) -> i32 { + self.0[0] + } + + #[inline] + pub fn y(&self) -> i32 { + self.0[1] + } + + #[inline] + pub fn set_x(&mut self, x: i32) { + self.0[0] = x; + } + + #[inline] + pub fn set_y(&mut self, y: i32) { + self.0[1] = y; + } +} + +/// 3D homogeneous points. #[derive(Clone, Copy, Debug, PartialEq, Default)] pub struct Point3DF32(pub F32x4); diff --git a/geometry/src/basic/rect.rs b/geometry/src/basic/rect.rs index d6cc33c4..ecb6a646 100644 --- a/geometry/src/basic/rect.rs +++ b/geometry/src/basic/rect.rs @@ -10,8 +10,8 @@ //! 2D axis-aligned rectangles, optimized with SIMD. -use crate::basic::point::Point2DF32; -use pathfinder_simd::default::F32x4; +use crate::basic::point::{Point2DF32, Point2DI32}; +use pathfinder_simd::default::{F32x4, I32x4}; #[derive(Clone, Copy, Debug, PartialEq, Default)] pub struct RectF32(pub F32x4); @@ -115,4 +115,79 @@ impl RectF32 { pub fn max_y(self) -> f32 { self.0[3] } + + #[inline] + pub fn scale_xy(self, factors: Point2DF32) -> RectF32 { + RectF32(self.0 * factors.0.concat_xy_xy(factors.0)) + } + + #[inline] + pub fn round_out(self) -> RectF32 { + RectF32::from_points(self.origin().floor(), self.lower_right().ceil()) + } + + #[inline] + pub fn to_i32(&self) -> RectI32 { + RectI32(self.0.to_i32x4()) + } +} + +#[derive(Clone, Copy, Debug, PartialEq, Default)] +pub struct RectI32(pub I32x4); + +impl RectI32 { + #[inline] + pub fn new(origin: Point2DI32, size: Point2DI32) -> RectI32 { + RectI32(origin.0.concat_xy_xy(origin.0 + size.0)) + } + + #[inline] + pub fn from_points(origin: Point2DI32, lower_right: Point2DI32) -> RectI32 { + RectI32(origin.0.concat_xy_xy(lower_right.0)) + } + + #[inline] + pub fn origin(&self) -> Point2DI32 { + Point2DI32(self.0) + } + + #[inline] + pub fn size(&self) -> Point2DI32 { + Point2DI32(self.0.zwxy() - self.0.xyxy()) + } + + #[inline] + pub fn upper_right(&self) -> Point2DI32 { + Point2DI32(self.0.zyxw()) + } + + #[inline] + pub fn lower_left(&self) -> Point2DI32 { + Point2DI32(self.0.xwzy()) + } + + #[inline] + pub fn lower_right(&self) -> Point2DI32 { + Point2DI32(self.0.zwxy()) + } + + #[inline] + pub fn min_x(self) -> i32 { + self.0[0] + } + + #[inline] + pub fn min_y(self) -> i32 { + self.0[1] + } + + #[inline] + pub fn max_x(self) -> i32 { + self.0[2] + } + + #[inline] + pub fn max_y(self) -> i32 { + self.0[3] + } } diff --git a/gl/src/debug.rs b/gl/src/debug.rs index a624d224..6c9d8f3a 100644 --- a/gl/src/debug.rs +++ b/gl/src/debug.rs @@ -16,9 +16,11 @@ //! The debug font atlas was generated using: https://evanw.github.io/font-texture-generator/ use crate::device::{Buffer, BufferTarget, BufferUploadMode, Program, Texture, Uniform, VertexAttr}; -use euclid::{Point2D, Rect, Size2D}; +use euclid::Size2D; use gl::types::{GLfloat, GLint, GLsizei, GLuint}; use gl; +use pathfinder_geometry::basic::point::Point2DI32; +use pathfinder_geometry::basic::rect::RectI32; use pathfinder_renderer::paint::ColorU; use serde_json; use std::collections::HashMap; @@ -30,11 +32,11 @@ use std::time::Duration; const DEBUG_FONT_VERTEX_SIZE: GLint = 8; const DEBUG_SOLID_VERTEX_SIZE: GLint = 4; -const WINDOW_WIDTH: i16 = 400; -const WINDOW_HEIGHT: i16 = LINE_HEIGHT * 2 + PADDING + 2; -const PADDING: i16 = 12; -const FONT_ASCENT: i16 = 28; -const LINE_HEIGHT: i16 = 42; +const WINDOW_WIDTH: i32 = 400; +const WINDOW_HEIGHT: i32 = LINE_HEIGHT * 2 + PADDING + 2; +const PADDING: i32 = 12; +const FONT_ASCENT: i32 = 28; +const LINE_HEIGHT: i32 = 42; static WINDOW_COLOR: ColorU = ColorU { r: 30, g: 30, b: 30, a: 255 - 30 }; @@ -57,15 +59,15 @@ pub struct DebugFont { #[derive(Deserialize)] struct DebugCharacter { - x: u16, - y: u16, - width: u16, - height: u16, + x: i32, + y: i32, + width: i32, + height: i32, #[serde(rename = "originX")] - origin_x: i16, + origin_x: i32, #[serde(rename = "originY")] - origin_y: i16, - advance: i16, + origin_y: i32, + advance: i32, } impl DebugFont { @@ -113,28 +115,28 @@ impl DebugRenderer { } pub fn draw(&self, tile_time: Duration, rendering_time: Option) { - let window_rect = - Rect::new(Point2D::new(self.framebuffer_size.width as i16 - PADDING - WINDOW_WIDTH, - self.framebuffer_size.height as i16 - PADDING - WINDOW_HEIGHT), - Size2D::new(WINDOW_WIDTH, WINDOW_HEIGHT)); - self.draw_solid_rect(&window_rect, WINDOW_COLOR); + let window_rect = RectI32::new( + Point2DI32::new(self.framebuffer_size.width as i32 - PADDING - WINDOW_WIDTH, + self.framebuffer_size.height as i32 - PADDING - WINDOW_HEIGHT), + Point2DI32::new(WINDOW_WIDTH, WINDOW_HEIGHT)); + self.draw_solid_rect(window_rect, WINDOW_COLOR); self.draw_text(&format!("Tiling: {:.3} ms", duration_ms(tile_time)), - &Point2D::new(window_rect.origin.x + PADDING, - window_rect.origin.y + PADDING + FONT_ASCENT)); + Point2DI32::new(window_rect.min_x() + PADDING, + window_rect.min_y() + PADDING + FONT_ASCENT)); if let Some(rendering_time) = rendering_time { self.draw_text(&format!("Rendering: {:.3} ms", duration_ms(rendering_time)), - &Point2D::new( - window_rect.origin.x + PADDING, - window_rect.origin.y + PADDING + FONT_ASCENT + LINE_HEIGHT)); + Point2DI32::new( + window_rect.min_x() + PADDING, + window_rect.min_y() + PADDING + FONT_ASCENT + LINE_HEIGHT)); } } - fn draw_solid_rect(&self, rect: &Rect, color: ColorU) { + fn draw_solid_rect(&self, rect: RectI32, color: ColorU) { let vertex_data = [ - DebugSolidVertex::new(rect.origin), - DebugSolidVertex::new(rect.top_right()), - DebugSolidVertex::new(rect.bottom_right()), - DebugSolidVertex::new(rect.bottom_left()), + DebugSolidVertex::new(rect.origin()), + DebugSolidVertex::new(rect.upper_right()), + DebugSolidVertex::new(rect.lower_right()), + DebugSolidVertex::new(rect.lower_left()), ]; self.solid_vertex_array .vertex_buffer @@ -159,8 +161,8 @@ impl DebugRenderer { } } - fn draw_text(&self, string: &str, origin: &Point2D) { - let mut next = *origin; + fn draw_text(&self, string: &str, origin: Point2DI32) { + let mut next = origin; let char_count = string.chars().count(); let mut vertex_data = Vec::with_capacity(char_count * 4); let mut index_data = Vec::with_capacity(char_count * 6); @@ -168,21 +170,24 @@ impl DebugRenderer { if !self.font.characters.contains_key(&character) { character = '?'; } + let info = &self.font.characters[&character]; let position_rect = - Rect::new(Point2D::new(next.x - info.origin_x, next.y - info.origin_y), - Size2D::new(info.width as i16, info.height as i16)); - let tex_coord_rect = Rect::new(Point2D::new(info.x, info.y), - Size2D::new(info.width, info.height)); + RectI32::new(Point2DI32::new(next.x() - info.origin_x, next.y() - info.origin_y), + Point2DI32::new(info.width as i32, info.height as i32)); + let tex_coord_rect = RectI32::new(Point2DI32::new(info.x, info.y), + Point2DI32::new(info.width, info.height)); let first_vertex_index = vertex_data.len(); vertex_data.extend_from_slice(&[ - DebugFontVertex::new(position_rect.origin, tex_coord_rect.origin), - DebugFontVertex::new(position_rect.top_right(), tex_coord_rect.top_right()), - DebugFontVertex::new(position_rect.bottom_right(), tex_coord_rect.bottom_right()), - DebugFontVertex::new(position_rect.bottom_left(), tex_coord_rect.bottom_left()), + DebugFontVertex::new(position_rect.origin(), tex_coord_rect.origin()), + DebugFontVertex::new(position_rect.upper_right(), tex_coord_rect.upper_right()), + DebugFontVertex::new(position_rect.lower_right(), tex_coord_rect.lower_right()), + DebugFontVertex::new(position_rect.lower_left(), tex_coord_rect.lower_left()), ]); index_data.extend(QUAD_INDICES.iter().map(|&i| i + first_vertex_index as u32)); - next.x += info.advance; + + let next_x = next.x() + info.advance; + next.set_x(next_x); } self.font_vertex_array @@ -349,12 +354,12 @@ struct DebugFontVertex { } impl DebugFontVertex { - fn new(position: Point2D, tex_coord: Point2D) -> DebugFontVertex { + fn new(position: Point2DI32, tex_coord: Point2DI32) -> DebugFontVertex { DebugFontVertex { - position_x: position.x, - position_y: position.y, - tex_coord_x: tex_coord.x, - tex_coord_y: tex_coord.y, + position_x: position.x() as i16, + position_y: position.y() as i16, + tex_coord_x: tex_coord.x() as u16, + tex_coord_y: tex_coord.y() as u16, } } } @@ -367,8 +372,8 @@ struct DebugSolidVertex { } impl DebugSolidVertex { - fn new(position: Point2D) -> DebugSolidVertex { - DebugSolidVertex { position_x: position.x, position_y: position.y } + fn new(position: Point2DI32) -> DebugSolidVertex { + DebugSolidVertex { position_x: position.x() as i16, position_y: position.y() as i16 } } } diff --git a/renderer/src/builder.rs b/renderer/src/builder.rs index a1e5dbef..5ec9f2d8 100644 --- a/renderer/src/builder.rs +++ b/renderer/src/builder.rs @@ -15,8 +15,7 @@ use crate::gpu_data::{MaskTileBatchPrimitive, SolidTileScenePrimitive}; use crate::scene; use crate::tiles; use crate::z_buffer::ZBuffer; -use euclid::Rect; -use pathfinder_geometry::basic::rect::RectF32; +use pathfinder_geometry::basic::rect::{RectF32, RectI32}; use std::iter; use std::u16; @@ -26,25 +25,24 @@ const MAX_MASKS_PER_BATCH: u16 = 0xffff; pub struct SceneBuilder { objects: Vec, z_buffer: ZBuffer, - tile_rect: Rect, + tile_rect: RectI32, current_object_index: usize, } impl SceneBuilder { pub fn new(objects: Vec, z_buffer: ZBuffer, view_box: RectF32) -> SceneBuilder { - let tile_rect = tiles::round_rect_out_to_tile_bounds(view_box); SceneBuilder { objects, z_buffer, - tile_rect, + tile_rect: tiles::round_rect_out_to_tile_bounds(view_box), current_object_index: 0, } } pub fn build_solid_tiles(&self) -> Vec { self.z_buffer - .build_solid_tiles(&self.objects, &self.tile_rect) + .build_solid_tiles(&self.objects, self.tile_rect) } pub fn build_batch(&mut self) -> Option { @@ -70,8 +68,9 @@ impl SceneBuilder { } // Cull occluded tiles. - let scene_tile_index = - scene::scene_tile_index(tile.tile_x, tile.tile_y, self.tile_rect); + let scene_tile_index = scene::scene_tile_index(tile.tile_x as i32, + tile.tile_y as i32, + self.tile_rect); if !self .z_buffer .test(scene_tile_index, self.current_object_index as u32) @@ -95,7 +94,8 @@ impl SceneBuilder { // Remap and copy fills, culling as necessary. for fill in &object.fills { - let object_tile_index = object.tile_coords_to_index(fill.tile_x, fill.tile_y); + let object_tile_index = object.tile_coords_to_index(fill.tile_x as i32, + fill.tile_y as i32); let mask_tile_index = object_tile_index_to_batch_mask_tile_index[object_tile_index as usize]; if mask_tile_index < u16::MAX { diff --git a/renderer/src/gpu_data.rs b/renderer/src/gpu_data.rs index 0becfcb6..9eea07f9 100644 --- a/renderer/src/gpu_data.rs +++ b/renderer/src/gpu_data.rs @@ -12,18 +12,17 @@ use crate::paint::{ObjectShader, ShaderId}; use crate::tiles::{self, TILE_HEIGHT, TILE_WIDTH}; -use euclid::Rect; use fixedbitset::FixedBitSet; use pathfinder_geometry::basic::line_segment::{LineSegmentF32, LineSegmentU4, LineSegmentU8}; use pathfinder_geometry::basic::point::Point2DF32; -use pathfinder_geometry::basic::rect::RectF32; +use pathfinder_geometry::basic::rect::{RectF32, RectI32}; use pathfinder_geometry::util; use pathfinder_simd::default::{F32x4, I32x4}; #[derive(Debug)] pub struct BuiltObject { pub bounds: RectF32, - pub tile_rect: Rect, + pub tile_rect: RectI32, pub tiles: Vec, pub fills: Vec, pub solid_tiles: FixedBitSet, @@ -92,11 +91,11 @@ impl BuiltObject { let tile_rect = tiles::round_rect_out_to_tile_bounds(bounds); // Allocate tiles. - let tile_count = tile_rect.size.width as usize * tile_rect.size.height as usize; + let tile_count = tile_rect.size().x() as usize * tile_rect.size().y() as usize; let mut tiles = Vec::with_capacity(tile_count); - for y in tile_rect.origin.y..tile_rect.max_y() { - for x in tile_rect.origin.x..tile_rect.max_x() { - tiles.push(TileObjectPrimitive::new(x, y)); + for y in tile_rect.min_y()..tile_rect.max_y() { + for x in tile_rect.min_x()..tile_rect.max_x() { + tiles.push(TileObjectPrimitive::new(x as i16, y as i16)); } } @@ -107,13 +106,13 @@ impl BuiltObject { } // TODO(pcwalton): SIMD-ify `tile_x` and `tile_y`. - fn add_fill(&mut self, segment: &LineSegmentF32, tile_x: i16, tile_y: i16) { + fn add_fill(&mut self, segment: &LineSegmentF32, tile_x: i32, tile_y: i32) { //println!("add_fill({:?} ({}, {}))", segment, tile_x, tile_y); let mut segment = (segment.0 * F32x4::splat(256.0)).to_i32x4(); - let tile_origin_x = (TILE_WIDTH as i32) * 256 * (tile_x as i32); - let tile_origin_y = (TILE_HEIGHT as i32) * 256 * (tile_y as i32); + let tile_origin_x = (TILE_WIDTH as i32) * 256 * tile_x; + let tile_origin_y = (TILE_HEIGHT as i32) * 256 * tile_y; let tile_origin = I32x4::new(tile_origin_x, tile_origin_y, tile_origin_x, tile_origin_y); segment = segment - tile_origin; @@ -149,8 +148,8 @@ impl BuiltObject { self.fills.push(FillObjectPrimitive { px, subpx, - tile_x, - tile_y, + tile_x: tile_x as i16, + tile_y: tile_y as i16, }); self.solid_tiles.set(tile_index as usize, false); } @@ -160,8 +159,8 @@ impl BuiltObject { left: f32, right: f32, mut winding: i16, - tile_x: i16, - tile_y: i16, + tile_x: i32, + tile_y: i32, ) { let tile_origin_y = (i32::from(tile_y) * TILE_HEIGHT as i32) as f32; let left = Point2DF32::new(left, tile_origin_y); @@ -190,8 +189,7 @@ impl BuiltObject { } } - // TODO(pcwalton): Optimize this better with SIMD! - pub fn generate_fill_primitives_for_line(&mut self, mut segment: LineSegmentF32, tile_y: i16) { + pub fn generate_fill_primitives_for_line(&mut self, mut segment: LineSegmentF32, tile_y: i32) { /*println!("... generate_fill_primitives_for_line(): segment={:?} tile_y={} ({}-{})", segment, tile_y, @@ -205,9 +203,10 @@ impl BuiltObject { (segment.to_x(), segment.from_x()) }; - let segment_tile_left = (f32::floor(segment_left) as i32 / TILE_WIDTH as i32) as i16; + // FIXME(pcwalton): Optimize this. + 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) as i16; + util::alignup_i32(f32::ceil(segment_right) as i32, TILE_WIDTH as i32); /*println!("segment_tile_left={} segment_tile_right={} tile_rect={:?}", segment_tile_left, segment_tile_right, self.tile_rect);*/ @@ -232,17 +231,17 @@ impl BuiltObject { } } - // FIXME(pcwalton): Use a `Point2D` instead? - pub fn tile_coords_to_index(&self, tile_x: i16, tile_y: i16) -> u32 { + // FIXME(pcwalton): Use a `Point2DI32` instead? + pub fn tile_coords_to_index(&self, tile_x: i32, tile_y: i32) -> u32 { /*println!("tile_coords_to_index(x={}, y={}, tile_rect={:?})", tile_x, tile_y, self.tile_rect);*/ - (tile_y - self.tile_rect.origin.y) as u32 * self.tile_rect.size.width as u32 - + (tile_x - self.tile_rect.origin.x) as u32 + (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 } - pub fn get_tile_mut(&mut self, tile_x: i16, tile_y: i16) -> &mut TileObjectPrimitive { + pub fn get_tile_mut(&mut self, tile_x: i32, tile_y: i32) -> &mut TileObjectPrimitive { let tile_index = self.tile_coords_to_index(tile_x, tile_y); &mut self.tiles[tile_index as usize] } diff --git a/renderer/src/scene.rs b/renderer/src/scene.rs index d6c7c52f..ba1996df 100644 --- a/renderer/src/scene.rs +++ b/renderer/src/scene.rs @@ -14,10 +14,9 @@ use crate::gpu_data::BuiltObject; use crate::paint::{ObjectShader, Paint, PaintId, ShaderId}; use crate::tiles::Tiler; use crate::z_buffer::ZBuffer; -use euclid::Rect; use hashbrown::HashMap; use pathfinder_geometry::basic::point::Point2DF32; -use pathfinder_geometry::basic::rect::RectF32; +use pathfinder_geometry::basic::rect::{RectF32, RectI32}; use pathfinder_geometry::basic::transform2d::Transform2DF32; use pathfinder_geometry::basic::transform3d::Perspective; use pathfinder_geometry::clip::PolygonClipper3D; @@ -185,10 +184,11 @@ impl PathObject { } } +// TODO(pcwalton): Use a `Point2DI32` here? #[inline] -pub fn scene_tile_index(tile_x: i16, tile_y: i16, tile_rect: Rect) -> u32 { - (tile_y - tile_rect.origin.y) as u32 * tile_rect.size.width as u32 - + (tile_x - tile_rect.origin.x) as u32 +pub fn scene_tile_index(tile_x: i32, tile_y: i32, tile_rect: RectI32) -> u32 { + (tile_y - tile_rect.min_y()) as u32 * tile_rect.size().x() as u32 + + (tile_x - tile_rect.min_x()) as u32 } pub enum BuildTransform { diff --git a/renderer/src/tiles.rs b/renderer/src/tiles.rs index a48ce5f9..f5cd2fb0 100644 --- a/renderer/src/tiles.rs +++ b/renderer/src/tiles.rs @@ -12,13 +12,11 @@ use crate::gpu_data::BuiltObject; use crate::paint::ShaderId; use crate::sorted_vector::SortedVector; use crate::z_buffer::ZBuffer; -use euclid::{Point2D, Rect, Size2D}; use pathfinder_geometry::basic::line_segment::LineSegmentF32; use pathfinder_geometry::basic::point::Point2DF32; -use pathfinder_geometry::basic::rect::RectF32; +use pathfinder_geometry::basic::rect::{RectF32, RectI32}; use pathfinder_geometry::outline::{Contour, Outline, PointIndex}; use pathfinder_geometry::segment::Segment; -use pathfinder_geometry::util; use std::cmp::Ordering; use std::mem; @@ -73,7 +71,7 @@ impl<'o, 'z> Tiler<'o, 'z> { // Generate strips. let tile_rect = self.built_object.tile_rect; - for strip_origin_y in tile_rect.origin.y..tile_rect.max_y() { + for strip_origin_y in tile_rect.min_y()..tile_rect.max_y() { self.generate_strip(strip_origin_y); } @@ -82,7 +80,7 @@ impl<'o, 'z> Tiler<'o, 'z> { //println!("{:#?}", self.built_object); } - fn generate_strip(&mut self, strip_origin_y: i16) { + fn generate_strip(&mut self, strip_origin_y: i32) { // Process old active edges. self.process_old_active_edges(strip_origin_y); @@ -105,14 +103,13 @@ impl<'o, 'z> Tiler<'o, 'z> { for solid_tile_index in self.built_object.solid_tiles.ones() { let tile = &self.built_object.tiles[solid_tile_index]; if tile.backdrop != 0 { - self.z_buffer - .update(tile.tile_x, tile.tile_y, self.object_index); + self.z_buffer.update(tile.tile_x as i32, tile.tile_y as i32, self.object_index); } } } - fn process_old_active_edges(&mut self, tile_y: i16) { - let mut current_tile_x = self.built_object.tile_rect.origin.x; + 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_subtile_x = 0.0; let mut current_winding = 0; @@ -153,7 +150,7 @@ impl<'o, 'z> Tiler<'o, 'z> { last_segment_x = segment_x; // Do initial subtile fill, if necessary. - let segment_tile_x = (f32::floor(segment_x) as i32 / TILE_WIDTH as i32) as i16; + let segment_tile_x = f32::floor(segment_x) as i32 / TILE_WIDTH as i32; if current_tile_x < segment_tile_x && current_subtile_x > 0.0 { let current_x = (i32::from(current_tile_x) * TILE_WIDTH as i32) as f32 + current_subtile_x; @@ -212,7 +209,7 @@ impl<'o, 'z> Tiler<'o, 'z> { //debug_assert_eq!(current_winding, 0); } - fn add_new_active_edge(&mut self, tile_y: i16) { + fn add_new_active_edge(&mut self, tile_y: i32) { let outline = &self.outline; let point_index = self.point_queue.pop().unwrap().point_index; @@ -302,15 +299,10 @@ impl<'o, 'z> Tiler<'o, 'z> { } } -pub fn round_rect_out_to_tile_bounds(rect: RectF32) -> Rect { - let tile_origin = Point2D::new((f32::floor(rect.min_x()) as i32 / TILE_WIDTH as i32) as i16, - (f32::floor(rect.min_y()) as i32 / TILE_HEIGHT as i32) as i16); - let tile_extent = Point2D::new( - util::alignup_i32(f32::ceil(rect.max_x()) as i32, TILE_WIDTH as i32) as i16, - util::alignup_i32(f32::ceil(rect.max_y()) as i32, TILE_HEIGHT as i32) as i16, - ); - let tile_size = Size2D::new(tile_extent.x - tile_origin.x, tile_extent.y - tile_origin.y); - Rect::new(tile_origin, tile_size) +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)) + .round_out() + .to_i32() } fn process_active_segment( @@ -318,7 +310,7 @@ fn process_active_segment( from_endpoint_index: u32, active_edges: &mut SortedVector, built_object: &mut BuiltObject, - tile_y: i16, + tile_y: i32, ) { let mut active_edge = ActiveEdge::from_segment(&contour.segment_after(from_endpoint_index)); //println!("... process_active_segment({:#?})", active_edge); @@ -372,7 +364,7 @@ impl ActiveEdge { } } - fn process(&mut self, built_object: &mut BuiltObject, tile_y: i16) { + fn process(&mut self, built_object: &mut BuiltObject, tile_y: i32) { //let tile_bottom = ((i32::from(tile_y) + 1) * TILE_HEIGHT as i32) as f32; //println!("process_active_edge({:#?}, tile_y={}({}))", self, tile_y, tile_bottom); @@ -453,7 +445,7 @@ impl ActiveEdge { &mut self, line_segment: &LineSegmentF32, built_object: &mut BuiltObject, - tile_y: i16, + tile_y: i32, ) -> Option { let tile_bottom = ((i32::from(tile_y) + 1) * TILE_HEIGHT as i32) as f32; /*println!("process_line_segment({:?}, tile_y={}) tile_bottom={}", diff --git a/renderer/src/z_buffer.rs b/renderer/src/z_buffer.rs index 5fbee1c5..e398a3ff 100644 --- a/renderer/src/z_buffer.rs +++ b/renderer/src/z_buffer.rs @@ -13,19 +13,18 @@ use crate::gpu_data::{BuiltObject, SolidTileScenePrimitive}; use crate::scene; use crate::tiles; -use euclid::Rect; -use pathfinder_geometry::basic::rect::RectF32; +use pathfinder_geometry::basic::rect::{RectF32, RectI32}; use std::sync::atomic::{AtomicUsize, Ordering as AtomicOrdering}; pub struct ZBuffer { buffer: Vec, - tile_rect: Rect, + tile_rect: RectI32, } impl ZBuffer { pub fn new(view_box: RectF32) -> ZBuffer { let tile_rect = tiles::round_rect_out_to_tile_bounds(view_box); - let tile_area = tile_rect.size.width as usize * tile_rect.size.height as usize; + let tile_area = tile_rect.size().x() as usize * tile_rect.size().y() as usize; ZBuffer { buffer: (0..tile_area).map(|_| AtomicUsize::new(0)).collect(), tile_rect, @@ -37,7 +36,7 @@ impl ZBuffer { existing_depth < object_index as usize + 1 } - pub fn update(&self, tile_x: i16, tile_y: i16, object_index: u16) { + pub fn update(&self, tile_x: i32, tile_y: i32, object_index: u16) { let scene_tile_index = scene::scene_tile_index(tile_x, tile_y, self.tile_rect) as usize; let mut old_depth = self.buffer[scene_tile_index].load(AtomicOrdering::SeqCst); let new_depth = (object_index + 1) as usize; @@ -58,21 +57,21 @@ impl ZBuffer { pub fn build_solid_tiles( &self, objects: &[BuiltObject], - tile_rect: &Rect, + tile_rect: RectI32, ) -> Vec { let mut solid_tiles = vec![]; - for scene_tile_y in 0..tile_rect.size.height { - for scene_tile_x in 0..tile_rect.size.width { + for scene_tile_y in 0..tile_rect.size().y() { + for scene_tile_x in 0..tile_rect.size().x() { let scene_tile_index = - scene_tile_y as usize * tile_rect.size.width as usize + scene_tile_x as usize; + scene_tile_y as usize * tile_rect.size().x() as usize + scene_tile_x as usize; let depth = self.buffer[scene_tile_index].load(AtomicOrdering::Relaxed); if depth == 0 { continue; } let object_index = (depth - 1) as usize; solid_tiles.push(SolidTileScenePrimitive { - tile_x: scene_tile_x + tile_rect.origin.x, - tile_y: scene_tile_y + tile_rect.origin.y, + tile_x: (scene_tile_x + tile_rect.min_x()) as i16, + tile_y: (scene_tile_y + tile_rect.min_y()) as i16, shader: objects[object_index].shader, }); } diff --git a/simd/src/x86.rs b/simd/src/x86.rs index a2f60225..653bc5a5 100644 --- a/simd/src/x86.rs +++ b/simd/src/x86.rs @@ -55,6 +55,16 @@ impl F32x4 { } } + #[inline] + pub fn floor(self) -> F32x4 { + unsafe { F32x4(x86_64::_mm_floor_ps(self.0)) } + } + + #[inline] + pub fn ceil(self) -> F32x4 { + unsafe { F32x4(x86_64::_mm_ceil_ps(self.0)) } + } + // Packed comparisons #[inline] @@ -1534,6 +1544,18 @@ impl I32x4 { unsafe { I32x4(x86_64::_mm_set1_epi32(x)) } } + // Concatenations + + #[inline] + pub fn concat_xy_xy(self, other: I32x4) -> I32x4 { + unsafe { + let this = x86_64::_mm_castsi128_pd(self.0); + let other = x86_64::_mm_castsi128_pd(other.0); + let result = x86_64::_mm_unpacklo_pd(this, other); + I32x4(x86_64::_mm_castpd_si128(result)) + } + } + // Conversions #[inline] @@ -1554,6 +1576,47 @@ impl I32x4 { pub fn packed_eq(self, other: I32x4) -> U32x4 { unsafe { U32x4(x86_64::_mm_cmpeq_epi32(self.0, other.0)) } } + + // Swizzles + + #[inline] + pub fn xyxy(self) -> I32x4 { + unsafe { + let this = x86_64::_mm_castsi128_ps(self.0); + I32x4(x86_64::_mm_castps_si128(x86_64::_mm_shuffle_ps(this, this, 68))) + } + } + + #[inline] + pub fn xwzy(self) -> I32x4 { + unsafe { + let this = x86_64::_mm_castsi128_ps(self.0); + I32x4(x86_64::_mm_castps_si128(x86_64::_mm_shuffle_ps(this, this, 108))) + } + } + + #[inline] + pub fn zyxw(self) -> I32x4 { + unsafe { + let this = x86_64::_mm_castsi128_ps(self.0); + I32x4(x86_64::_mm_castps_si128(x86_64::_mm_shuffle_ps(this, this, 198))) + } + } + + #[inline] + pub fn zwxy(self) -> I32x4 { + unsafe { + let this = x86_64::_mm_castsi128_ps(self.0); + I32x4(x86_64::_mm_castps_si128(x86_64::_mm_shuffle_ps(this, this, 78))) + } + } +} + +impl Default for I32x4 { + #[inline] + fn default() -> I32x4 { + unsafe { I32x4(x86_64::_mm_setzero_si128()) } + } } impl Index for I32x4 { @@ -1564,6 +1627,21 @@ impl Index for I32x4 { } } +impl IndexMut for I32x4 { + #[inline] + fn index_mut(&mut self, index: usize) -> &mut i32 { + unsafe { &mut mem::transmute::<&mut __m128i, &mut [i32; 4]>(&mut self.0)[index] } + } +} + +impl Add for I32x4 { + type Output = I32x4; + #[inline] + fn add(self, other: I32x4) -> I32x4 { + unsafe { I32x4(x86_64::_mm_add_epi32(self.0, other.0)) } + } +} + impl Sub for I32x4 { type Output = I32x4; #[inline]