Add a SIMD integer rect type
This commit is contained in:
parent
fe410e066f
commit
3d0463999c
|
@ -11,11 +11,10 @@
|
||||||
//! A SIMD-optimized point type.
|
//! A SIMD-optimized point type.
|
||||||
|
|
||||||
use euclid::Point2D;
|
use euclid::Point2D;
|
||||||
use pathfinder_simd::default::F32x4;
|
use pathfinder_simd::default::{F32x4, I32x4};
|
||||||
use std::ops::{Add, AddAssign, Mul, Sub};
|
use std::ops::{Add, AddAssign, Mul, Sub};
|
||||||
|
|
||||||
// 2D points.
|
/// 2D points with 32-bit floating point coordinates.
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Default)]
|
#[derive(Clone, Copy, Debug, Default)]
|
||||||
pub struct Point2DF32(pub F32x4);
|
pub struct Point2DF32(pub F32x4);
|
||||||
|
|
||||||
|
@ -89,6 +88,16 @@ impl Point2DF32 {
|
||||||
pub fn scale(&self, x: f32) -> Point2DF32 {
|
pub fn scale(&self, x: f32) -> Point2DF32 {
|
||||||
Point2DF32(self.0 * F32x4::splat(x))
|
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 {
|
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)]
|
#[derive(Clone, Copy, Debug, PartialEq, Default)]
|
||||||
pub struct Point3DF32(pub F32x4);
|
pub struct Point3DF32(pub F32x4);
|
||||||
|
|
||||||
|
|
|
@ -10,8 +10,8 @@
|
||||||
|
|
||||||
//! 2D axis-aligned rectangles, optimized with SIMD.
|
//! 2D axis-aligned rectangles, optimized with SIMD.
|
||||||
|
|
||||||
use crate::basic::point::Point2DF32;
|
use crate::basic::point::{Point2DF32, Point2DI32};
|
||||||
use pathfinder_simd::default::F32x4;
|
use pathfinder_simd::default::{F32x4, I32x4};
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Default)]
|
#[derive(Clone, Copy, Debug, PartialEq, Default)]
|
||||||
pub struct RectF32(pub F32x4);
|
pub struct RectF32(pub F32x4);
|
||||||
|
@ -115,4 +115,79 @@ impl RectF32 {
|
||||||
pub fn max_y(self) -> f32 {
|
pub fn max_y(self) -> f32 {
|
||||||
self.0[3]
|
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]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,9 +16,11 @@
|
||||||
//! The debug font atlas was generated using: https://evanw.github.io/font-texture-generator/
|
//! 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 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::types::{GLfloat, GLint, GLsizei, GLuint};
|
||||||
use gl;
|
use gl;
|
||||||
|
use pathfinder_geometry::basic::point::Point2DI32;
|
||||||
|
use pathfinder_geometry::basic::rect::RectI32;
|
||||||
use pathfinder_renderer::paint::ColorU;
|
use pathfinder_renderer::paint::ColorU;
|
||||||
use serde_json;
|
use serde_json;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
@ -30,11 +32,11 @@ use std::time::Duration;
|
||||||
const DEBUG_FONT_VERTEX_SIZE: GLint = 8;
|
const DEBUG_FONT_VERTEX_SIZE: GLint = 8;
|
||||||
const DEBUG_SOLID_VERTEX_SIZE: GLint = 4;
|
const DEBUG_SOLID_VERTEX_SIZE: GLint = 4;
|
||||||
|
|
||||||
const WINDOW_WIDTH: i16 = 400;
|
const WINDOW_WIDTH: i32 = 400;
|
||||||
const WINDOW_HEIGHT: i16 = LINE_HEIGHT * 2 + PADDING + 2;
|
const WINDOW_HEIGHT: i32 = LINE_HEIGHT * 2 + PADDING + 2;
|
||||||
const PADDING: i16 = 12;
|
const PADDING: i32 = 12;
|
||||||
const FONT_ASCENT: i16 = 28;
|
const FONT_ASCENT: i32 = 28;
|
||||||
const LINE_HEIGHT: i16 = 42;
|
const LINE_HEIGHT: i32 = 42;
|
||||||
|
|
||||||
static WINDOW_COLOR: ColorU = ColorU { r: 30, g: 30, b: 30, a: 255 - 30 };
|
static WINDOW_COLOR: ColorU = ColorU { r: 30, g: 30, b: 30, a: 255 - 30 };
|
||||||
|
|
||||||
|
@ -57,15 +59,15 @@ pub struct DebugFont {
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
struct DebugCharacter {
|
struct DebugCharacter {
|
||||||
x: u16,
|
x: i32,
|
||||||
y: u16,
|
y: i32,
|
||||||
width: u16,
|
width: i32,
|
||||||
height: u16,
|
height: i32,
|
||||||
#[serde(rename = "originX")]
|
#[serde(rename = "originX")]
|
||||||
origin_x: i16,
|
origin_x: i32,
|
||||||
#[serde(rename = "originY")]
|
#[serde(rename = "originY")]
|
||||||
origin_y: i16,
|
origin_y: i32,
|
||||||
advance: i16,
|
advance: i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DebugFont {
|
impl DebugFont {
|
||||||
|
@ -113,28 +115,28 @@ impl DebugRenderer {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn draw(&self, tile_time: Duration, rendering_time: Option<Duration>) {
|
pub fn draw(&self, tile_time: Duration, rendering_time: Option<Duration>) {
|
||||||
let window_rect =
|
let window_rect = RectI32::new(
|
||||||
Rect::new(Point2D::new(self.framebuffer_size.width as i16 - PADDING - WINDOW_WIDTH,
|
Point2DI32::new(self.framebuffer_size.width as i32 - PADDING - WINDOW_WIDTH,
|
||||||
self.framebuffer_size.height as i16 - PADDING - WINDOW_HEIGHT),
|
self.framebuffer_size.height as i32 - PADDING - WINDOW_HEIGHT),
|
||||||
Size2D::new(WINDOW_WIDTH, WINDOW_HEIGHT));
|
Point2DI32::new(WINDOW_WIDTH, WINDOW_HEIGHT));
|
||||||
self.draw_solid_rect(&window_rect, WINDOW_COLOR);
|
self.draw_solid_rect(window_rect, WINDOW_COLOR);
|
||||||
self.draw_text(&format!("Tiling: {:.3} ms", duration_ms(tile_time)),
|
self.draw_text(&format!("Tiling: {:.3} ms", duration_ms(tile_time)),
|
||||||
&Point2D::new(window_rect.origin.x + PADDING,
|
Point2DI32::new(window_rect.min_x() + PADDING,
|
||||||
window_rect.origin.y + PADDING + FONT_ASCENT));
|
window_rect.min_y() + PADDING + FONT_ASCENT));
|
||||||
if let Some(rendering_time) = rendering_time {
|
if let Some(rendering_time) = rendering_time {
|
||||||
self.draw_text(&format!("Rendering: {:.3} ms", duration_ms(rendering_time)),
|
self.draw_text(&format!("Rendering: {:.3} ms", duration_ms(rendering_time)),
|
||||||
&Point2D::new(
|
Point2DI32::new(
|
||||||
window_rect.origin.x + PADDING,
|
window_rect.min_x() + PADDING,
|
||||||
window_rect.origin.y + PADDING + FONT_ASCENT + LINE_HEIGHT));
|
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 = [
|
let vertex_data = [
|
||||||
DebugSolidVertex::new(rect.origin),
|
DebugSolidVertex::new(rect.origin()),
|
||||||
DebugSolidVertex::new(rect.top_right()),
|
DebugSolidVertex::new(rect.upper_right()),
|
||||||
DebugSolidVertex::new(rect.bottom_right()),
|
DebugSolidVertex::new(rect.lower_right()),
|
||||||
DebugSolidVertex::new(rect.bottom_left()),
|
DebugSolidVertex::new(rect.lower_left()),
|
||||||
];
|
];
|
||||||
self.solid_vertex_array
|
self.solid_vertex_array
|
||||||
.vertex_buffer
|
.vertex_buffer
|
||||||
|
@ -159,8 +161,8 @@ impl DebugRenderer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw_text(&self, string: &str, origin: &Point2D<i16>) {
|
fn draw_text(&self, string: &str, origin: Point2DI32) {
|
||||||
let mut next = *origin;
|
let mut next = origin;
|
||||||
let char_count = string.chars().count();
|
let char_count = string.chars().count();
|
||||||
let mut vertex_data = Vec::with_capacity(char_count * 4);
|
let mut vertex_data = Vec::with_capacity(char_count * 4);
|
||||||
let mut index_data = Vec::with_capacity(char_count * 6);
|
let mut index_data = Vec::with_capacity(char_count * 6);
|
||||||
|
@ -168,21 +170,24 @@ impl DebugRenderer {
|
||||||
if !self.font.characters.contains_key(&character) {
|
if !self.font.characters.contains_key(&character) {
|
||||||
character = '?';
|
character = '?';
|
||||||
}
|
}
|
||||||
|
|
||||||
let info = &self.font.characters[&character];
|
let info = &self.font.characters[&character];
|
||||||
let position_rect =
|
let position_rect =
|
||||||
Rect::new(Point2D::new(next.x - info.origin_x, next.y - info.origin_y),
|
RectI32::new(Point2DI32::new(next.x() - info.origin_x, next.y() - info.origin_y),
|
||||||
Size2D::new(info.width as i16, info.height as i16));
|
Point2DI32::new(info.width as i32, info.height as i32));
|
||||||
let tex_coord_rect = Rect::new(Point2D::new(info.x, info.y),
|
let tex_coord_rect = RectI32::new(Point2DI32::new(info.x, info.y),
|
||||||
Size2D::new(info.width, info.height));
|
Point2DI32::new(info.width, info.height));
|
||||||
let first_vertex_index = vertex_data.len();
|
let first_vertex_index = vertex_data.len();
|
||||||
vertex_data.extend_from_slice(&[
|
vertex_data.extend_from_slice(&[
|
||||||
DebugFontVertex::new(position_rect.origin, tex_coord_rect.origin),
|
DebugFontVertex::new(position_rect.origin(), tex_coord_rect.origin()),
|
||||||
DebugFontVertex::new(position_rect.top_right(), tex_coord_rect.top_right()),
|
DebugFontVertex::new(position_rect.upper_right(), tex_coord_rect.upper_right()),
|
||||||
DebugFontVertex::new(position_rect.bottom_right(), tex_coord_rect.bottom_right()),
|
DebugFontVertex::new(position_rect.lower_right(), tex_coord_rect.lower_right()),
|
||||||
DebugFontVertex::new(position_rect.bottom_left(), tex_coord_rect.bottom_left()),
|
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));
|
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
|
self.font_vertex_array
|
||||||
|
@ -349,12 +354,12 @@ struct DebugFontVertex {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DebugFontVertex {
|
impl DebugFontVertex {
|
||||||
fn new(position: Point2D<i16>, tex_coord: Point2D<u16>) -> DebugFontVertex {
|
fn new(position: Point2DI32, tex_coord: Point2DI32) -> DebugFontVertex {
|
||||||
DebugFontVertex {
|
DebugFontVertex {
|
||||||
position_x: position.x,
|
position_x: position.x() as i16,
|
||||||
position_y: position.y,
|
position_y: position.y() as i16,
|
||||||
tex_coord_x: tex_coord.x,
|
tex_coord_x: tex_coord.x() as u16,
|
||||||
tex_coord_y: tex_coord.y,
|
tex_coord_y: tex_coord.y() as u16,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -367,8 +372,8 @@ struct DebugSolidVertex {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DebugSolidVertex {
|
impl DebugSolidVertex {
|
||||||
fn new(position: Point2D<i16>) -> DebugSolidVertex {
|
fn new(position: Point2DI32) -> DebugSolidVertex {
|
||||||
DebugSolidVertex { position_x: position.x, position_y: position.y }
|
DebugSolidVertex { position_x: position.x() as i16, position_y: position.y() as i16 }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,8 +15,7 @@ use crate::gpu_data::{MaskTileBatchPrimitive, SolidTileScenePrimitive};
|
||||||
use crate::scene;
|
use crate::scene;
|
||||||
use crate::tiles;
|
use crate::tiles;
|
||||||
use crate::z_buffer::ZBuffer;
|
use crate::z_buffer::ZBuffer;
|
||||||
use euclid::Rect;
|
use pathfinder_geometry::basic::rect::{RectF32, RectI32};
|
||||||
use pathfinder_geometry::basic::rect::RectF32;
|
|
||||||
use std::iter;
|
use std::iter;
|
||||||
use std::u16;
|
use std::u16;
|
||||||
|
|
||||||
|
@ -26,25 +25,24 @@ const MAX_MASKS_PER_BATCH: u16 = 0xffff;
|
||||||
pub struct SceneBuilder {
|
pub struct SceneBuilder {
|
||||||
objects: Vec<BuiltObject>,
|
objects: Vec<BuiltObject>,
|
||||||
z_buffer: ZBuffer,
|
z_buffer: ZBuffer,
|
||||||
tile_rect: Rect<i16>,
|
tile_rect: RectI32,
|
||||||
|
|
||||||
current_object_index: usize,
|
current_object_index: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SceneBuilder {
|
impl SceneBuilder {
|
||||||
pub fn new(objects: Vec<BuiltObject>, z_buffer: ZBuffer, view_box: RectF32) -> 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 {
|
SceneBuilder {
|
||||||
objects,
|
objects,
|
||||||
z_buffer,
|
z_buffer,
|
||||||
tile_rect,
|
tile_rect: tiles::round_rect_out_to_tile_bounds(view_box),
|
||||||
current_object_index: 0,
|
current_object_index: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn build_solid_tiles(&self) -> Vec<SolidTileScenePrimitive> {
|
pub fn build_solid_tiles(&self) -> Vec<SolidTileScenePrimitive> {
|
||||||
self.z_buffer
|
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> {
|
pub fn build_batch(&mut self) -> Option<Batch> {
|
||||||
|
@ -70,8 +68,9 @@ impl SceneBuilder {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cull occluded tiles.
|
// Cull occluded tiles.
|
||||||
let scene_tile_index =
|
let scene_tile_index = scene::scene_tile_index(tile.tile_x as i32,
|
||||||
scene::scene_tile_index(tile.tile_x, tile.tile_y, self.tile_rect);
|
tile.tile_y as i32,
|
||||||
|
self.tile_rect);
|
||||||
if !self
|
if !self
|
||||||
.z_buffer
|
.z_buffer
|
||||||
.test(scene_tile_index, self.current_object_index as u32)
|
.test(scene_tile_index, self.current_object_index as u32)
|
||||||
|
@ -95,7 +94,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, 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 =
|
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 {
|
||||||
|
|
|
@ -12,18 +12,17 @@
|
||||||
|
|
||||||
use crate::paint::{ObjectShader, ShaderId};
|
use crate::paint::{ObjectShader, ShaderId};
|
||||||
use crate::tiles::{self, TILE_HEIGHT, TILE_WIDTH};
|
use crate::tiles::{self, TILE_HEIGHT, TILE_WIDTH};
|
||||||
use euclid::Rect;
|
|
||||||
use fixedbitset::FixedBitSet;
|
use fixedbitset::FixedBitSet;
|
||||||
use pathfinder_geometry::basic::line_segment::{LineSegmentF32, LineSegmentU4, LineSegmentU8};
|
use pathfinder_geometry::basic::line_segment::{LineSegmentF32, LineSegmentU4, LineSegmentU8};
|
||||||
use pathfinder_geometry::basic::point::Point2DF32;
|
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_geometry::util;
|
||||||
use pathfinder_simd::default::{F32x4, I32x4};
|
use pathfinder_simd::default::{F32x4, I32x4};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct BuiltObject {
|
pub struct BuiltObject {
|
||||||
pub bounds: RectF32,
|
pub bounds: RectF32,
|
||||||
pub tile_rect: Rect<i16>,
|
pub tile_rect: RectI32,
|
||||||
pub tiles: Vec<TileObjectPrimitive>,
|
pub tiles: Vec<TileObjectPrimitive>,
|
||||||
pub fills: Vec<FillObjectPrimitive>,
|
pub fills: Vec<FillObjectPrimitive>,
|
||||||
pub solid_tiles: FixedBitSet,
|
pub solid_tiles: FixedBitSet,
|
||||||
|
@ -92,11 +91,11 @@ impl BuiltObject {
|
||||||
let tile_rect = tiles::round_rect_out_to_tile_bounds(bounds);
|
let tile_rect = tiles::round_rect_out_to_tile_bounds(bounds);
|
||||||
|
|
||||||
// Allocate tiles.
|
// 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);
|
let mut tiles = Vec::with_capacity(tile_count);
|
||||||
for y in tile_rect.origin.y..tile_rect.max_y() {
|
for y in tile_rect.min_y()..tile_rect.max_y() {
|
||||||
for x in tile_rect.origin.x..tile_rect.max_x() {
|
for x in tile_rect.min_x()..tile_rect.max_x() {
|
||||||
tiles.push(TileObjectPrimitive::new(x, y));
|
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`.
|
// 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);
|
//println!("add_fill({:?} ({}, {}))", segment, tile_x, tile_y);
|
||||||
|
|
||||||
let mut segment = (segment.0 * F32x4::splat(256.0)).to_i32x4();
|
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_x = (TILE_WIDTH as i32) * 256 * tile_x;
|
||||||
let tile_origin_y = (TILE_HEIGHT as i32) * 256 * (tile_y as i32);
|
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_origin = I32x4::new(tile_origin_x, tile_origin_y, tile_origin_x, tile_origin_y);
|
||||||
|
|
||||||
segment = segment - tile_origin;
|
segment = segment - tile_origin;
|
||||||
|
@ -149,8 +148,8 @@ impl BuiltObject {
|
||||||
self.fills.push(FillObjectPrimitive {
|
self.fills.push(FillObjectPrimitive {
|
||||||
px,
|
px,
|
||||||
subpx,
|
subpx,
|
||||||
tile_x,
|
tile_x: tile_x as i16,
|
||||||
tile_y,
|
tile_y: tile_y as i16,
|
||||||
});
|
});
|
||||||
self.solid_tiles.set(tile_index as usize, false);
|
self.solid_tiles.set(tile_index as usize, false);
|
||||||
}
|
}
|
||||||
|
@ -160,8 +159,8 @@ impl BuiltObject {
|
||||||
left: f32,
|
left: f32,
|
||||||
right: f32,
|
right: f32,
|
||||||
mut winding: i16,
|
mut winding: i16,
|
||||||
tile_x: i16,
|
tile_x: i32,
|
||||||
tile_y: i16,
|
tile_y: i32,
|
||||||
) {
|
) {
|
||||||
let tile_origin_y = (i32::from(tile_y) * TILE_HEIGHT as i32) as f32;
|
let tile_origin_y = (i32::from(tile_y) * TILE_HEIGHT as i32) as f32;
|
||||||
let left = Point2DF32::new(left, tile_origin_y);
|
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: i32) {
|
||||||
pub fn generate_fill_primitives_for_line(&mut self, mut segment: LineSegmentF32, tile_y: i16) {
|
|
||||||
/*println!("... generate_fill_primitives_for_line(): segment={:?} tile_y={} ({}-{})",
|
/*println!("... generate_fill_primitives_for_line(): segment={:?} tile_y={} ({}-{})",
|
||||||
segment,
|
segment,
|
||||||
tile_y,
|
tile_y,
|
||||||
|
@ -205,9 +203,10 @@ impl BuiltObject {
|
||||||
(segment.to_x(), segment.from_x())
|
(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 =
|
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={:?}",
|
/*println!("segment_tile_left={} segment_tile_right={} tile_rect={:?}",
|
||||||
segment_tile_left, segment_tile_right, self.tile_rect);*/
|
segment_tile_left, segment_tile_right, self.tile_rect);*/
|
||||||
|
|
||||||
|
@ -232,17 +231,17 @@ impl BuiltObject {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME(pcwalton): Use a `Point2D<i16>` instead?
|
// FIXME(pcwalton): Use a `Point2DI32` instead?
|
||||||
pub fn tile_coords_to_index(&self, tile_x: i16, tile_y: i16) -> u32 {
|
pub fn tile_coords_to_index(&self, tile_x: i32, tile_y: i32) -> 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.origin.y) as u32 * self.tile_rect.size.width as u32
|
(tile_y - self.tile_rect.min_y()) as u32 * self.tile_rect.size().x() as u32
|
||||||
+ (tile_x - self.tile_rect.origin.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);
|
let tile_index = self.tile_coords_to_index(tile_x, tile_y);
|
||||||
&mut self.tiles[tile_index as usize]
|
&mut self.tiles[tile_index as usize]
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,10 +14,9 @@ use crate::gpu_data::BuiltObject;
|
||||||
use crate::paint::{ObjectShader, Paint, PaintId, ShaderId};
|
use crate::paint::{ObjectShader, Paint, PaintId, ShaderId};
|
||||||
use crate::tiles::Tiler;
|
use crate::tiles::Tiler;
|
||||||
use crate::z_buffer::ZBuffer;
|
use crate::z_buffer::ZBuffer;
|
||||||
use euclid::Rect;
|
|
||||||
use hashbrown::HashMap;
|
use hashbrown::HashMap;
|
||||||
use pathfinder_geometry::basic::point::Point2DF32;
|
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::transform2d::Transform2DF32;
|
||||||
use pathfinder_geometry::basic::transform3d::Perspective;
|
use pathfinder_geometry::basic::transform3d::Perspective;
|
||||||
use pathfinder_geometry::clip::PolygonClipper3D;
|
use pathfinder_geometry::clip::PolygonClipper3D;
|
||||||
|
@ -185,10 +184,11 @@ impl PathObject {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO(pcwalton): Use a `Point2DI32` here?
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn scene_tile_index(tile_x: i16, tile_y: i16, tile_rect: Rect<i16>) -> u32 {
|
pub fn scene_tile_index(tile_x: i32, tile_y: i32, tile_rect: RectI32) -> u32 {
|
||||||
(tile_y - tile_rect.origin.y) as u32 * tile_rect.size.width as u32
|
(tile_y - tile_rect.min_y()) as u32 * tile_rect.size().x() as u32
|
||||||
+ (tile_x - tile_rect.origin.x) as u32
|
+ (tile_x - tile_rect.min_x()) as u32
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum BuildTransform {
|
pub enum BuildTransform {
|
||||||
|
|
|
@ -12,13 +12,11 @@ use crate::gpu_data::BuiltObject;
|
||||||
use crate::paint::ShaderId;
|
use crate::paint::ShaderId;
|
||||||
use crate::sorted_vector::SortedVector;
|
use crate::sorted_vector::SortedVector;
|
||||||
use crate::z_buffer::ZBuffer;
|
use crate::z_buffer::ZBuffer;
|
||||||
use euclid::{Point2D, Rect, Size2D};
|
|
||||||
use pathfinder_geometry::basic::line_segment::LineSegmentF32;
|
use pathfinder_geometry::basic::line_segment::LineSegmentF32;
|
||||||
use pathfinder_geometry::basic::point::Point2DF32;
|
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::outline::{Contour, Outline, PointIndex};
|
||||||
use pathfinder_geometry::segment::Segment;
|
use pathfinder_geometry::segment::Segment;
|
||||||
use pathfinder_geometry::util;
|
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
|
||||||
|
@ -73,7 +71,7 @@ impl<'o, 'z> Tiler<'o, 'z> {
|
||||||
|
|
||||||
// Generate strips.
|
// Generate strips.
|
||||||
let tile_rect = self.built_object.tile_rect;
|
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);
|
self.generate_strip(strip_origin_y);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -82,7 +80,7 @@ impl<'o, 'z> Tiler<'o, 'z> {
|
||||||
//println!("{:#?}", self.built_object);
|
//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.
|
// Process old active edges.
|
||||||
self.process_old_active_edges(strip_origin_y);
|
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() {
|
for solid_tile_index in self.built_object.solid_tiles.ones() {
|
||||||
let tile = &self.built_object.tiles[solid_tile_index];
|
let tile = &self.built_object.tiles[solid_tile_index];
|
||||||
if tile.backdrop != 0 {
|
if tile.backdrop != 0 {
|
||||||
self.z_buffer
|
self.z_buffer.update(tile.tile_x as i32, tile.tile_y as i32, self.object_index);
|
||||||
.update(tile.tile_x, tile.tile_y, self.object_index);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn process_old_active_edges(&mut self, tile_y: i16) {
|
fn process_old_active_edges(&mut self, tile_y: i32) {
|
||||||
let mut current_tile_x = self.built_object.tile_rect.origin.x;
|
let mut current_tile_x = self.built_object.tile_rect.min_x();
|
||||||
let mut current_subtile_x = 0.0;
|
let mut current_subtile_x = 0.0;
|
||||||
let mut current_winding = 0;
|
let mut current_winding = 0;
|
||||||
|
|
||||||
|
@ -153,7 +150,7 @@ impl<'o, 'z> Tiler<'o, 'z> {
|
||||||
last_segment_x = segment_x;
|
last_segment_x = segment_x;
|
||||||
|
|
||||||
// Do initial subtile fill, if necessary.
|
// 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 {
|
if current_tile_x < segment_tile_x && current_subtile_x > 0.0 {
|
||||||
let current_x =
|
let current_x =
|
||||||
(i32::from(current_tile_x) * TILE_WIDTH as i32) as f32 + current_subtile_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);
|
//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 outline = &self.outline;
|
||||||
let point_index = self.point_queue.pop().unwrap().point_index;
|
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> {
|
pub fn round_rect_out_to_tile_bounds(rect: RectF32) -> RectI32 {
|
||||||
let tile_origin = Point2D::new((f32::floor(rect.min_x()) as i32 / TILE_WIDTH as i32) as i16,
|
rect.scale_xy(Point2DF32::new(1.0 / TILE_WIDTH as f32, 1.0 / TILE_HEIGHT as f32))
|
||||||
(f32::floor(rect.min_y()) as i32 / TILE_HEIGHT as i32) as i16);
|
.round_out()
|
||||||
let tile_extent = Point2D::new(
|
.to_i32()
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn process_active_segment(
|
fn process_active_segment(
|
||||||
|
@ -318,7 +310,7 @@ fn process_active_segment(
|
||||||
from_endpoint_index: u32,
|
from_endpoint_index: u32,
|
||||||
active_edges: &mut SortedVector<ActiveEdge>,
|
active_edges: &mut SortedVector<ActiveEdge>,
|
||||||
built_object: &mut BuiltObject,
|
built_object: &mut BuiltObject,
|
||||||
tile_y: i16,
|
tile_y: i32,
|
||||||
) {
|
) {
|
||||||
let mut active_edge = ActiveEdge::from_segment(&contour.segment_after(from_endpoint_index));
|
let mut active_edge = ActiveEdge::from_segment(&contour.segment_after(from_endpoint_index));
|
||||||
//println!("... process_active_segment({:#?})", active_edge);
|
//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;
|
//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);
|
//println!("process_active_edge({:#?}, tile_y={}({}))", self, tile_y, tile_bottom);
|
||||||
|
|
||||||
|
@ -453,7 +445,7 @@ impl ActiveEdge {
|
||||||
&mut self,
|
&mut self,
|
||||||
line_segment: &LineSegmentF32,
|
line_segment: &LineSegmentF32,
|
||||||
built_object: &mut BuiltObject,
|
built_object: &mut BuiltObject,
|
||||||
tile_y: i16,
|
tile_y: i32,
|
||||||
) -> Option<LineSegmentF32> {
|
) -> Option<LineSegmentF32> {
|
||||||
let tile_bottom = ((i32::from(tile_y) + 1) * TILE_HEIGHT as i32) as f32;
|
let tile_bottom = ((i32::from(tile_y) + 1) * TILE_HEIGHT as i32) as f32;
|
||||||
/*println!("process_line_segment({:?}, tile_y={}) tile_bottom={}",
|
/*println!("process_line_segment({:?}, tile_y={}) tile_bottom={}",
|
||||||
|
|
|
@ -13,19 +13,18 @@
|
||||||
use crate::gpu_data::{BuiltObject, SolidTileScenePrimitive};
|
use crate::gpu_data::{BuiltObject, SolidTileScenePrimitive};
|
||||||
use crate::scene;
|
use crate::scene;
|
||||||
use crate::tiles;
|
use crate::tiles;
|
||||||
use euclid::Rect;
|
use pathfinder_geometry::basic::rect::{RectF32, RectI32};
|
||||||
use pathfinder_geometry::basic::rect::RectF32;
|
|
||||||
use std::sync::atomic::{AtomicUsize, Ordering as AtomicOrdering};
|
use std::sync::atomic::{AtomicUsize, Ordering as AtomicOrdering};
|
||||||
|
|
||||||
pub struct ZBuffer {
|
pub struct ZBuffer {
|
||||||
buffer: Vec<AtomicUsize>,
|
buffer: Vec<AtomicUsize>,
|
||||||
tile_rect: Rect<i16>,
|
tile_rect: RectI32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ZBuffer {
|
impl ZBuffer {
|
||||||
pub fn new(view_box: RectF32) -> ZBuffer {
|
pub fn new(view_box: RectF32) -> ZBuffer {
|
||||||
let tile_rect = tiles::round_rect_out_to_tile_bounds(view_box);
|
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 {
|
ZBuffer {
|
||||||
buffer: (0..tile_area).map(|_| AtomicUsize::new(0)).collect(),
|
buffer: (0..tile_area).map(|_| AtomicUsize::new(0)).collect(),
|
||||||
tile_rect,
|
tile_rect,
|
||||||
|
@ -37,7 +36,7 @@ impl ZBuffer {
|
||||||
existing_depth < object_index as usize + 1
|
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 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 mut old_depth = self.buffer[scene_tile_index].load(AtomicOrdering::SeqCst);
|
||||||
let new_depth = (object_index + 1) as usize;
|
let new_depth = (object_index + 1) as usize;
|
||||||
|
@ -58,21 +57,21 @@ impl ZBuffer {
|
||||||
pub fn build_solid_tiles(
|
pub fn build_solid_tiles(
|
||||||
&self,
|
&self,
|
||||||
objects: &[BuiltObject],
|
objects: &[BuiltObject],
|
||||||
tile_rect: &Rect<i16>,
|
tile_rect: RectI32,
|
||||||
) -> Vec<SolidTileScenePrimitive> {
|
) -> Vec<SolidTileScenePrimitive> {
|
||||||
let mut solid_tiles = vec![];
|
let mut solid_tiles = vec![];
|
||||||
for scene_tile_y in 0..tile_rect.size.height {
|
for scene_tile_y in 0..tile_rect.size().y() {
|
||||||
for scene_tile_x in 0..tile_rect.size.width {
|
for scene_tile_x in 0..tile_rect.size().x() {
|
||||||
let scene_tile_index =
|
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);
|
let depth = self.buffer[scene_tile_index].load(AtomicOrdering::Relaxed);
|
||||||
if depth == 0 {
|
if depth == 0 {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let object_index = (depth - 1) as usize;
|
let object_index = (depth - 1) as usize;
|
||||||
solid_tiles.push(SolidTileScenePrimitive {
|
solid_tiles.push(SolidTileScenePrimitive {
|
||||||
tile_x: scene_tile_x + tile_rect.origin.x,
|
tile_x: (scene_tile_x + tile_rect.min_x()) as i16,
|
||||||
tile_y: scene_tile_y + tile_rect.origin.y,
|
tile_y: (scene_tile_y + tile_rect.min_y()) as i16,
|
||||||
shader: objects[object_index].shader,
|
shader: objects[object_index].shader,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
// Packed comparisons
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -1534,6 +1544,18 @@ impl I32x4 {
|
||||||
unsafe { I32x4(x86_64::_mm_set1_epi32(x)) }
|
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
|
// Conversions
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -1554,6 +1576,47 @@ impl I32x4 {
|
||||||
pub fn packed_eq(self, other: I32x4) -> U32x4 {
|
pub fn packed_eq(self, other: I32x4) -> U32x4 {
|
||||||
unsafe { U32x4(x86_64::_mm_cmpeq_epi32(self.0, other.0)) }
|
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 {
|
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 {
|
impl Sub<I32x4> for I32x4 {
|
||||||
type Output = I32x4;
|
type Output = I32x4;
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|
Loading…
Reference in New Issue