Implement basic linear gradients.

This is not a very efficient implementation yet, but it seems to work.
This commit is contained in:
Patrick Walton 2020-02-07 11:46:20 -08:00
parent 740597d886
commit 5a21557a6d
28 changed files with 495 additions and 386 deletions

21
Cargo.lock generated
View File

@ -362,20 +362,6 @@ dependencies = [
"objc 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", "objc 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]]
name = "cocoa"
version = "0.20.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"block 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"core-foundation 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"core-graphics 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)",
"foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
"objc 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]] [[package]]
name = "color-backtrace" name = "color-backtrace"
version = "0.3.0" version = "0.3.0"
@ -615,7 +601,7 @@ name = "demo"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"color-backtrace 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "color-backtrace 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"foreign-types 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"gl 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", "gl 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)",
"jemallocator 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "jemallocator 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"metal 0.17.1 (registry+https://github.com/rust-lang/crates.io-index)", "metal 0.17.1 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1731,9 +1717,9 @@ dependencies = [
"bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"block 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "block 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"cocoa 0.20.0 (registry+https://github.com/rust-lang/crates.io-index)", "cocoa 0.19.1 (registry+https://github.com/rust-lang/crates.io-index)",
"core-foundation 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "core-foundation 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"foreign-types 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"half 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "half 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"metal 0.17.1 (registry+https://github.com/rust-lang/crates.io-index)", "metal 0.17.1 (registry+https://github.com/rust-lang/crates.io-index)",
"objc 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", "objc 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
@ -2739,7 +2725,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" "checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f"
"checksum cmake 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "81fb25b677f8bf1eb325017cb6bb8452f87969db0fedb4f757b297bee78a7c62" "checksum cmake 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "81fb25b677f8bf1eb325017cb6bb8452f87969db0fedb4f757b297bee78a7c62"
"checksum cocoa 0.19.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f29f7768b2d1be17b96158e3285951d366b40211320fb30826a76cb7a0da6400" "checksum cocoa 0.19.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f29f7768b2d1be17b96158e3285951d366b40211320fb30826a76cb7a0da6400"
"checksum cocoa 0.20.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0a4736c86d51bd878b474400d9ec888156f4037015f5d09794fab9f26eab1ad4"
"checksum color-backtrace 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "65d13f1078cc63c791d0deba0dd43db37c9ec02b311f10bed10b577016f3a957" "checksum color-backtrace 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "65d13f1078cc63c791d0deba0dd43db37c9ec02b311f10bed10b577016f3a957"
"checksum color_quant 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0dbbb57365263e881e805dc77d94697c9118fd94d8da011240555aa7b23445bd" "checksum color_quant 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0dbbb57365263e881e805dc77d94697c9118fd94d8da011240555aa7b23445bd"
"checksum combine 3.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "da3da6baa321ec19e1cc41d31bf599f00c783d0517095cdaf0332e3fe8d20680" "checksum combine 3.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "da3da6baa321ec19e1cc41d31bf599f00c783d0517095cdaf0332e3fe8d20680"

View File

@ -28,6 +28,7 @@ use std::f32::consts::PI;
use std::mem; use std::mem;
use std::sync::Arc; use std::sync::Arc;
use text::FontCollection; use text::FontCollection;
#[cfg(feature = "pf-text")] #[cfg(feature = "pf-text")]
pub use text::TextMetrics; pub use text::TextMetrics;
pub use text::CanvasFontContext; pub use text::CanvasFontContext;

View File

@ -21,6 +21,11 @@ pub struct ColorU {
} }
impl ColorU { impl ColorU {
#[inline]
pub fn new(r: u8, g: u8, b: u8, a: u8) -> ColorU {
ColorU { r, g, b, a }
}
#[inline] #[inline]
pub fn transparent_black() -> ColorU { pub fn transparent_black() -> ColorU {
ColorU::from_u32(0) ColorU::from_u32(0)

View File

@ -12,7 +12,7 @@ use crate::sorted_vector::SortedVector;
use pathfinder_color::ColorU; use pathfinder_color::ColorU;
use pathfinder_geometry::line_segment::LineSegment2F; use pathfinder_geometry::line_segment::LineSegment2F;
use pathfinder_simd::default::F32x4; use pathfinder_simd::default::F32x4;
use std::cmp::{self, Ordering, PartialOrd}; use std::cmp::{Ordering, PartialOrd};
use std::convert; use std::convert;
use std::hash::{Hash, Hasher}; use std::hash::{Hash, Hasher};
use std::mem; use std::mem;
@ -25,8 +25,8 @@ pub struct Gradient {
#[derive(Clone, Copy, PartialEq, PartialOrd, Debug)] #[derive(Clone, Copy, PartialEq, PartialOrd, Debug)]
pub struct ColorStop { pub struct ColorStop {
pub color: ColorU,
pub offset: f32, pub offset: f32,
pub color: ColorU,
} }
impl Eq for Gradient {} impl Eq for Gradient {}
@ -79,10 +79,11 @@ impl Gradient {
return ColorU::transparent_black(); return ColorU::transparent_black();
} }
let lower_index = self.stops.binary_search_by(|stop| { let last_index = self.stops.len() - 1;
let upper_index = self.stops.binary_search_by(|stop| {
stop.offset.partial_cmp(&t).unwrap_or(Ordering::Less) stop.offset.partial_cmp(&t).unwrap_or(Ordering::Less)
}).unwrap_or_else(convert::identity); }).unwrap_or_else(convert::identity).min(last_index);
let upper_index = cmp::min(lower_index + 1, self.stops.len() - 1); let lower_index = if upper_index > 0 { upper_index - 1 } else { upper_index };
let lower_stop = &self.stops.array[lower_index]; let lower_stop = &self.stops.array[lower_index];
let upper_stop = &self.stops.array[upper_index]; let upper_stop = &self.stops.array[upper_index];
@ -104,3 +105,10 @@ impl Gradient {
} }
} }
} }
impl ColorStop {
#[inline]
pub fn new(color: ColorU, offset: f32) -> ColorStop {
ColorStop { color, offset }
}
}

View File

@ -32,7 +32,7 @@ path = "../../gpu"
path = "../../simd" path = "../../simd"
[target.'cfg(target_os = "macos")'.dependencies] [target.'cfg(target_os = "macos")'.dependencies]
foreign-types = "0.5" foreign-types = "0.3"
metal = "0.17" metal = "0.17"
[target.'cfg(target_os = "macos")'.dependencies.pathfinder_metal] [target.'cfg(target_os = "macos")'.dependencies.pathfinder_metal]

View File

@ -181,6 +181,11 @@ impl RectF {
RectF::from_points(self.origin() - amount, self.lower_right() + amount) RectF::from_points(self.origin() - amount, self.lower_right() + amount)
} }
#[inline]
pub fn contract(self, amount: Vector2F) -> RectF {
RectF::from_points(self.origin() + amount, self.lower_right() - amount)
}
#[inline] #[inline]
pub fn to_i32(&self) -> RectI { pub fn to_i32(&self) -> RectI {
RectI(self.0.to_i32x4()) RectI(self.0.to_i32x4())
@ -308,6 +313,11 @@ impl RectI {
.all_true() .all_true()
} }
#[inline]
pub fn contract(self, amount: Vector2I) -> RectI {
RectI::from_points(self.origin() + amount, self.lower_right() - amount)
}
#[inline] #[inline]
pub fn to_f32(&self) -> RectF { pub fn to_f32(&self) -> RectF {
RectF(self.0.to_f32x4()) RectF(self.0.to_f32x4())

View File

@ -14,8 +14,8 @@ use crate::line_segment::LineSegment2F;
use crate::rect::RectF; use crate::rect::RectF;
use crate::transform3d::Transform4F; use crate::transform3d::Transform4F;
use crate::unit_vector::UnitVector; use crate::unit_vector::UnitVector;
use crate::vector::{Vector2F, Vector2I}; use crate::vector::Vector2F;
use pathfinder_simd::default::{F32x4, I32x4}; use pathfinder_simd::default::F32x4;
use std::ops::{Mul, MulAssign, Sub}; use std::ops::{Mul, MulAssign, Sub};
/// A 2x2 matrix, optimized with SIMD, in column-major order. /// A 2x2 matrix, optimized with SIMD, in column-major order.
@ -74,14 +74,17 @@ impl Matrix2x2F {
pub fn m11(&self) -> f32 { pub fn m11(&self) -> f32 {
self.0[0] self.0[0]
} }
#[inline] #[inline]
pub fn m21(&self) -> f32 { pub fn m21(&self) -> f32 {
self.0[1] self.0[1]
} }
#[inline] #[inline]
pub fn m12(&self) -> f32 { pub fn m12(&self) -> f32 {
self.0[2] self.0[2]
} }
#[inline] #[inline]
pub fn m22(&self) -> f32 { pub fn m22(&self) -> f32 {
self.0[3] self.0[3]
@ -113,29 +116,6 @@ impl Mul<Vector2F> for Matrix2x2F {
} }
} }
/// A 2x2 integer matrix, optimized with SIMD, in column-major order.
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Matrix2x2I(pub I32x4);
impl Matrix2x2I {
#[inline]
pub fn m11(&self) -> i32 {
self.0[0]
}
#[inline]
pub fn m21(&self) -> i32 {
self.0[1]
}
#[inline]
pub fn m12(&self) -> i32 {
self.0[2]
}
#[inline]
pub fn m22(&self) -> i32 {
self.0[3]
}
}
/// An affine transform, optimized with SIMD. /// An affine transform, optimized with SIMD.
#[derive(Clone, Copy, Debug, PartialEq)] #[derive(Clone, Copy, Debug, PartialEq)]
pub struct Transform2F { pub struct Transform2F {
@ -346,10 +326,3 @@ impl MulAssign for Transform2F {
*self = *self * other *self = *self * other
} }
} }
/// An affine integer transform, optimized with SIMD.
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Transform2I {
pub matrix: Matrix2x2I,
pub vector: Vector2I,
}

View File

@ -11,7 +11,7 @@
//! A SIMD-optimized point type. //! A SIMD-optimized point type.
use pathfinder_simd::default::{F32x2, F32x4, I32x2}; use pathfinder_simd::default::{F32x2, F32x4, I32x2};
use std::ops::{Add, AddAssign, Mul, Neg, Sub}; use std::ops::{Add, AddAssign, Div, Mul, Neg, Sub};
/// 2D points with 32-bit floating point coordinates. /// 2D points with 32-bit floating point coordinates.
#[derive(Clone, Copy, Debug, Default)] #[derive(Clone, Copy, Debug, Default)]
@ -135,6 +135,15 @@ impl Vector2F {
Vector2F(self.0.yx()) Vector2F(self.0.yx())
} }
/// Returns the coefficient when the given vector `a` is projected onto this one.
///
/// That is, if this vector is `v` and this function returns `c`, then `proj_v a = cv`. In
/// other words, this function computes `(a⋅v) / (v⋅v)`.
#[inline]
pub fn projection_coefficient(self, a: Vector2F) -> f32 {
a.dot(self) / self.square_length()
}
#[inline] #[inline]
pub fn is_zero(self) -> bool { pub fn is_zero(self) -> bool {
self == Vector2F::default() self == Vector2F::default()
@ -182,6 +191,14 @@ impl Mul<Vector2F> for Vector2F {
} }
} }
impl Div<Vector2F> for Vector2F {
type Output = Vector2F;
#[inline]
fn div(self, other: Vector2F) -> Vector2F {
Vector2F(self.0 / other.0)
}
}
impl Neg for Vector2F { impl Neg for Vector2F {
type Output = Vector2F; type Output = Vector2F;
#[inline] #[inline]

View File

@ -8,9 +8,9 @@ edition = "2018"
bitflags = "1.0" bitflags = "1.0"
byteorder = "1.3" byteorder = "1.3"
block = "0.1" block = "0.1"
cocoa = "0.20" cocoa = "0.19"
core-foundation = "0.7" core-foundation = "0.7"
foreign-types = "0.5" foreign-types = "0.3"
half = "1.4" half = "1.4"
metal = "0.17" metal = "0.17"
objc = "0.2" objc = "0.2"

View File

@ -11,7 +11,7 @@
//! Packs data onto the GPU. //! Packs data onto the GPU.
use crate::concurrent::executor::Executor; use crate::concurrent::executor::Executor;
use crate::gpu_data::{AlphaTileBatchPrimitive, BuiltObject, FillBatchPrimitive, RenderCommand}; use crate::gpu_data::{AlphaTile, BuiltObject, FillBatchPrimitive, RenderCommand};
use crate::options::{PreparedBuildOptions, RenderCommandListener}; use crate::options::{PreparedBuildOptions, RenderCommandListener};
use crate::paint::{PaintInfo, PaintMetadata}; use crate::paint::{PaintInfo, PaintMetadata};
use crate::scene::Scene; use crate::scene::Scene;
@ -23,6 +23,7 @@ use pathfinder_geometry::vector::{Vector2F, Vector2I};
use pathfinder_geometry::rect::{RectF, RectI}; use pathfinder_geometry::rect::{RectF, RectI};
use pathfinder_geometry::util; use pathfinder_geometry::util;
use pathfinder_simd::default::{F32x4, I32x4}; use pathfinder_simd::default::{F32x4, I32x4};
use std::i16;
use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::atomic::{AtomicUsize, Ordering};
use std::time::Instant; use std::time::Instant;
use std::u16; use std::u16;
@ -88,7 +89,7 @@ impl<'a> SceneBuilder<'a> {
built_options: &PreparedBuildOptions, built_options: &PreparedBuildOptions,
scene: &Scene, scene: &Scene,
paint_metadata: &[PaintMetadata], paint_metadata: &[PaintMetadata],
) -> Vec<AlphaTileBatchPrimitive> { ) -> Vec<AlphaTile> {
let path_object = &scene.paths[path_index]; let path_object = &scene.paths[path_index];
let outline = scene.apply_render_options(path_object.outline(), built_options); let outline = scene.apply_render_options(path_object.outline(), built_options);
let paint_id = path_object.paint(); let paint_id = path_object.paint();
@ -105,26 +106,29 @@ impl<'a> SceneBuilder<'a> {
tiler.built_object.alpha_tiles tiler.built_object.alpha_tiles
} }
fn cull_alpha_tiles(&self, alpha_tiles: &mut Vec<AlphaTileBatchPrimitive>) { fn cull_alpha_tiles(&self, alpha_tiles: &mut Vec<AlphaTile>) {
for alpha_tile in alpha_tiles { for alpha_tile in alpha_tiles {
let alpha_tile_coords = alpha_tile.tile_coords(); let alpha_tile_coords = alpha_tile.upper_left.tile_position();
if self if self
.z_buffer .z_buffer
.test(alpha_tile_coords, alpha_tile.object_index as u32) .test(alpha_tile_coords, alpha_tile.upper_left.object_index as u32)
{ {
continue; continue;
} }
// FIXME(pcwalton): Clean this up. // FIXME(pcwalton): Clean this up.
alpha_tile.tile_x_lo = 0xff; alpha_tile.upper_left.tile_x = i16::MIN;
alpha_tile.tile_y_lo = 0xff; alpha_tile.upper_left.tile_y = i16::MIN;
alpha_tile.tile_hi = 0xff; alpha_tile.upper_right.tile_x = i16::MIN;
alpha_tile.upper_right.tile_y = i16::MIN;
alpha_tile.lower_left.tile_x = i16::MIN;
alpha_tile.lower_left.tile_y = i16::MIN;
alpha_tile.lower_right.tile_x = i16::MIN;
alpha_tile.lower_right.tile_y = i16::MIN;
} }
} }
fn pack_alpha_tiles(&mut self, fn pack_alpha_tiles(&mut self, paint_metadata: &[PaintMetadata], alpha_tiles: Vec<AlphaTile>) {
paint_metadata: &[PaintMetadata],
alpha_tiles: Vec<AlphaTileBatchPrimitive>) {
let path_count = self.scene.paths.len() as u32; let path_count = self.scene.paths.len() as u32;
let solid_tiles = self.z_buffer.build_solid_tiles(&self.scene.paths, let solid_tiles = self.z_buffer.build_solid_tiles(&self.scene.paths,
paint_metadata, paint_metadata,
@ -139,7 +143,7 @@ impl<'a> SceneBuilder<'a> {
fn finish_building(&mut self, fn finish_building(&mut self,
paint_metadata: &[PaintMetadata], paint_metadata: &[PaintMetadata],
mut alpha_tiles: Vec<AlphaTileBatchPrimitive>) { mut alpha_tiles: Vec<AlphaTile>) {
self.listener.send(RenderCommand::FlushFills); self.listener.send(RenderCommand::FlushFills);
self.cull_alpha_tiles(&mut alpha_tiles); self.cull_alpha_tiles(&mut alpha_tiles);
self.pack_alpha_tiles(paint_metadata, alpha_tiles); self.pack_alpha_tiles(paint_metadata, alpha_tiles);

View File

@ -10,8 +10,7 @@
use crate::gpu::debug::DebugUIPresenter; use crate::gpu::debug::DebugUIPresenter;
use crate::gpu::options::{DestFramebuffer, RendererOptions}; use crate::gpu::options::{DestFramebuffer, RendererOptions};
use crate::gpu_data::{AlphaTileBatchPrimitive, FillBatchPrimitive, PaintData}; use crate::gpu_data::{AlphaTile, FillBatchPrimitive, PaintData, RenderCommand, SolidTileVertex};
use crate::gpu_data::{RenderCommand, SolidTileBatchPrimitive};
use crate::post::DefringingKernel; use crate::post::DefringingKernel;
use crate::tiles::{TILE_HEIGHT, TILE_WIDTH}; use crate::tiles::{TILE_HEIGHT, TILE_WIDTH};
use pathfinder_color::ColorF; use pathfinder_color::ColorF;
@ -34,14 +33,17 @@ use std::u32;
static QUAD_VERTEX_POSITIONS: [u16; 8] = [0, 0, 1, 0, 1, 1, 0, 1]; static QUAD_VERTEX_POSITIONS: [u16; 8] = [0, 0, 1, 0, 1, 1, 0, 1];
static QUAD_VERTEX_INDICES: [u32; 6] = [0, 1, 3, 1, 2, 3]; static QUAD_VERTEX_INDICES: [u32; 6] = [0, 1, 3, 1, 2, 3];
pub(crate) const MASK_TILES_ACROSS: u32 = 256;
pub(crate) const MASK_TILES_DOWN: u32 = 256;
// FIXME(pcwalton): Shrink this again! // FIXME(pcwalton): Shrink this again!
const MASK_FRAMEBUFFER_WIDTH: i32 = TILE_WIDTH as i32 * 256; const MASK_FRAMEBUFFER_WIDTH: i32 = TILE_WIDTH as i32 * MASK_TILES_ACROSS as i32;
const MASK_FRAMEBUFFER_HEIGHT: i32 = TILE_HEIGHT as i32 * 256; const MASK_FRAMEBUFFER_HEIGHT: i32 = TILE_HEIGHT as i32 * MASK_TILES_DOWN as i32;
// TODO(pcwalton): Replace with `mem::size_of` calls? // TODO(pcwalton): Replace with `mem::size_of` calls?
const FILL_INSTANCE_SIZE: usize = 8; const FILL_INSTANCE_SIZE: usize = 8;
const SOLID_TILE_INSTANCE_SIZE: usize = 20; const SOLID_TILE_VERTEX_SIZE: usize = 12;
const MASK_TILE_INSTANCE_SIZE: usize = 20; const MASK_TILE_VERTEX_SIZE: usize = 16;
const MAX_FILLS_PER_BATCH: usize = 0x4000; const MAX_FILLS_PER_BATCH: usize = 0x4000;
@ -63,6 +65,8 @@ where
area_lut_texture: D::Texture, area_lut_texture: D::Texture,
quad_vertex_positions_buffer: D::Buffer, quad_vertex_positions_buffer: D::Buffer,
quad_vertex_indices_buffer: D::Buffer, quad_vertex_indices_buffer: D::Buffer,
quads_vertex_indices_buffer: D::Buffer,
quads_vertex_indices_length: usize,
fill_vertex_array: FillVertexArray<D>, fill_vertex_array: FillVertexArray<D>,
mask_framebuffer: D::Framebuffer, mask_framebuffer: D::Framebuffer,
paint_texture: Option<D::Texture>, paint_texture: Option<D::Texture>,
@ -132,6 +136,7 @@ where
BufferTarget::Index, BufferTarget::Index,
BufferUploadMode::Static, BufferUploadMode::Static,
); );
let quads_vertex_indices_buffer = device.create_buffer();
let fill_vertex_array = FillVertexArray::new( let fill_vertex_array = FillVertexArray::new(
&device, &device,
@ -142,14 +147,12 @@ where
let alpha_tile_vertex_array = AlphaTileVertexArray::new( let alpha_tile_vertex_array = AlphaTileVertexArray::new(
&device, &device,
&alpha_tile_program, &alpha_tile_program,
&quad_vertex_positions_buffer, &quads_vertex_indices_buffer,
&quad_vertex_indices_buffer,
); );
let solid_tile_vertex_array = SolidTileVertexArray::new( let solid_tile_vertex_array = SolidTileVertexArray::new(
&device, &device,
&solid_tile_program, &solid_tile_program,
&quad_vertex_positions_buffer, &quads_vertex_indices_buffer,
&quad_vertex_indices_buffer,
); );
let postprocess_vertex_array = PostprocessVertexArray::new( let postprocess_vertex_array = PostprocessVertexArray::new(
&device, &device,
@ -187,6 +190,8 @@ where
area_lut_texture, area_lut_texture,
quad_vertex_positions_buffer, quad_vertex_positions_buffer,
quad_vertex_indices_buffer, quad_vertex_indices_buffer,
quads_vertex_indices_buffer,
quads_vertex_indices_length: 0,
fill_vertex_array, fill_vertex_array,
mask_framebuffer, mask_framebuffer,
paint_texture: None, paint_texture: None,
@ -237,10 +242,10 @@ where
self.draw_buffered_fills(); self.draw_buffered_fills();
self.begin_composite_timer_query(); self.begin_composite_timer_query();
} }
RenderCommand::SolidTile(ref solid_tiles) => { RenderCommand::SolidTile(ref solid_tile_vertices) => {
let count = solid_tiles.len(); let count = solid_tile_vertices.len() / 4;
self.stats.solid_tile_count += count; self.stats.solid_tile_count += count;
self.upload_solid_tiles(solid_tiles); self.upload_solid_tiles(solid_tile_vertices);
self.draw_solid_tiles(count as u32); self.draw_solid_tiles(count as u32);
} }
RenderCommand::AlphaTile(ref alpha_tiles) => { RenderCommand::AlphaTile(ref alpha_tiles) => {
@ -370,22 +375,49 @@ where
TextureDataRef::U8(paint_texels)); TextureDataRef::U8(paint_texels));
} }
fn upload_solid_tiles(&mut self, solid_tiles: &[SolidTileBatchPrimitive]) { fn upload_solid_tiles(&mut self, solid_tile_vertices: &[SolidTileVertex]) {
self.device.allocate_buffer( self.device.allocate_buffer(
&self.solid_tile_vertex_array.vertex_buffer, &self.solid_tile_vertex_array.vertex_buffer,
BufferData::Memory(&solid_tiles), BufferData::Memory(&solid_tile_vertices),
BufferTarget::Vertex, BufferTarget::Vertex,
BufferUploadMode::Dynamic, BufferUploadMode::Dynamic,
); );
self.ensure_index_buffer(solid_tile_vertices.len() / 4);
} }
fn upload_alpha_tiles(&mut self, alpha_tiles: &[AlphaTileBatchPrimitive]) { fn upload_alpha_tiles(&mut self, alpha_tiles: &[AlphaTile]) {
self.device.allocate_buffer( self.device.allocate_buffer(
&self.alpha_tile_vertex_array.vertex_buffer, &self.alpha_tile_vertex_array.vertex_buffer,
BufferData::Memory(&alpha_tiles), BufferData::Memory(&alpha_tiles),
BufferTarget::Vertex, BufferTarget::Vertex,
BufferUploadMode::Dynamic, BufferUploadMode::Dynamic,
); );
self.ensure_index_buffer(alpha_tiles.len());
}
fn ensure_index_buffer(&mut self, mut length: usize) {
length = length.next_power_of_two();
if self.quads_vertex_indices_length >= length {
return;
}
// TODO(pcwalton): Generate these with SIMD.
let mut indices: Vec<u32> = Vec::with_capacity(length * 6);
for index in 0..(length as u32) {
indices.extend_from_slice(&[
index * 4 + 0, index * 4 + 1, index * 4 + 2,
index * 4 + 1, index * 4 + 3, index * 4 + 2,
]);
}
self.device.allocate_buffer(
&self.quads_vertex_indices_buffer,
BufferData::Memory(&indices),
BufferTarget::Index,
BufferUploadMode::Static,
);
self.quads_vertex_indices_length = length;
} }
fn add_fills(&mut self, mut fills: &[FillBatchPrimitive]) { fn add_fills(&mut self, mut fills: &[FillBatchPrimitive]) {
@ -465,7 +497,7 @@ where
Transform4F::from_scale(scale).translate(Vector4F::new(-1.0, 1.0, 0.0, 1.0)) Transform4F::from_scale(scale).translate(Vector4F::new(-1.0, 1.0, 0.0, 1.0))
} }
fn draw_alpha_tiles(&mut self, count: u32) { fn draw_alpha_tiles(&mut self, tile_count: u32) {
let clear_color = self.clear_color_for_draw_operation(); let clear_color = self.clear_color_for_draw_operation();
let mut textures = vec![self.device.framebuffer_texture(&self.mask_framebuffer)]; let mut textures = vec![self.device.framebuffer_texture(&self.mask_framebuffer)];
@ -490,7 +522,7 @@ where
.0 .0
.to_f32x2()))); .to_f32x2())));
self.device.draw_elements_instanced(6, count, &RenderState { self.device.draw_elements(tile_count * 6, &RenderState {
target: &self.draw_render_target(), target: &self.draw_render_target(),
program: &self.alpha_tile_program.program, program: &self.alpha_tile_program.program,
vertex_array: &self.alpha_tile_vertex_array.vertex_array, vertex_array: &self.alpha_tile_vertex_array.vertex_array,
@ -512,7 +544,7 @@ where
self.preserve_draw_framebuffer(); self.preserve_draw_framebuffer();
} }
fn draw_solid_tiles(&mut self, count: u32) { fn draw_solid_tiles(&mut self, tile_count: u32) {
let clear_color = self.clear_color_for_draw_operation(); let clear_color = self.clear_color_for_draw_operation();
let mut textures = vec![]; let mut textures = vec![];
@ -530,7 +562,7 @@ where
uniforms.push((&self.solid_tile_program.paint_texture_size_uniform, uniforms.push((&self.solid_tile_program.paint_texture_size_uniform,
UniformData::Vec2(self.device.texture_size(paint_texture).0.to_f32x2()))); UniformData::Vec2(self.device.texture_size(paint_texture).0.to_f32x2())));
self.device.draw_elements_instanced(6, count, &RenderState { self.device.draw_elements(6 * tile_count, &RenderState {
target: &self.draw_render_target(), target: &self.draw_render_target(),
program: &self.solid_tile_program.program, program: &self.solid_tile_program.program,
vertex_array: &self.solid_tile_vertex_array.vertex_array, vertex_array: &self.solid_tile_vertex_array.vertex_array,
@ -940,87 +972,57 @@ where
fn new( fn new(
device: &D, device: &D,
alpha_tile_program: &AlphaTileProgram<D>, alpha_tile_program: &AlphaTileProgram<D>,
quad_vertex_positions_buffer: &D::Buffer, quads_vertex_indices_buffer: &D::Buffer,
quad_vertex_indices_buffer: &D::Buffer,
) -> AlphaTileVertexArray<D> { ) -> AlphaTileVertexArray<D> {
let (vertex_array, vertex_buffer) = (device.create_vertex_array(), device.create_buffer()); let (vertex_array, vertex_buffer) = (device.create_vertex_array(), device.create_buffer());
let tess_coord_attr = device.get_vertex_attr(&alpha_tile_program.program, "TessCoord") let tile_position_attr =
.unwrap(); device.get_vertex_attr(&alpha_tile_program.program, "TilePosition").unwrap();
let tile_origin_attr = device.get_vertex_attr(&alpha_tile_program.program, "TileOrigin") let color_tex_coord_attr = device.get_vertex_attr(&alpha_tile_program.program,
.unwrap(); "ColorTexCoord").unwrap();
let mask_tex_coord_attr = device.get_vertex_attr(&alpha_tile_program.program,
"MaskTexCoord").unwrap();
let backdrop_attr = device.get_vertex_attr(&alpha_tile_program.program, "Backdrop") let backdrop_attr = device.get_vertex_attr(&alpha_tile_program.program, "Backdrop")
.unwrap(); .unwrap();
let tile_index_attr = device.get_vertex_attr(&alpha_tile_program.program, "TileIndex")
.unwrap();
let color_tex_matrix_attr = device.get_vertex_attr(&alpha_tile_program.program,
"ColorTexMatrix").unwrap();
let color_tex_offset_attr = device.get_vertex_attr(&alpha_tile_program.program,
"ColorTexOffset").unwrap();
// NB: The object must be of type `I16`, not `U16`, to work around a macOS Radeon device.bind_buffer(&vertex_array, &vertex_buffer, BufferTarget::Vertex);
// driver bug. device.configure_vertex_attr(&vertex_array, &tile_position_attr, &VertexAttrDescriptor {
device.bind_buffer(&vertex_array, quad_vertex_positions_buffer, BufferTarget::Vertex);
device.configure_vertex_attr(&vertex_array, &tess_coord_attr, &VertexAttrDescriptor {
size: 2, size: 2,
class: VertexAttrClass::Int, class: VertexAttrClass::Int,
attr_type: VertexAttrType::U16, attr_type: VertexAttrType::I16,
stride: 4, stride: MASK_TILE_VERTEX_SIZE,
offset: 0, offset: 0,
divisor: 0, divisor: 0,
buffer_index: 0, buffer_index: 0,
}); });
device.bind_buffer(&vertex_array, &vertex_buffer, BufferTarget::Vertex); device.configure_vertex_attr(&vertex_array, &color_tex_coord_attr, &VertexAttrDescriptor {
device.configure_vertex_attr(&vertex_array, &tile_origin_attr, &VertexAttrDescriptor { size: 2,
size: 3, class: VertexAttrClass::FloatNorm,
class: VertexAttrClass::Int, attr_type: VertexAttrType::U16,
attr_type: VertexAttrType::U8, stride: MASK_TILE_VERTEX_SIZE,
stride: MASK_TILE_INSTANCE_SIZE, offset: 4,
offset: 0, divisor: 0,
divisor: 1, buffer_index: 0,
buffer_index: 1, });
device.configure_vertex_attr(&vertex_array, &mask_tex_coord_attr, &VertexAttrDescriptor {
size: 2,
class: VertexAttrClass::FloatNorm,
attr_type: VertexAttrType::U16,
stride: MASK_TILE_VERTEX_SIZE,
offset: 8,
divisor: 0,
buffer_index: 0,
}); });
device.configure_vertex_attr(&vertex_array, &backdrop_attr, &VertexAttrDescriptor { device.configure_vertex_attr(&vertex_array, &backdrop_attr, &VertexAttrDescriptor {
size: 1,
class: VertexAttrClass::Int,
attr_type: VertexAttrType::I8,
stride: MASK_TILE_INSTANCE_SIZE,
offset: 3,
divisor: 1,
buffer_index: 1,
});
device.configure_vertex_attr(&vertex_array, &tile_index_attr, &VertexAttrDescriptor {
size: 1, size: 1,
class: VertexAttrClass::Int, class: VertexAttrClass::Int,
attr_type: VertexAttrType::I16, attr_type: VertexAttrType::I16,
stride: MASK_TILE_INSTANCE_SIZE, stride: MASK_TILE_VERTEX_SIZE,
offset: 6, offset: 12,
divisor: 1, divisor: 0,
buffer_index: 1, buffer_index: 0,
}); });
device.configure_vertex_attr(&vertex_array, device.bind_buffer(&vertex_array, quads_vertex_indices_buffer, BufferTarget::Index);
&color_tex_matrix_attr,
&VertexAttrDescriptor {
size: 4,
class: VertexAttrClass::FloatNorm,
attr_type: VertexAttrType::U16,
stride: MASK_TILE_INSTANCE_SIZE,
offset: 8,
divisor: 1,
buffer_index: 1,
});
device.configure_vertex_attr(&vertex_array,
&color_tex_offset_attr,
&VertexAttrDescriptor {
size: 2,
class: VertexAttrClass::FloatNorm,
attr_type: VertexAttrType::U16,
stride: MASK_TILE_INSTANCE_SIZE,
offset: 16,
divisor: 1,
buffer_index: 1,
});
device.bind_buffer(&vertex_array, quad_vertex_indices_buffer, BufferTarget::Index);
AlphaTileVertexArray { vertex_array, vertex_buffer } AlphaTileVertexArray { vertex_array, vertex_buffer }
} }
@ -1041,65 +1043,39 @@ where
fn new( fn new(
device: &D, device: &D,
solid_tile_program: &SolidTileProgram<D>, solid_tile_program: &SolidTileProgram<D>,
quad_vertex_positions_buffer: &D::Buffer, quads_vertex_indices_buffer: &D::Buffer,
quad_vertex_indices_buffer: &D::Buffer,
) -> SolidTileVertexArray<D> { ) -> SolidTileVertexArray<D> {
let (vertex_array, vertex_buffer) = (device.create_vertex_array(), device.create_buffer()); let (vertex_array, vertex_buffer) = (device.create_vertex_array(), device.create_buffer());
let tess_coord_attr = device.get_vertex_attr(&solid_tile_program.program, "TessCoord") let tile_position_attr =
.unwrap(); device.get_vertex_attr(&solid_tile_program.program, "TilePosition").unwrap();
let tile_origin_attr = device.get_vertex_attr(&solid_tile_program.program, "TileOrigin") let color_tex_coord_attr =
.unwrap(); device.get_vertex_attr(&solid_tile_program.program, "ColorTexCoord").unwrap();
let color_tex_matrix_attr = device.get_vertex_attr(&solid_tile_program.program,
"ColorTexMatrix").unwrap();
let color_tex_offset_attr = device.get_vertex_attr(&solid_tile_program.program,
"ColorTexOffset").unwrap();
// NB: The object must be of type short, not unsigned short, to work around a macOS // NB: The tile origin must be of type short, not unsigned short, to work around a macOS
// Radeon driver bug. // Radeon driver bug.
device.bind_buffer(&vertex_array, quad_vertex_positions_buffer, BufferTarget::Vertex); device.bind_buffer(&vertex_array, &vertex_buffer, BufferTarget::Vertex);
device.configure_vertex_attr(&vertex_array, &tess_coord_attr, &VertexAttrDescriptor { device.configure_vertex_attr(&vertex_array, &tile_position_attr, &VertexAttrDescriptor {
size: 2, size: 2,
class: VertexAttrClass::Int, class: VertexAttrClass::Int,
attr_type: VertexAttrType::U16, attr_type: VertexAttrType::I16,
stride: 4, stride: SOLID_TILE_VERTEX_SIZE,
offset: 0, offset: 0,
divisor: 0, divisor: 0,
buffer_index: 0, buffer_index: 0,
}); });
device.bind_buffer(&vertex_array, &vertex_buffer, BufferTarget::Vertex);
device.configure_vertex_attr(&vertex_array, &tile_origin_attr, &VertexAttrDescriptor {
size: 2,
class: VertexAttrClass::Int,
attr_type: VertexAttrType::I16,
stride: SOLID_TILE_INSTANCE_SIZE,
offset: 0,
divisor: 1,
buffer_index: 1,
});
device.configure_vertex_attr(&vertex_array, device.configure_vertex_attr(&vertex_array,
&color_tex_matrix_attr, &color_tex_coord_attr,
&VertexAttrDescriptor {
size: 4,
class: VertexAttrClass::FloatNorm,
attr_type: VertexAttrType::U16,
stride: SOLID_TILE_INSTANCE_SIZE,
offset: 4,
divisor: 1,
buffer_index: 1,
});
device.configure_vertex_attr(&vertex_array,
&color_tex_offset_attr,
&VertexAttrDescriptor { &VertexAttrDescriptor {
size: 2, size: 2,
class: VertexAttrClass::FloatNorm, class: VertexAttrClass::FloatNorm,
attr_type: VertexAttrType::U16, attr_type: VertexAttrType::U16,
stride: SOLID_TILE_INSTANCE_SIZE, stride: SOLID_TILE_VERTEX_SIZE,
offset: 12, offset: 4,
divisor: 1, divisor: 0,
buffer_index: 1, buffer_index: 0,
}); });
device.bind_buffer(&vertex_array, quad_vertex_indices_buffer, BufferTarget::Index); device.bind_buffer(&vertex_array, quads_vertex_indices_buffer, BufferTarget::Index);
SolidTileVertexArray { vertex_array, vertex_buffer } SolidTileVertexArray { vertex_array, vertex_buffer }
} }

View File

@ -22,7 +22,7 @@ use std::time::Duration;
pub(crate) struct BuiltObject { pub(crate) struct BuiltObject {
pub bounds: RectF, pub bounds: RectF,
pub fills: Vec<FillBatchPrimitive>, pub fills: Vec<FillBatchPrimitive>,
pub alpha_tiles: Vec<AlphaTileBatchPrimitive>, pub alpha_tiles: Vec<AlphaTile>,
pub tiles: DenseTileMap<TileObjectPrimitive>, pub tiles: DenseTileMap<TileObjectPrimitive>,
} }
@ -31,8 +31,8 @@ pub enum RenderCommand {
AddPaintData(PaintData), AddPaintData(PaintData),
AddFills(Vec<FillBatchPrimitive>), AddFills(Vec<FillBatchPrimitive>),
FlushFills, FlushFills,
AlphaTile(Vec<AlphaTileBatchPrimitive>), AlphaTile(Vec<AlphaTile>),
SolidTile(Vec<SolidTileBatchPrimitive>), SolidTile(Vec<SolidTileVertex>),
Finish { build_time: Duration }, Finish { build_time: Duration },
} }
@ -69,34 +69,35 @@ pub struct FillBatchPrimitive {
#[derive(Clone, Copy, Debug)] #[derive(Clone, Copy, Debug)]
#[repr(C)] #[repr(C)]
pub struct SolidTileBatchPrimitive { pub struct SolidTileVertex {
pub tile_x: i16, pub tile_x: i16,
pub tile_y: i16, pub tile_y: i16,
pub texture_m00: u16, pub color_u: u16,
pub texture_m10: u16, pub color_v: u16,
pub texture_m01: u16,
pub texture_m11: u16,
pub texture_m02: u16,
pub texture_m12: u16,
pub object_index: u16, pub object_index: u16,
pub pad: u16, pub pad: u16,
} }
#[derive(Clone, Copy, Debug, Default)] #[derive(Clone, Copy, Debug, Default)]
#[repr(C)] #[repr(C)]
pub struct AlphaTileBatchPrimitive { pub struct AlphaTile {
pub tile_x_lo: u8, pub upper_left: AlphaTileVertex,
pub tile_y_lo: u8, pub upper_right: AlphaTileVertex,
pub tile_hi: u8, pub lower_left: AlphaTileVertex,
pub backdrop: i8, pub lower_right: AlphaTileVertex,
}
#[derive(Clone, Copy, Debug, Default)]
#[repr(C)]
pub struct AlphaTileVertex {
pub tile_x: i16,
pub tile_y: i16,
pub color_u: u16,
pub color_v: u16,
pub mask_u: u16,
pub mask_v: u16,
pub backdrop: i16,
pub object_index: u16, pub object_index: u16,
pub tile_index: u16,
pub texture_m00: u16,
pub texture_m10: u16,
pub texture_m01: u16,
pub texture_m11: u16,
pub texture_m02: u16,
pub texture_m12: u16,
} }
impl Debug for RenderCommand { impl Debug for RenderCommand {

View File

@ -1,6 +1,6 @@
// pathfinder/renderer/src/paint.rs // pathfinder/renderer/src/paint.rs
// //
// Copyright © 2019 The Pathfinder Project Developers. // Copyright © 2020 The Pathfinder Project Developers.
// //
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
@ -10,17 +10,25 @@
use crate::allocator::{TextureAllocator, TextureLocation}; use crate::allocator::{TextureAllocator, TextureLocation};
use crate::gpu_data::PaintData; use crate::gpu_data::PaintData;
use crate::tiles::{TILE_HEIGHT, TILE_WIDTH};
use hashbrown::HashMap; use hashbrown::HashMap;
use pathfinder_color::ColorU; use pathfinder_color::ColorU;
use pathfinder_content::gradient::Gradient; use pathfinder_content::gradient::Gradient;
use pathfinder_geometry::rect::RectI; use pathfinder_geometry::rect::{RectF, RectI};
use pathfinder_geometry::transform2d::{Matrix2x2I, Transform2I}; use pathfinder_geometry::transform2d::{Matrix2x2F, Transform2F};
use pathfinder_geometry::vector::Vector2I; use pathfinder_geometry::util;
use pathfinder_simd::default::I32x4; use pathfinder_geometry::vector::{Vector2F, Vector2I};
use pathfinder_simd::default::F32x4;
use std::fmt::{self, Debug, Formatter}; use std::fmt::{self, Debug, Formatter};
const PAINT_TEXTURE_LENGTH: u32 = 1024; const PAINT_TEXTURE_LENGTH: u32 = 1024;
const PAINT_TEXTURE_SCALE: u32 = 65536 / PAINT_TEXTURE_LENGTH; const PAINT_TEXTURE_SCALE: f32 = 1.0 / PAINT_TEXTURE_LENGTH as f32;
// The size of a gradient tile.
//
// TODO(pcwalton): Choose this size dynamically!
const GRADIENT_TILE_LENGTH: u32 = 256;
const GRADIENT_TILE_SCALE: f32 = GRADIENT_TILE_LENGTH as f32 * PAINT_TEXTURE_SCALE;
const SOLID_COLOR_TILE_LENGTH: u32 = 16; const SOLID_COLOR_TILE_LENGTH: u32 = 16;
const MAX_SOLID_COLORS_PER_TILE: u32 = SOLID_COLOR_TILE_LENGTH * SOLID_COLOR_TILE_LENGTH; const MAX_SOLID_COLORS_PER_TILE: u32 = SOLID_COLOR_TILE_LENGTH * SOLID_COLOR_TILE_LENGTH;
@ -112,10 +120,13 @@ pub struct PaintInfo {
pub metadata: Vec<PaintMetadata>, pub metadata: Vec<PaintMetadata>,
} }
// TODO(pcwalton): Add clamp/repeat options.
#[derive(Debug)] #[derive(Debug)]
pub struct PaintMetadata { pub struct PaintMetadata {
/// The transform to apply to the texture coordinates, in 0.16 fixed point. /// The rectangle within the texture atlas.
pub tex_transform: Transform2I, pub tex_rect: RectI,
/// The transform to apply to screen coordinates to translate them into UVs.
pub tex_transform: Transform2F,
/// True if this paint is fully opaque. /// True if this paint is fully opaque.
pub is_opaque: bool, pub is_opaque: bool,
} }
@ -133,29 +144,61 @@ impl Palette {
paint_id paint_id
} }
pub fn build_paint_info(&self) -> PaintInfo { pub fn build_paint_info(&self, view_box_size: Vector2I) -> PaintInfo {
let mut allocator = TextureAllocator::new(PAINT_TEXTURE_LENGTH); let mut allocator = TextureAllocator::new(PAINT_TEXTURE_LENGTH);
let area = PAINT_TEXTURE_LENGTH as usize * PAINT_TEXTURE_LENGTH as usize; let area = PAINT_TEXTURE_LENGTH as usize * PAINT_TEXTURE_LENGTH as usize;
let (mut texels, mut metadata) = (vec![0; area * 4], vec![]); let (mut texels, mut metadata) = (vec![0; area * 4], vec![]);
let mut solid_color_tile_builder = SolidColorTileBuilder::new(); let mut solid_color_tile_builder = SolidColorTileBuilder::new();
for paint in &self.paints { for paint in &self.paints {
let tex_transform; let (texture_location, tex_transform);
match paint { match paint {
Paint::Color(color) => { Paint::Color(color) => {
// TODO(pcwalton): Handle other paint types. texture_location = solid_color_tile_builder.allocate(&mut allocator);
let texture_location = solid_color_tile_builder.allocate(&mut allocator); let vector = rect_to_inset_uv(texture_location.rect).origin();
tex_transform = Transform2F { matrix: Matrix2x2F(F32x4::default()), vector };
put_pixel(&mut texels, texture_location.rect.origin(), *color); put_pixel(&mut texels, texture_location.rect.origin(), *color);
tex_transform = Transform2I {
matrix: Matrix2x2I(I32x4::default()),
vector: texture_location.rect.origin().scale(PAINT_TEXTURE_SCALE as i32) +
Vector2I::splat(PAINT_TEXTURE_SCALE as i32 / 2),
};
} }
Paint::Gradient(_) => unimplemented!(), Paint::Gradient(ref gradient) => {
// TODO(pcwalton): Optimize this:
// 1. Use repeating/clamp on the sides.
// 2. Choose an optimal size for the gradient that minimizes memory usage while
// retaining quality.
texture_location =
allocator.allocate(Vector2I::splat(GRADIENT_TILE_LENGTH as i32))
.expect("Failed to allocate space for the gradient!");
tex_transform =
Transform2F::from_translation(rect_to_uv(texture_location.rect).origin()) *
Transform2F::from_scale(Vector2F::splat(GRADIENT_TILE_SCALE) /
view_box_size.to_f32());
let gradient_line = tex_transform * gradient.line();
// TODO(pcwalton): Optimize this:
// 1. Calculate ∇t up front and use differencing in the inner loop.
// 2. Go four pixels at a time with SIMD.
for y in 0..(GRADIENT_TILE_LENGTH as i32) {
for x in 0..(GRADIENT_TILE_LENGTH as i32) {
let point = texture_location.rect.origin() + Vector2I::new(x, y);
let vector = point.to_f32().scale(1.0 / PAINT_TEXTURE_LENGTH as f32) -
gradient_line.from();
let mut t = gradient_line.vector().projection_coefficient(vector);
t = util::clamp(t, 0.0, 1.0);
put_pixel(&mut texels, point, gradient.sample(t));
}
}
}
} }
metadata.push(PaintMetadata { tex_transform, is_opaque: paint.is_opaque() }); metadata.push(PaintMetadata {
tex_rect: texture_location.rect,
tex_transform,
is_opaque: paint.is_opaque(),
});
} }
let size = Vector2I::splat(PAINT_TEXTURE_LENGTH as i32); let size = Vector2I::splat(PAINT_TEXTURE_LENGTH as i32);
@ -169,9 +212,28 @@ impl Palette {
texels[index + 2] = color.b; texels[index + 2] = color.b;
texels[index + 3] = color.a; texels[index + 3] = color.a;
} }
fn rect_to_uv(rect: RectI) -> RectF {
rect.to_f32().scale(1.0 / PAINT_TEXTURE_LENGTH as f32)
}
fn rect_to_inset_uv(rect: RectI) -> RectF {
rect_to_uv(rect).contract(Vector2F::splat(0.5 / PAINT_TEXTURE_LENGTH as f32))
}
} }
} }
impl PaintMetadata {
// TODO(pcwalton): Apply clamp/repeat to tile rect.
pub(crate) fn calculate_tex_coords(&self, tile_position: Vector2I) -> Vector2F {
let tile_size = Vector2I::new(TILE_WIDTH as i32, TILE_HEIGHT as i32);
let tex_coords = self.tex_transform * tile_position.scale_xy(tile_size).to_f32();
tex_coords
}
}
// Solid color allocation
struct SolidColorTileBuilder(Option<SolidColorTileBuilderData>); struct SolidColorTileBuilder(Option<SolidColorTileBuilderData>);
struct SolidColorTileBuilderData { struct SolidColorTileBuilderData {

View File

@ -47,7 +47,7 @@ impl Scene {
#[inline] #[inline]
pub fn build_paint_info(&self) -> PaintInfo { pub fn build_paint_info(&self) -> PaintInfo {
self.palette.build_paint_info() self.palette.build_paint_info(self.view_box.size().to_i32())
} }
#[allow(clippy::trivially_copy_pass_by_ref)] #[allow(clippy::trivially_copy_pass_by_ref)]

View File

@ -9,14 +9,14 @@
// except according to those terms. // except according to those terms.
use crate::builder::SceneBuilder; use crate::builder::SceneBuilder;
use crate::gpu_data::{AlphaTileBatchPrimitive, BuiltObject, TileObjectPrimitive}; use crate::gpu::renderer::MASK_TILES_ACROSS;
use crate::gpu_data::{AlphaTile, AlphaTileVertex, BuiltObject, TileObjectPrimitive};
use crate::paint::PaintMetadata; use crate::paint::PaintMetadata;
use pathfinder_content::outline::{Contour, Outline, PointIndex}; use pathfinder_content::outline::{Contour, Outline, PointIndex};
use pathfinder_content::segment::Segment; use pathfinder_content::segment::Segment;
use pathfinder_content::sorted_vector::SortedVector; use pathfinder_content::sorted_vector::SortedVector;
use pathfinder_geometry::line_segment::LineSegment2F; use pathfinder_geometry::line_segment::LineSegment2F;
use pathfinder_geometry::rect::{RectF, RectI}; use pathfinder_geometry::rect::{RectF, RectI};
use pathfinder_geometry::transform2d::Transform2I;
use pathfinder_geometry::vector::{Vector2F, Vector2I}; use pathfinder_geometry::vector::{Vector2F, Vector2I};
use std::cmp::Ordering; use std::cmp::Ordering;
use std::mem; use std::mem;
@ -126,15 +126,32 @@ impl<'a> Tiler<'a> {
} }
} }
let alpha_tile = AlphaTileBatchPrimitive::new( self.built_object.alpha_tiles.push(AlphaTile {
tile_coords, upper_left: AlphaTileVertex::new(tile_coords,
tile.backdrop, tile.alpha_tile_index as u16,
self.object_index, Vector2I::default(),
tile.alpha_tile_index as u16, self.object_index,
self.paint_metadata.tex_transform, tile.backdrop as i16,
); &self.paint_metadata),
upper_right: AlphaTileVertex::new(tile_coords,
self.built_object.alpha_tiles.push(alpha_tile); tile.alpha_tile_index as u16,
Vector2I::new(1, 0),
self.object_index,
tile.backdrop as i16,
&self.paint_metadata),
lower_left: AlphaTileVertex::new(tile_coords,
tile.alpha_tile_index as u16,
Vector2I::new(0, 1),
self.object_index,
tile.backdrop as i16,
&self.paint_metadata),
lower_right: AlphaTileVertex::new(tile_coords,
tile.alpha_tile_index as u16,
Vector2I::splat(1),
self.object_index,
tile.backdrop as i16,
&self.paint_metadata),
});
} }
} }
@ -526,36 +543,39 @@ impl PartialOrd<ActiveEdge> for ActiveEdge {
} }
} }
impl AlphaTileBatchPrimitive { impl AlphaTileVertex {
#[inline] #[inline]
fn new(tile_coords: Vector2I, fn new(tile_origin: Vector2I,
backdrop: i8,
object_index: u16,
tile_index: u16, tile_index: u16,
tex_transform: Transform2I) tile_offset: Vector2I,
-> AlphaTileBatchPrimitive { object_index: u16,
AlphaTileBatchPrimitive { backdrop: i16,
tile_x_lo: (tile_coords.x() & 0xff) as u8, paint_metadata: &PaintMetadata)
tile_y_lo: (tile_coords.y() & 0xff) as u8, -> AlphaTileVertex {
tile_hi: (((tile_coords.x() >> 8) & 0x0f) | ((tile_coords.y() >> 4) & 0xf0)) as u8, let tile_position = tile_origin + tile_offset;
backdrop, let color_uv = paint_metadata.calculate_tex_coords(tile_position).scale(65535.0).to_i32();
let mask_u = tile_index as i32 % MASK_TILES_ACROSS as i32;
let mask_v = tile_index as i32 / MASK_TILES_ACROSS as i32;
let mask_scale = 65535.0 / MASK_TILES_ACROSS as f32;
let mask_uv = Vector2I::new(mask_u, mask_v) + tile_offset;
let mask_uv = mask_uv.to_f32().scale(mask_scale).to_i32();
AlphaTileVertex {
tile_x: tile_position.x() as i16,
tile_y: tile_position.y() as i16,
color_u: color_uv.x() as u16,
color_v: color_uv.y() as u16,
mask_u: mask_uv.x() as u16,
mask_v: mask_uv.y() as u16,
object_index, object_index,
tile_index, backdrop,
texture_m00: tex_transform.matrix.m11() as u16,
texture_m10: tex_transform.matrix.m21() as u16,
texture_m01: tex_transform.matrix.m12() as u16,
texture_m11: tex_transform.matrix.m22() as u16,
texture_m02: tex_transform.vector.x() as u16,
texture_m12: tex_transform.vector.y() as u16,
} }
} }
#[inline] #[inline]
pub fn tile_coords(&self) -> Vector2I { pub fn tile_position(&self) -> Vector2I {
Vector2I::new( Vector2I::new(self.tile_x as i32, self.tile_y as i32)
(self.tile_x_lo as i32) | (((self.tile_hi & 0xf) as i32) << 8),
(self.tile_y_lo as i32) | (((self.tile_hi & 0xf0) as i32) << 4),
)
} }
} }

View File

@ -10,13 +10,12 @@
//! Software occlusion culling. //! Software occlusion culling.
use crate::gpu_data::SolidTileBatchPrimitive; use crate::gpu_data::SolidTileVertex;
use crate::paint::PaintMetadata; use crate::paint::PaintMetadata;
use crate::scene::PathObject; use crate::scene::PathObject;
use crate::tile_map::DenseTileMap; use crate::tile_map::DenseTileMap;
use crate::tiles; use crate::tiles;
use pathfinder_geometry::rect::RectF; use pathfinder_geometry::rect::RectF;
use pathfinder_geometry::transform2d::Transform2I;
use pathfinder_geometry::vector::Vector2I; use pathfinder_geometry::vector::Vector2I;
use std::ops::Range; use std::ops::Range;
use std::sync::atomic::{AtomicUsize, Ordering as AtomicOrdering}; use std::sync::atomic::{AtomicUsize, Ordering as AtomicOrdering};
@ -61,7 +60,7 @@ impl ZBuffer {
paths: &[PathObject], paths: &[PathObject],
paint_metadata: &[PaintMetadata], paint_metadata: &[PaintMetadata],
object_range: Range<u32>) object_range: Range<u32>)
-> Vec<SolidTileBatchPrimitive> { -> Vec<SolidTileVertex> {
let mut solid_tiles = vec![]; let mut solid_tiles = vec![];
for tile_index in 0..self.buffer.data.len() { for tile_index in 0..self.buffer.data.len() {
let depth = self.buffer.data[tile_index].load(AtomicOrdering::Relaxed); let depth = self.buffer.data[tile_index].load(AtomicOrdering::Relaxed);
@ -76,30 +75,39 @@ impl ZBuffer {
} }
let paint_id = paths[object_index as usize].paint(); let paint_id = paths[object_index as usize].paint();
let tex_transform = paint_metadata[paint_id.0 as usize].tex_transform; let paint_metadata = &paint_metadata[paint_id.0 as usize];
solid_tiles.push(SolidTileBatchPrimitive::new(tile_coords + self.buffer.rect.origin(), let tile_position = tile_coords + self.buffer.rect.origin();
object_index as u16, let object_index = object_index as u16;
tex_transform));
solid_tiles.extend_from_slice(&[
SolidTileVertex::new(tile_position, object_index, paint_metadata),
SolidTileVertex::new(tile_position + Vector2I::new(1, 0),
object_index,
paint_metadata),
SolidTileVertex::new(tile_position + Vector2I::new(0, 1),
object_index,
paint_metadata),
SolidTileVertex::new(tile_position + Vector2I::new(1, 1),
object_index,
paint_metadata),
]);
} }
solid_tiles solid_tiles
} }
} }
impl SolidTileBatchPrimitive { impl SolidTileVertex {
fn new(tile_coords: Vector2I, object_index: u16, tex_transform: Transform2I) fn new(tile_position: Vector2I, object_index: u16, paint_metadata: &PaintMetadata)
-> SolidTileBatchPrimitive { -> SolidTileVertex {
SolidTileBatchPrimitive { let color_uv = paint_metadata.calculate_tex_coords(tile_position).scale(65535.0).to_i32();
tile_x: tile_coords.x() as i16, SolidTileVertex {
tile_y: tile_coords.y() as i16, tile_x: tile_position.x() as i16,
tile_y: tile_position.y() as i16,
object_index: object_index, object_index: object_index,
texture_m00: tex_transform.matrix.m11() as u16, color_u: color_uv.x() as u16,
texture_m10: tex_transform.matrix.m21() as u16, color_v: color_uv.y() as u16,
texture_m01: tex_transform.matrix.m12() as u16,
texture_m11: tex_transform.matrix.m22() as u16,
texture_m02: tex_transform.vector.x() as u16,
texture_m12: tex_transform.vector.y() as u16,
pad: 0, pad: 0,
} }
} }

View File

@ -18,8 +18,8 @@ uniform sampler2D uStencilTexture;
uniform sampler2D uPaintTexture; uniform sampler2D uPaintTexture;
uniform vec2 uPaintTextureSize; uniform vec2 uPaintTextureSize;
in vec2 vMaskTexCoord;
in vec2 vColorTexCoord; in vec2 vColorTexCoord;
in vec2 vMaskTexCoord;
in float vBackdrop; in float vBackdrop;
in vec4 vColor; in vec4 vColor;

View File

@ -18,32 +18,20 @@ uniform mat4 uTransform;
uniform vec2 uTileSize; uniform vec2 uTileSize;
uniform vec2 uStencilTextureSize; uniform vec2 uStencilTextureSize;
in uvec2 aTessCoord; in ivec2 aTilePosition;
in uvec3 aTileOrigin; in vec2 aColorTexCoord;
in vec4 aColorTexMatrix; in vec2 aMaskTexCoord;
in vec2 aColorTexOffset;
in int aBackdrop; in int aBackdrop;
in int aTileIndex;
out vec2 vMaskTexCoord;
out vec2 vColorTexCoord; out vec2 vColorTexCoord;
out vec2 vMaskTexCoord;
out float vBackdrop; out float vBackdrop;
vec2 computeTileOffset(uint tileIndex, float stencilTextureWidth){
uint tilesPerRow = uint(stencilTextureWidth / uTileSize . x);
uvec2 tileOffset = uvec2(tileIndex % tilesPerRow, tileIndex / tilesPerRow);
return vec2(tileOffset)* uTileSize;
}
void main(){ void main(){
vec2 tileOffset = vec2(aTessCoord)* uTileSize; vec2 position = aTilePosition * uTileSize;
vec2 origin = vec2(aTileOrigin . xy)+ vec2(aTileOrigin . z & 15u, aTileOrigin . z >> 4u)* 256.0;
vec2 position = origin * uTileSize + tileOffset;
vec2 maskTexCoordOrigin = computeTileOffset(uint(aTileIndex), uStencilTextureSize . x);
vec2 maskTexCoord = maskTexCoordOrigin + tileOffset;
vMaskTexCoord = maskTexCoord / uStencilTextureSize; vMaskTexCoord = aMaskTexCoord;
vColorTexCoord = mat2(aColorTexMatrix)* tileOffset + aColorTexOffset; vColorTexCoord = aColorTexCoord;
vBackdrop = float(aBackdrop); vBackdrop = float(aBackdrop);
gl_Position = uTransform * vec4(position, 0.0, 1.0); gl_Position = uTransform * vec4(position, 0.0, 1.0);
} }

View File

@ -17,17 +17,14 @@ precision highp float;
uniform mat4 uTransform; uniform mat4 uTransform;
uniform vec2 uTileSize; uniform vec2 uTileSize;
in uvec2 aTessCoord; in ivec2 aTilePosition;
in ivec2 aTileOrigin; in vec2 aColorTexCoord;
in vec4 aColorTexMatrix;
in vec2 aColorTexOffset;
out vec2 vColorTexCoord; out vec2 vColorTexCoord;
void main(){ void main(){
vec2 tileOffset = vec2(aTessCoord)* uTileSize; vec2 position = aTilePosition * uTileSize;
vec2 position = aTileOrigin * uTileSize + tileOffset; vColorTexCoord = aColorTexCoord;
vColorTexCoord = mat2(aColorTexMatrix)* tileOffset + aColorTexOffset;
gl_Position = uTransform * vec4(position, 0.0, 1.0); gl_Position = uTransform * vec4(position, 0.0, 1.0);
} }

View File

@ -19,8 +19,8 @@ struct main0_out
struct main0_in struct main0_in
{ {
float2 vMaskTexCoord [[user(locn0)]]; float2 vColorTexCoord [[user(locn0)]];
float2 vColorTexCoord [[user(locn1)]]; float2 vMaskTexCoord [[user(locn1)]];
float vBackdrop [[user(locn2)]]; float vBackdrop [[user(locn2)]];
}; };

View File

@ -1,6 +1,4 @@
// Automatically generated from files in pathfinder/shaders/. Do not edit! // Automatically generated from files in pathfinder/shaders/. Do not edit!
#pragma clang diagnostic ignored "-Wmissing-prototypes"
#include <metal_stdlib> #include <metal_stdlib>
#include <simd/simd.h> #include <simd/simd.h>
@ -9,47 +7,31 @@ using namespace metal;
struct spvDescriptorSetBuffer0 struct spvDescriptorSetBuffer0
{ {
constant float2* uTileSize [[id(0)]]; constant float2* uTileSize [[id(0)]];
constant float2* uStencilTextureSize [[id(1)]]; constant float4x4* uTransform [[id(1)]];
constant float4x4* uTransform [[id(2)]];
}; };
struct main0_out struct main0_out
{ {
float2 vMaskTexCoord [[user(locn0)]]; float2 vColorTexCoord [[user(locn0)]];
float2 vColorTexCoord [[user(locn1)]]; float2 vMaskTexCoord [[user(locn1)]];
float vBackdrop [[user(locn2)]]; float vBackdrop [[user(locn2)]];
float4 gl_Position [[position]]; float4 gl_Position [[position]];
}; };
struct main0_in struct main0_in
{ {
uint2 aTessCoord [[attribute(0)]]; int2 aTilePosition [[attribute(0)]];
uint3 aTileOrigin [[attribute(1)]]; float2 aColorTexCoord [[attribute(1)]];
float4 aColorTexMatrix [[attribute(2)]]; float2 aMaskTexCoord [[attribute(2)]];
float2 aColorTexOffset [[attribute(3)]]; int aBackdrop [[attribute(3)]];
int aBackdrop [[attribute(4)]];
int aTileIndex [[attribute(5)]];
}; };
float2 computeTileOffset(thread const uint& tileIndex, thread const float& stencilTextureWidth, thread float2 uTileSize)
{
uint tilesPerRow = uint(stencilTextureWidth / uTileSize.x);
uint2 tileOffset = uint2(tileIndex % tilesPerRow, tileIndex / tilesPerRow);
return float2(tileOffset) * uTileSize;
}
vertex main0_out main0(main0_in in [[stage_in]], constant spvDescriptorSetBuffer0& spvDescriptorSet0 [[buffer(0)]]) vertex main0_out main0(main0_in in [[stage_in]], constant spvDescriptorSetBuffer0& spvDescriptorSet0 [[buffer(0)]])
{ {
main0_out out = {}; main0_out out = {};
float2 tileOffset = float2(in.aTessCoord) * (*spvDescriptorSet0.uTileSize); float2 position = float2(in.aTilePosition) * (*spvDescriptorSet0.uTileSize);
float2 origin = float2(in.aTileOrigin.xy) + (float2(float(in.aTileOrigin.z & 15u), float(in.aTileOrigin.z >> 4u)) * 256.0); out.vMaskTexCoord = in.aMaskTexCoord;
float2 position = (origin * (*spvDescriptorSet0.uTileSize)) + tileOffset; out.vColorTexCoord = in.aColorTexCoord;
uint param = uint(in.aTileIndex);
float param_1 = (*spvDescriptorSet0.uStencilTextureSize).x;
float2 maskTexCoordOrigin = computeTileOffset(param, param_1, (*spvDescriptorSet0.uTileSize));
float2 maskTexCoord = maskTexCoordOrigin + tileOffset;
out.vMaskTexCoord = maskTexCoord / (*spvDescriptorSet0.uStencilTextureSize);
out.vColorTexCoord = (float2x2(float2(in.aColorTexMatrix.xy), float2(in.aColorTexMatrix.zw)) * tileOffset) + in.aColorTexOffset;
out.vBackdrop = float(in.aBackdrop); out.vBackdrop = float(in.aBackdrop);
out.gl_Position = (*spvDescriptorSet0.uTransform) * float4(position, 0.0, 1.0); out.gl_Position = (*spvDescriptorSet0.uTransform) * float4(position, 0.0, 1.0);
return out; return out;

View File

@ -18,18 +18,15 @@ struct main0_out
struct main0_in struct main0_in
{ {
uint2 aTessCoord [[attribute(0)]]; int2 aTilePosition [[attribute(0)]];
int2 aTileOrigin [[attribute(1)]]; float2 aColorTexCoord [[attribute(1)]];
float4 aColorTexMatrix [[attribute(2)]];
float2 aColorTexOffset [[attribute(3)]];
}; };
vertex main0_out main0(main0_in in [[stage_in]], constant spvDescriptorSetBuffer0& spvDescriptorSet0 [[buffer(0)]]) vertex main0_out main0(main0_in in [[stage_in]], constant spvDescriptorSetBuffer0& spvDescriptorSet0 [[buffer(0)]])
{ {
main0_out out = {}; main0_out out = {};
float2 tileOffset = float2(in.aTessCoord) * (*spvDescriptorSet0.uTileSize); float2 position = float2(in.aTilePosition) * (*spvDescriptorSet0.uTileSize);
float2 position = (float2(in.aTileOrigin) * (*spvDescriptorSet0.uTileSize)) + tileOffset; out.vColorTexCoord = in.aColorTexCoord;
out.vColorTexCoord = (float2x2(float2(in.aColorTexMatrix.xy), float2(in.aColorTexMatrix.zw)) * tileOffset) + in.aColorTexOffset;
out.gl_Position = (*spvDescriptorSet0.uTransform) * float4(position, 0.0, 1.0); out.gl_Position = (*spvDescriptorSet0.uTransform) * float4(position, 0.0, 1.0);
return out; return out;
} }

View File

@ -2,7 +2,7 @@
// pathfinder/shaders/tile_alpha.fs.glsl // pathfinder/shaders/tile_alpha.fs.glsl
// //
// Copyright © 2018 The Pathfinder Project Developers. // Copyright © 2020 The Pathfinder Project Developers.
// //
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
@ -16,8 +16,8 @@ uniform sampler2D uStencilTexture;
uniform sampler2D uPaintTexture; uniform sampler2D uPaintTexture;
uniform vec2 uPaintTextureSize; uniform vec2 uPaintTextureSize;
in vec2 vMaskTexCoord;
in vec2 vColorTexCoord; in vec2 vColorTexCoord;
in vec2 vMaskTexCoord;
in float vBackdrop; in float vBackdrop;
in vec4 vColor; in vec4 vColor;

View File

@ -16,32 +16,20 @@ uniform mat4 uTransform;
uniform vec2 uTileSize; uniform vec2 uTileSize;
uniform vec2 uStencilTextureSize; uniform vec2 uStencilTextureSize;
in uvec2 aTessCoord; in ivec2 aTilePosition;
in uvec3 aTileOrigin; in vec2 aColorTexCoord;
in vec4 aColorTexMatrix; in vec2 aMaskTexCoord;
in vec2 aColorTexOffset;
in int aBackdrop; in int aBackdrop;
in int aTileIndex;
out vec2 vMaskTexCoord;
out vec2 vColorTexCoord; out vec2 vColorTexCoord;
out vec2 vMaskTexCoord;
out float vBackdrop; out float vBackdrop;
vec2 computeTileOffset(uint tileIndex, float stencilTextureWidth) {
uint tilesPerRow = uint(stencilTextureWidth / uTileSize.x);
uvec2 tileOffset = uvec2(tileIndex % tilesPerRow, tileIndex / tilesPerRow);
return vec2(tileOffset) * uTileSize;
}
void main() { void main() {
vec2 tileOffset = vec2(aTessCoord) * uTileSize; vec2 position = aTilePosition * uTileSize;
vec2 origin = vec2(aTileOrigin.xy) + vec2(aTileOrigin.z & 15u, aTileOrigin.z >> 4u) * 256.0;
vec2 position = origin * uTileSize + tileOffset;
vec2 maskTexCoordOrigin = computeTileOffset(uint(aTileIndex), uStencilTextureSize.x);
vec2 maskTexCoord = maskTexCoordOrigin + tileOffset;
vMaskTexCoord = maskTexCoord / uStencilTextureSize; vMaskTexCoord = aMaskTexCoord;
vColorTexCoord = mat2(aColorTexMatrix) * tileOffset + aColorTexOffset; vColorTexCoord = aColorTexCoord;
vBackdrop = float(aBackdrop); vBackdrop = float(aBackdrop);
gl_Position = uTransform * vec4(position, 0.0, 1.0); gl_Position = uTransform * vec4(position, 0.0, 1.0);
} }

View File

@ -2,7 +2,7 @@
// pathfinder/shaders/tile_solid.vs.glsl // pathfinder/shaders/tile_solid.vs.glsl
// //
// Copyright © 2019 The Pathfinder Project Developers. // Copyright © 2020 The Pathfinder Project Developers.
// //
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
@ -15,16 +15,13 @@ precision highp float;
uniform mat4 uTransform; uniform mat4 uTransform;
uniform vec2 uTileSize; uniform vec2 uTileSize;
in uvec2 aTessCoord; in ivec2 aTilePosition;
in ivec2 aTileOrigin; in vec2 aColorTexCoord;
in vec4 aColorTexMatrix;
in vec2 aColorTexOffset;
out vec2 vColorTexCoord; out vec2 vColorTexCoord;
void main() { void main() {
vec2 tileOffset = vec2(aTessCoord) * uTileSize; vec2 position = aTilePosition * uTileSize;
vec2 position = aTileOrigin * uTileSize + tileOffset; vColorTexCoord = aColorTexCoord;
vColorTexCoord = mat2(aColorTexMatrix) * tileOffset + aColorTexOffset;
gl_Position = uTransform * vec4(position, 0.0, 1.0); gl_Position = uTransform * vec4(position, 0.0, 1.0);
} }

View File

@ -179,6 +179,14 @@ impl Add<F32x2> for F32x2 {
} }
} }
impl Div<F32x2> for F32x2 {
type Output = F32x2;
#[inline]
fn div(self, other: F32x2) -> F32x2 {
unsafe { F32x2(simd_div(self.0, other.0)) }
}
}
impl Mul<F32x2> for F32x2 { impl Mul<F32x2> for F32x2 {
type Output = F32x2; type Output = F32x2;
#[inline] #[inline]
@ -380,6 +388,14 @@ impl Add<F32x4> for F32x4 {
} }
} }
impl Div<F32x4> for F32x4 {
type Output = F32x4;
#[inline]
fn div(self, other: F32x4) -> F32x4 {
unsafe { F32x4(simd_div(self.0, other.0)) }
}
}
impl Mul<F32x4> for F32x4 { impl Mul<F32x4> for F32x4 {
type Output = F32x4; type Output = F32x4;
#[inline] #[inline]
@ -412,6 +428,18 @@ impl I32x2 {
I32x2::new(x, x) I32x2::new(x, x)
} }
// Accessors
#[inline]
pub fn x(self) -> i32 {
self[0]
}
#[inline]
pub fn y(self) -> i32 {
self[1]
}
#[inline] #[inline]
pub fn packed_eq(self, other: I32x2) -> U32x2 { pub fn packed_eq(self, other: I32x2) -> U32x2 {
unsafe { U32x2(simd_eq(self.0, other.0)) } unsafe { U32x2(simd_eq(self.0, other.0)) }
@ -750,6 +778,7 @@ impl Index<usize> for U32x4 {
extern "platform-intrinsic" { extern "platform-intrinsic" {
fn simd_add<T>(x: T, y: T) -> T; fn simd_add<T>(x: T, y: T) -> T;
fn simd_div<T>(x: T, y: T) -> T;
fn simd_mul<T>(x: T, y: T) -> T; fn simd_mul<T>(x: T, y: T) -> T;
fn simd_sub<T>(x: T, y: T) -> T; fn simd_sub<T>(x: T, y: T) -> T;

View File

@ -10,7 +10,7 @@
use std::f32; use std::f32;
use std::fmt::{self, Debug, Formatter}; use std::fmt::{self, Debug, Formatter};
use std::ops::{Add, BitAnd, BitOr, Index, IndexMut, Mul, Shr, Sub}; use std::ops::{Add, BitAnd, BitOr, Div, Index, IndexMut, Mul, Shr, Sub};
mod swizzle_f32x4; mod swizzle_f32x4;
mod swizzle_i32x4; mod swizzle_i32x4;
@ -166,6 +166,14 @@ impl Add<F32x2> for F32x2 {
} }
} }
impl Div<F32x2> for F32x2 {
type Output = F32x2;
#[inline]
fn div(self, other: F32x2) -> F32x2 {
F32x2([self[0] / other[0], self[1] / other[1]])
}
}
impl Mul<F32x2> for F32x2 { impl Mul<F32x2> for F32x2 {
type Output = F32x2; type Output = F32x2;
#[inline] #[inline]
@ -403,6 +411,19 @@ impl Add<F32x4> for F32x4 {
} }
} }
impl Div<F32x4> for F32x4 {
type Output = F32x4;
#[inline]
fn div(self, other: F32x4) -> F32x4 {
F32x4([
self[0] / other[0],
self[1] / other[1],
self[2] / other[2],
self[3] / other[3],
])
}
}
impl Mul<F32x4> for F32x4 { impl Mul<F32x4> for F32x4 {
type Output = F32x4; type Output = F32x4;
#[inline] #[inline]
@ -445,6 +466,18 @@ impl I32x2 {
I32x2([x, x]) I32x2([x, x])
} }
// Accessors
#[inline]
pub fn x(self) -> i32 {
self[0]
}
#[inline]
pub fn y(self) -> i32 {
self[1]
}
#[inline] #[inline]
pub fn packed_eq(self, other: I32x2) -> U32x2 { pub fn packed_eq(self, other: I32x2) -> U32x2 {
U32x2([ U32x2([

View File

@ -11,7 +11,7 @@
use std::cmp::PartialEq; use std::cmp::PartialEq;
use std::fmt::{self, Debug, Formatter}; use std::fmt::{self, Debug, Formatter};
use std::mem; use std::mem;
use std::ops::{Add, BitAnd, BitOr, BitXor, Index, IndexMut, Mul, Not, Shr, Sub}; use std::ops::{Add, BitAnd, BitOr, BitXor, Div, Index, IndexMut, Mul, Not, Shr, Sub};
#[cfg(target_pointer_width = "32")] #[cfg(target_pointer_width = "32")]
use std::arch::x86::{__m128, __m128i}; use std::arch::x86::{__m128, __m128i};
@ -191,6 +191,14 @@ impl Add<F32x2> for F32x2 {
} }
} }
impl Div<F32x2> for F32x2 {
type Output = F32x2;
#[inline]
fn div(self, other: F32x2) -> F32x2 {
(self.to_f32x4() / other.to_f32x4()).xy()
}
}
impl Mul<F32x2> for F32x2 { impl Mul<F32x2> for F32x2 {
type Output = F32x2; type Output = F32x2;
#[inline] #[inline]
@ -423,6 +431,14 @@ impl Add<F32x4> for F32x4 {
} }
} }
impl Div<F32x4> for F32x4 {
type Output = F32x4;
#[inline]
fn div(self, other: F32x4) -> F32x4 {
unsafe { F32x4(x86::_mm_div_ps(self.0, other.0)) }
}
}
impl Mul<F32x4> for F32x4 { impl Mul<F32x4> for F32x4 {
type Output = F32x4; type Output = F32x4;
#[inline] #[inline]
@ -461,6 +477,18 @@ impl I32x2 {
I32x2::new(x, x) I32x2::new(x, x)
} }
// Accessors
#[inline]
pub fn x(self) -> i32 {
self[0]
}
#[inline]
pub fn y(self) -> i32 {
self[1]
}
// Concatenations // Concatenations
#[inline] #[inline]