Apply path transforms to paints

This commit is contained in:
Patrick Walton 2020-03-03 14:26:38 -08:00
parent 12574101e5
commit 2beb2bb126
6 changed files with 87 additions and 56 deletions

View File

@ -20,15 +20,15 @@ use crate::options::{PreparedBuildOptions, RenderCommandListener};
use crate::paint::{PaintInfo, PaintMetadata}; use crate::paint::{PaintInfo, PaintMetadata};
use crate::scene::{DisplayItem, Scene}; use crate::scene::{DisplayItem, Scene};
use crate::tile_map::DenseTileMap; use crate::tile_map::DenseTileMap;
use crate::tiles::{self, TILE_HEIGHT, TILE_WIDTH, Tiler, TilingPathInfo}; use crate::tiles::{self, DrawTilingPathInfo, TILE_HEIGHT, TILE_WIDTH, Tiler, TilingPathInfo};
use crate::z_buffer::ZBuffer; use crate::z_buffer::{DepthMetadata, ZBuffer};
use pathfinder_content::effects::BlendMode; use pathfinder_content::effects::BlendMode;
use pathfinder_content::fill::FillRule; use pathfinder_content::fill::FillRule;
use pathfinder_content::pattern::RenderTargetId; use pathfinder_content::pattern::RenderTargetId;
use pathfinder_geometry::line_segment::{LineSegment2F, LineSegmentU4, LineSegmentU8}; use pathfinder_geometry::line_segment::{LineSegment2F, LineSegmentU4, LineSegmentU8};
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_geometry::vector::{Vector2F, Vector2I};
use pathfinder_gpu::TextureSamplingFlags; use pathfinder_gpu::TextureSamplingFlags;
use pathfinder_simd::default::{F32x4, I32x4}; use pathfinder_simd::default::{F32x4, I32x4};
use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::atomic::{AtomicUsize, Ordering};
@ -170,8 +170,7 @@ impl<'a> SceneBuilder<'a> {
built_clip_paths: &[BuiltPath], built_clip_paths: &[BuiltPath],
) -> BuiltDrawPath { ) -> BuiltDrawPath {
let path_object = &scene.paths[path_index]; let path_object = &scene.paths[path_index];
let mut outline = scene.apply_render_options(path_object.outline(), built_options); let outline = scene.apply_render_options(path_object.outline(), built_options);
outline.transform(&path_object.transform());
let paint_id = path_object.paint(); let paint_id = path_object.paint();
let paint_metadata = &paint_metadata[paint_id.0 as usize]; let paint_metadata = &paint_metadata[paint_id.0 as usize];
@ -183,12 +182,13 @@ impl<'a> SceneBuilder<'a> {
path_object.fill_rule(), path_object.fill_rule(),
view_box, view_box,
path_index as u16, path_index as u16,
TilingPathInfo::Draw { TilingPathInfo::Draw(DrawTilingPathInfo {
paint_metadata, paint_metadata,
blend_mode: path_object.blend_mode(), blend_mode: path_object.blend_mode(),
opacity: path_object.opacity(), opacity: path_object.opacity(),
built_clip_path, built_clip_path,
}); transform_inv: path_object.transform().inverse(),
}));
tiler.generate_tiles(); tiler.generate_tiles();
@ -357,8 +357,12 @@ impl<'a> SceneBuilder<'a> {
built_draw_paths[start_index..end_index].iter().enumerate() { built_draw_paths[start_index..end_index].iter().enumerate() {
let solid_tiles = &built_draw_path.path.solid_tiles; let solid_tiles = &built_draw_path.path.solid_tiles;
let path_index = (path_subindex + start_index) as u32; let path_index = (path_subindex + start_index) as u32;
let paint = self.scene.paths[path_index as usize].paint(); let path = &self.scene.paths[path_index as usize];
z_buffer.update(solid_tiles, current_depth, paint); let metadata = DepthMetadata {
paint_id: path.paint(),
transform: path.transform(),
};
z_buffer.update(solid_tiles, current_depth, metadata);
current_depth += 1; current_depth += 1;
} }
} }
@ -701,33 +705,28 @@ impl ObjectBuilder {
mask_tile_index: u16, mask_tile_index: u16,
tile_coords: Vector2I, tile_coords: Vector2I,
object_index: u16, object_index: u16,
opacity: u8, draw_tiling_path_info: &DrawTilingPathInfo) {
paint_metadata: &PaintMetadata) {
alpha_tiles.push(AlphaTile { alpha_tiles.push(AlphaTile {
upper_left: AlphaTileVertex::new(tile_coords, upper_left: AlphaTileVertex::new(tile_coords,
mask_tile_index, mask_tile_index,
Vector2I::default(), Vector2I::default(),
object_index, object_index,
opacity, draw_tiling_path_info),
paint_metadata),
upper_right: AlphaTileVertex::new(tile_coords, upper_right: AlphaTileVertex::new(tile_coords,
mask_tile_index, mask_tile_index,
Vector2I::new(1, 0), Vector2I::new(1, 0),
object_index, object_index,
opacity, draw_tiling_path_info),
paint_metadata),
lower_left: AlphaTileVertex::new(tile_coords, lower_left: AlphaTileVertex::new(tile_coords,
mask_tile_index, mask_tile_index,
Vector2I::new(0, 1), Vector2I::new(0, 1),
object_index, object_index,
opacity, draw_tiling_path_info),
paint_metadata),
lower_right: AlphaTileVertex::new(tile_coords, lower_right: AlphaTileVertex::new(tile_coords,
mask_tile_index, mask_tile_index,
Vector2I::splat(1), Vector2I::splat(1),
object_index, object_index,
opacity, draw_tiling_path_info),
paint_metadata),
}); });
} }
} }
@ -759,11 +758,12 @@ impl AlphaTileVertex {
tile_index: u16, tile_index: u16,
tile_offset: Vector2I, tile_offset: Vector2I,
object_index: u16, object_index: u16,
opacity: u8, draw_tiling_path_info: &DrawTilingPathInfo)
paint_metadata: &PaintMetadata)
-> AlphaTileVertex { -> AlphaTileVertex {
let tile_position = tile_origin + tile_offset; let tile_position = tile_origin + tile_offset;
let color_uv = paint_metadata.calculate_tex_coords(tile_position); let transform_inv = draw_tiling_path_info.transform_inv;
let color_uv = draw_tiling_path_info.paint_metadata.calculate_tex_coords(tile_position,
transform_inv);
let mask_uv = calculate_mask_uv(tile_index, tile_offset); let mask_uv = calculate_mask_uv(tile_index, tile_offset);
AlphaTileVertex { AlphaTileVertex {
tile_x: tile_position.x() as i16, tile_x: tile_position.x() as i16,
@ -773,7 +773,7 @@ impl AlphaTileVertex {
mask_u: mask_uv.x() as u16, mask_u: mask_uv.x() as u16,
mask_v: mask_uv.y() as u16, mask_v: mask_uv.y() as u16,
object_index, object_index,
opacity, opacity: draw_tiling_path_info.opacity,
pad: 0, pad: 0,
} }
} }

View File

@ -525,9 +525,13 @@ impl Palette {
impl PaintMetadata { impl PaintMetadata {
// TODO(pcwalton): Apply clamp/repeat to tile rect. // TODO(pcwalton): Apply clamp/repeat to tile rect.
pub(crate) fn calculate_tex_coords(&self, tile_position: Vector2I) -> Vector2F { pub(crate) fn calculate_tex_coords(&self,
tile_position: Vector2I,
path_transform_inv: Transform2F)
-> Vector2F {
let tile_size = Vector2I::new(TILE_WIDTH as i32, TILE_HEIGHT as i32); 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(); let position = tile_position.scale_xy(tile_size).to_f32();
let tex_coords = self.tex_transform * path_transform_inv * position;
tex_coords tex_coords
} }
} }

View File

@ -46,7 +46,9 @@ impl Scene {
} }
} }
pub fn push_path(&mut self, path: DrawPath) { pub fn push_path(&mut self, mut path: DrawPath) {
path.outline.transform(&path.transform());
self.bounds = self.bounds.union_rect(path.outline.bounds()); self.bounds = self.bounds.union_rect(path.outline.bounds());
self.paths.push(path); self.paths.push(path);

View File

@ -18,6 +18,7 @@ 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::Transform2F;
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;
@ -43,12 +44,19 @@ pub(crate) struct Tiler<'a> {
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
pub(crate) enum TilingPathInfo<'a> { pub(crate) enum TilingPathInfo<'a> {
Clip, Clip,
Draw { Draw(DrawTilingPathInfo<'a>),
paint_metadata: &'a PaintMetadata, }
blend_mode: BlendMode,
opacity: u8, #[derive(Clone, Copy)]
built_clip_path: Option<&'a BuiltPath>, pub(crate) struct DrawTilingPathInfo<'a> {
}, pub(crate) paint_metadata: &'a PaintMetadata,
pub(crate) blend_mode: BlendMode,
pub(crate) opacity: u8,
// The inverse of the path transform.
//
// We calculate texture transforms with this.
pub(crate) transform_inv: Transform2F,
pub(crate) built_clip_path: Option<&'a BuiltPath>,
} }
impl<'a> Tiler<'a> { impl<'a> Tiler<'a> {
@ -128,11 +136,9 @@ impl<'a> Tiler<'a> {
} }
fn pack_and_cull_draw_path(&mut self) { fn pack_and_cull_draw_path(&mut self) {
let (paint_metadata, blend_mode, opacity, built_clip_path) = match self.path_info { let draw_tiling_path_info = match self.path_info {
TilingPathInfo::Clip => unreachable!(), TilingPathInfo::Clip => unreachable!(),
TilingPathInfo::Draw { paint_metadata, blend_mode, opacity, built_clip_path } => { TilingPathInfo::Draw(draw_tiling_path_info) => draw_tiling_path_info,
(paint_metadata, blend_mode, opacity, built_clip_path)
}
}; };
for (draw_tile_index, draw_tile) in self.object_builder for (draw_tile_index, draw_tile) in self.object_builder
@ -145,7 +151,7 @@ impl<'a> Tiler<'a> {
.local_tile_index_to_coords(draw_tile_index as u32); .local_tile_index_to_coords(draw_tile_index as u32);
// Figure out what clip tile we need, if any. // Figure out what clip tile we need, if any.
let clip_tile = match built_clip_path { let clip_tile = match draw_tiling_path_info.built_clip_path {
None => None, None => None,
Some(built_clip_path) => { Some(built_clip_path) => {
match built_clip_path.tiles.get(tile_coords) { match built_clip_path.tiles.get(tile_coords) {
@ -182,7 +188,9 @@ impl<'a> Tiler<'a> {
// Next, if this is a solid tile that completely occludes the background, record // Next, if this is a solid tile that completely occludes the background, record
// that fact and stop here. // that fact and stop here.
if paint_metadata.is_opaque && blend_mode.occludes_backdrop() && opacity == !0 { if draw_tiling_path_info.paint_metadata.is_opaque &&
draw_tiling_path_info.blend_mode.occludes_backdrop() &&
draw_tiling_path_info.opacity == !0 {
self.object_builder.built_path.solid_tiles.push(SolidTile::new(tile_coords)); self.object_builder.built_path.solid_tiles.push(SolidTile::new(tile_coords));
continue; continue;
} }
@ -210,8 +218,7 @@ impl<'a> Tiler<'a> {
mask_tile_index, mask_tile_index,
tile_coords, tile_coords,
self.object_index, self.object_index,
opacity, &draw_tiling_path_info);
paint_metadata);
} }
} }

View File

@ -16,24 +16,30 @@ use crate::paint::{PaintId, PaintMetadata};
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::Transform2F;
use pathfinder_geometry::vector::Vector2I; use pathfinder_geometry::vector::Vector2I;
use vec_map::VecMap; use vec_map::VecMap;
pub(crate) struct ZBuffer { pub(crate) struct ZBuffer {
buffer: DenseTileMap<u32>, buffer: DenseTileMap<u32>,
depth_to_paint_id: VecMap<PaintId>, depth_metadata: VecMap<DepthMetadata>,
} }
pub(crate) struct SolidTiles { pub(crate) struct SolidTiles {
pub(crate) batches: Vec<SolidTileBatch>, pub(crate) batches: Vec<SolidTileBatch>,
} }
#[derive(Clone, Copy)]
pub(crate) struct DepthMetadata {
pub(crate) paint_id: PaintId,
pub(crate) transform: Transform2F,
}
impl ZBuffer { impl ZBuffer {
pub(crate) fn new(view_box: RectF) -> ZBuffer { pub(crate) fn new(view_box: RectF) -> 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);
ZBuffer { ZBuffer {
buffer: DenseTileMap::from_builder(|_| 0, tile_rect), buffer: DenseTileMap::from_builder(|_| 0, tile_rect),
depth_to_paint_id: VecMap::new(), depth_metadata: VecMap::new(),
} }
} }
@ -42,8 +48,11 @@ impl ZBuffer {
self.buffer.data[tile_index as usize] < depth self.buffer.data[tile_index as usize] < depth
} }
pub(crate) fn update(&mut self, solid_tiles: &[SolidTile], depth: u32, paint_id: PaintId) { pub(crate) fn update(&mut self,
self.depth_to_paint_id.insert(depth as usize, paint_id); solid_tiles: &[SolidTile],
depth: u32,
metadata: DepthMetadata) {
self.depth_metadata.insert(depth as usize, metadata);
for solid_tile in solid_tiles { for solid_tile in solid_tiles {
let tile_index = self.buffer.coords_to_index_unchecked(solid_tile.coords); let tile_index = self.buffer.coords_to_index_unchecked(solid_tile.coords);
let z_dest = &mut self.buffer.data[tile_index as usize]; let z_dest = &mut self.buffer.data[tile_index as usize];
@ -62,8 +71,9 @@ impl ZBuffer {
let tile_coords = self.buffer.index_to_coords(tile_index); let tile_coords = self.buffer.index_to_coords(tile_index);
let paint_id = self.depth_to_paint_id[depth as usize]; let depth_metadata = self.depth_metadata[depth as usize];
let paint_metadata = &paint_metadata[paint_id.0 as usize]; let paint_metadata = &paint_metadata[depth_metadata.paint_id.0 as usize];
let transform = depth_metadata.transform;
let tile_position = tile_coords + self.buffer.rect.origin(); let tile_position = tile_coords + self.buffer.rect.origin();
@ -83,10 +93,16 @@ impl ZBuffer {
let batch = solid_tiles.batches.last_mut().unwrap(); let batch = solid_tiles.batches.last_mut().unwrap();
batch.vertices.extend_from_slice(&[ batch.vertices.extend_from_slice(&[
SolidTileVertex::new(tile_position, paint_metadata), SolidTileVertex::new(tile_position, transform, paint_metadata),
SolidTileVertex::new(tile_position + Vector2I::new(1, 0), paint_metadata), SolidTileVertex::new(tile_position + Vector2I::new(1, 0),
SolidTileVertex::new(tile_position + Vector2I::new(0, 1), paint_metadata), transform,
SolidTileVertex::new(tile_position + Vector2I::new(1, 1), paint_metadata), paint_metadata),
SolidTileVertex::new(tile_position + Vector2I::new(0, 1),
transform,
paint_metadata),
SolidTileVertex::new(tile_position + Vector2I::new(1, 1),
transform,
paint_metadata),
]); ]);
} }
@ -95,8 +111,9 @@ impl ZBuffer {
} }
impl SolidTileVertex { impl SolidTileVertex {
fn new(tile_position: Vector2I, paint_metadata: &PaintMetadata) -> SolidTileVertex { fn new(tile_position: Vector2I, transform: Transform2F, paint_metadata: &PaintMetadata)
let color_uv = paint_metadata.calculate_tex_coords(tile_position); -> SolidTileVertex {
let color_uv = paint_metadata.calculate_tex_coords(tile_position, transform);
SolidTileVertex { SolidTileVertex {
tile_x: tile_position.x() as i16, tile_x: tile_position.x() as i16,
tile_y: tile_position.y() as i16, tile_y: tile_position.y() as i16,

View File

@ -3,6 +3,8 @@
# When you add a new resource, make sure to add it to this file. # When you add a new resource, make sure to add it to this file.
debug-fonts/regular.json debug-fonts/regular.json
shaders/gl3/blit.fs.glsl
shaders/gl3/blit.vs.glsl
shaders/gl3/debug_solid.fs.glsl shaders/gl3/debug_solid.fs.glsl
shaders/gl3/debug_solid.vs.glsl shaders/gl3/debug_solid.vs.glsl
shaders/gl3/debug_texture.fs.glsl shaders/gl3/debug_texture.fs.glsl
@ -11,10 +13,6 @@ shaders/gl3/demo_ground.fs.glsl
shaders/gl3/demo_ground.vs.glsl shaders/gl3/demo_ground.vs.glsl
shaders/gl3/fill.fs.glsl shaders/gl3/fill.fs.glsl
shaders/gl3/fill.vs.glsl shaders/gl3/fill.vs.glsl
shaders/gl3/filter.vs.glsl
shaders/gl3/filter_basic.fs.glsl
shaders/gl3/filter_blur.fs.glsl
shaders/gl3/filter_text.fs.glsl
shaders/gl3/mask.vs.glsl shaders/gl3/mask.vs.glsl
shaders/gl3/mask_evenodd.fs.glsl shaders/gl3/mask_evenodd.fs.glsl
shaders/gl3/mask_winding.fs.glsl shaders/gl3/mask_winding.fs.glsl
@ -37,6 +35,9 @@ shaders/gl3/tile_alpha_overlay.fs.glsl
shaders/gl3/tile_alpha_softlight.fs.glsl shaders/gl3/tile_alpha_softlight.fs.glsl
shaders/gl3/tile_copy.fs.glsl shaders/gl3/tile_copy.fs.glsl
shaders/gl3/tile_copy.vs.glsl shaders/gl3/tile_copy.vs.glsl
shaders/gl3/tile_filter.vs.glsl
shaders/gl3/tile_filter_blur.fs.glsl
shaders/gl3/tile_filter_text.fs.glsl
shaders/gl3/tile_solid.fs.glsl shaders/gl3/tile_solid.fs.glsl
shaders/gl3/tile_solid.vs.glsl shaders/gl3/tile_solid.vs.glsl
shaders/gl3/tile_solid_monochrome.vs.glsl shaders/gl3/tile_solid_monochrome.vs.glsl