Add a SIMD integer rect type

This commit is contained in:
Patrick Walton 2019-02-05 10:55:01 -08:00
parent fe410e066f
commit 3d0463999c
9 changed files with 315 additions and 123 deletions

View File

@ -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<Point2DF32> 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);

View File

@ -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]
}
}

View File

@ -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<Duration>) {
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<i16>, 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<i16>) {
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<i16>, tex_coord: Point2D<u16>) -> 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<i16>) -> 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 }
}
}

View File

@ -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<BuiltObject>,
z_buffer: ZBuffer,
tile_rect: Rect<i16>,
tile_rect: RectI32,
current_object_index: usize,
}
impl SceneBuilder {
pub fn new(objects: Vec<BuiltObject>, 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<SolidTileScenePrimitive> {
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<Batch> {
@ -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 {

View File

@ -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<i16>,
pub tile_rect: RectI32,
pub tiles: Vec<TileObjectPrimitive>,
pub fills: Vec<FillObjectPrimitive>,
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<i16>` 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]
}

View File

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

View File

@ -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<i16> {
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<ActiveEdge>,
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<LineSegmentF32> {
let tile_bottom = ((i32::from(tile_y) + 1) * TILE_HEIGHT as i32) as f32;
/*println!("process_line_segment({:?}, tile_y={}) tile_bottom={}",

View File

@ -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<AtomicUsize>,
tile_rect: Rect<i16>,
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<i16>,
tile_rect: RectI32,
) -> Vec<SolidTileScenePrimitive> {
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,
});
}

View File

@ -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<usize> for I32x4 {
@ -1564,6 +1627,21 @@ impl Index<usize> for I32x4 {
}
}
impl IndexMut<usize> 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<I32x4> 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<I32x4> for I32x4 {
type Output = I32x4;
#[inline]