Switch to guard-band style clipping to eliminate artefacts

This commit is contained in:
Patrick Walton 2019-02-22 13:15:00 -08:00
parent e10e2e97d4
commit 1e3298fdb7
5 changed files with 38 additions and 35 deletions

View File

@ -422,12 +422,8 @@ impl Contour {
fn prepare_for_tiling(&mut self, view_box: RectF32) { 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 // Snap points to the view box bounds. This mops up floating point error from the clipping
// process. // 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); let (mut last_endpoint_index, mut contour_is_monotonic) = (None, true);
for point_index in 0..(self.points.len() as u32) { 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 contour_is_monotonic {
if self.point_is_endpoint(point_index) { if self.point_is_endpoint(point_index) {
if let Some(last_endpoint_index) = last_endpoint_index { if let Some(last_endpoint_index) = last_endpoint_index {

View File

@ -98,8 +98,8 @@ impl SceneBuilder {
// 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 object_tile_index =
fill.tile_y as i32); object.tile_coords_to_index(fill.tile_x as i32, fill.tile_y as i32).unwrap();
let mask_tile_index = let mask_tile_index =
object_tile_index_to_batch_mask_tile_index[object_tile_index as usize]; object_tile_index_to_batch_mask_tile_index[object_tile_index as usize];
if mask_tile_index < u16::MAX { if mask_tile_index < u16::MAX {

View File

@ -109,27 +109,22 @@ impl BuiltObject {
// TODO(pcwalton): SIMD-ify `tile_x` and `tile_y`. // TODO(pcwalton): SIMD-ify `tile_x` and `tile_y`.
fn add_fill(&mut self, segment: &LineSegmentF32, tile_x: i32, tile_y: i32) { 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) {
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_upper_left =
let tile_origin_y = (TILE_HEIGHT as i32) * 256 * tile_y; F32x4::new(tile_x as f32, tile_y as f32, tile_x as f32, tile_y as f32) * tile_size;
let tile_origin = I32x4::new(tile_origin_x, tile_origin_y, tile_origin_x, tile_origin_y);
segment = segment - tile_origin; let segment = (segment.0 - tile_upper_left) * F32x4::splat(256.0);
/* let segment =
println!("... before min: {} {} {} {}", segment.clamp(min, max).to_i32x4().as_u8x16().shuffle(shuffle_mask).as_i32x4();
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();
// Unpack whole and fractional pixels. // Unpack whole and fractional pixels.
let px = LineSegmentU4((segment[1] | (segment[1] >> 12)) as u16); let px = LineSegmentU4((segment[1] | (segment[1] >> 12)) as u16);
@ -142,8 +137,6 @@ impl BuiltObject {
return; return;
} }
let tile_index = self.tile_coords_to_index(tile_x, tile_y);
//println!("... ... OK, pushing"); //println!("... ... OK, pushing");
self.fills.push(FillObjectPrimitive { self.fills.push(FillObjectPrimitive {
@ -233,18 +226,26 @@ impl BuiltObject {
} }
// FIXME(pcwalton): Use a `Point2DI32` instead? // 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<u32> {
/*println!("tile_coords_to_index(x={}, y={}, tile_rect={:?})", /*println!("tile_coords_to_index(x={}, y={}, tile_rect={:?})",
tile_x, tile_x,
tile_y, tile_y,
self.tile_rect);*/ self.tile_rect);*/
(tile_y - self.tile_rect.min_y()) as u32 * self.tile_rect.size().x() as u32 if tile_x < self.tile_rect.min_x() || tile_x >= self.tile_rect.max_x() ||
+ (tile_x - self.tile_rect.min_x()) as u32 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); 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]),
}
} }
} }

View File

@ -169,16 +169,17 @@ 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);
self.built_object if let Some(tile) = self.built_object.get_tile_mut(current_tile_x, tile_y) {
.get_tile_mut(current_tile_x, tile_y) tile.backdrop = current_winding;
.backdrop = current_winding; }
current_tile_x += 1; current_tile_x += 1;
current_subtile_x = 0.0; current_subtile_x = 0.0;
} }
// Do final subtile fill, if necessary. // Do final subtile fill, if necessary.
debug_assert_eq!(current_tile_x, segment_tile_x); 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 = let segment_subtile_x =
segment_x - (i32::from(current_tile_x) * TILE_WIDTH as i32) as f32; segment_x - (i32::from(current_tile_x) * TILE_WIDTH as i32) as f32;
if segment_subtile_x > current_subtile_x { if segment_subtile_x > current_subtile_x {

View File

@ -47,6 +47,11 @@ impl F32x4 {
unsafe { F32x4(x86_64::_mm_max_ps(self.0, other.0)) } 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] #[inline]
pub fn abs(self) -> F32x4 { pub fn abs(self) -> F32x4 {
unsafe { unsafe {