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) {
// 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 {

View File

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

View File

@ -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<u32> {
/*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]),
}
}
}

View File

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

View File

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