diff --git a/geometry/src/outline.rs b/geometry/src/outline.rs index 0aa5495e..d3c9fa1a 100644 --- a/geometry/src/outline.rs +++ b/geometry/src/outline.rs @@ -422,12 +422,8 @@ impl Contour { fn prepare_for_tiling(&mut self, view_box: RectF32) { // Snap points to the view box bounds. This mops up floating point error from the clipping // process. - let (origin_upper_left, origin_lower_right) = (view_box.origin(), view_box.lower_right()); let (mut last_endpoint_index, mut contour_is_monotonic) = (None, true); for point_index in 0..(self.points.len() as u32) { - let position = &mut self.points[point_index as usize]; - *position = position.clamp(origin_upper_left, origin_lower_right); - if contour_is_monotonic { if self.point_is_endpoint(point_index) { if let Some(last_endpoint_index) = last_endpoint_index { diff --git a/renderer/src/builder.rs b/renderer/src/builder.rs index 97cef66d..3fa7bdcf 100644 --- a/renderer/src/builder.rs +++ b/renderer/src/builder.rs @@ -98,8 +98,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 as i32, - fill.tile_y as i32); + let object_tile_index = + object.tile_coords_to_index(fill.tile_x as i32, fill.tile_y as i32).unwrap(); 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 cbf37b5e..f86c48bb 100644 --- a/renderer/src/gpu_data.rs +++ b/renderer/src/gpu_data.rs @@ -109,27 +109,22 @@ impl BuiltObject { // TODO(pcwalton): SIMD-ify `tile_x` and `tile_y`. fn add_fill(&mut self, segment: &LineSegmentF32, tile_x: i32, tile_y: i32) { //println!("add_fill({:?} ({}, {}))", segment, tile_x, tile_y); + let tile_index = match self.tile_coords_to_index(tile_x, tile_y) { + None => return, + Some(tile_index) => tile_index, + }; - let mut segment = (segment.0 * F32x4::splat(256.0)).to_i32x4(); + 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 shuffle_mask = I32x4::new(0x0c08_0400, 0x0d05_0901, 0, 0).as_u8x16(); - 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); + let tile_upper_left = + F32x4::new(tile_x as f32, tile_y as f32, tile_x as f32, tile_y as f32) * tile_size; - segment = segment - tile_origin; - /* - println!("... before min: {} {} {} {}", - segment[0], segment[1], segment[2], segment[3]); - */ - //segment = Sse41::max_epi32(segment, Sse41::setzero_epi32()); - segment = segment.min(I32x4::splat(0x0fff)); - //println!("... after min: {} {} {} {}", segment[0], segment[1], segment[2], segment[3]); - - let shuffle_mask = I32x4::new(0x0c08_0400, 0x0d05_0901, 0, 0); - segment = segment - .as_u8x16() - .shuffle(shuffle_mask.as_u8x16()) - .as_i32x4(); + 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(); // Unpack whole and fractional pixels. let px = LineSegmentU4((segment[1] | (segment[1] >> 12)) as u16); @@ -142,8 +137,6 @@ impl BuiltObject { return; } - let tile_index = self.tile_coords_to_index(tile_x, tile_y); - //println!("... ... OK, pushing"); self.fills.push(FillObjectPrimitive { @@ -233,18 +226,26 @@ impl BuiltObject { } // FIXME(pcwalton): Use a `Point2DI32` instead? - pub fn tile_coords_to_index(&self, tile_x: i32, tile_y: i32) -> u32 { + pub fn tile_coords_to_index(&self, tile_x: i32, tile_y: i32) -> Option { /*println!("tile_coords_to_index(x={}, y={}, tile_rect={:?})", tile_x, tile_y, self.tile_rect);*/ - (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 + 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) + } } - pub fn get_tile_mut(&mut self, tile_x: i32, tile_y: i32) -> &mut TileObjectPrimitive { + pub fn get_tile_mut(&mut self, tile_x: i32, tile_y: i32) -> Option<&mut TileObjectPrimitive> { let tile_index = self.tile_coords_to_index(tile_x, tile_y); - &mut self.tiles[tile_index as usize] + match tile_index { + None => None, + Some(tile_index) => Some(&mut self.tiles[tile_index as usize]), + } } } diff --git a/renderer/src/tiles.rs b/renderer/src/tiles.rs index f5cd2fb0..39ae0348 100644 --- a/renderer/src/tiles.rs +++ b/renderer/src/tiles.rs @@ -169,16 +169,17 @@ impl<'o, 'z> Tiler<'o, 'z> { // Move over to the correct tile, filling in as we go. while current_tile_x < segment_tile_x { //println!("... emitting backdrop {} @ tile {}", current_winding, current_tile_x); - self.built_object - .get_tile_mut(current_tile_x, tile_y) - .backdrop = current_winding; + if let Some(tile) = self.built_object.get_tile_mut(current_tile_x, tile_y) { + tile.backdrop = current_winding; + } + current_tile_x += 1; current_subtile_x = 0.0; } // Do final subtile fill, if necessary. debug_assert_eq!(current_tile_x, segment_tile_x); - debug_assert!(current_tile_x <= self.built_object.tile_rect.max_x()); + //debug_assert!(current_tile_x <= self.built_object.tile_rect.max_x()); let segment_subtile_x = segment_x - (i32::from(current_tile_x) * TILE_WIDTH as i32) as f32; if segment_subtile_x > current_subtile_x { diff --git a/simd/src/x86.rs b/simd/src/x86.rs index b38b49a6..1c7669de 100644 --- a/simd/src/x86.rs +++ b/simd/src/x86.rs @@ -47,6 +47,11 @@ impl F32x4 { unsafe { F32x4(x86_64::_mm_max_ps(self.0, other.0)) } } + #[inline] + pub fn clamp(self, min: F32x4, max: F32x4) -> F32x4 { + self.max(min).min(max) + } + #[inline] pub fn abs(self) -> F32x4 { unsafe {