Rework the tile builder for D3D11
This commit is contained in:
parent
17356311d6
commit
f92c631f97
|
@ -10,11 +10,13 @@ homepage = "https://github.com/servo/pathfinder"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
bitflags = "1.0"
|
bitflags = "1.0"
|
||||||
|
byte-slice-cast = "0.3"
|
||||||
byteorder = "1.2"
|
byteorder = "1.2"
|
||||||
crossbeam-channel = "0.4"
|
crossbeam-channel = "0.4"
|
||||||
fxhash = "0.2"
|
fxhash = "0.2"
|
||||||
half = "1.5"
|
half = "1.5"
|
||||||
hashbrown = "0.7"
|
hashbrown = "0.7"
|
||||||
|
log = "0.4"
|
||||||
rayon = "1.0"
|
rayon = "1.0"
|
||||||
serde = "1.0"
|
serde = "1.0"
|
||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
|
@ -22,9 +24,6 @@ smallvec = "1.2"
|
||||||
vec_map = "0.8"
|
vec_map = "0.8"
|
||||||
instant = { version = "0.1.2", features = ["wasm-bindgen"] }
|
instant = { version = "0.1.2", features = ["wasm-bindgen"] }
|
||||||
|
|
||||||
[dependencies.log]
|
|
||||||
version = "0.4"
|
|
||||||
|
|
||||||
[dependencies.pathfinder_color]
|
[dependencies.pathfinder_color]
|
||||||
path = "../color"
|
path = "../color"
|
||||||
version = "0.5"
|
version = "0.5"
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -11,35 +11,23 @@
|
||||||
use pathfinder_geometry::rect::RectI;
|
use pathfinder_geometry::rect::RectI;
|
||||||
use pathfinder_geometry::vector::{Vector2I, vec2i};
|
use pathfinder_geometry::vector::{Vector2I, vec2i};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct DenseTileMap<T> {
|
pub struct DenseTileMap<T> where T: Clone + Copy {
|
||||||
pub data: Vec<T>,
|
pub data: Vec<T>,
|
||||||
pub rect: RectI,
|
pub rect: RectI,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> DenseTileMap<T> {
|
impl<T> DenseTileMap<T> where T: Clone + Copy {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn new(rect: RectI) -> DenseTileMap<T>
|
pub fn from_builder<F>(mut build: F, rect: RectI) -> DenseTileMap<T>
|
||||||
where
|
where F: FnMut(Vector2I) -> T {
|
||||||
T: Copy + Clone + Default,
|
let mut data = Vec::with_capacity(rect.size().x() as usize * rect.size().y() as usize);
|
||||||
{
|
for y in rect.min_y()..rect.max_y() {
|
||||||
let length = rect.size().x() as usize * rect.size().y() as usize;
|
for x in rect.min_x()..rect.max_x() {
|
||||||
DenseTileMap {
|
data.push(build(vec2i(x, y)));
|
||||||
data: vec![T::default(); length],
|
}
|
||||||
rect,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn from_builder<F>(build: F, rect: RectI) -> DenseTileMap<T>
|
|
||||||
where
|
|
||||||
F: FnMut(usize) -> T,
|
|
||||||
{
|
|
||||||
let length = rect.size().x() as usize * rect.size().y() as usize;
|
|
||||||
DenseTileMap {
|
|
||||||
data: (0..length).map(build).collect(),
|
|
||||||
rect,
|
|
||||||
}
|
}
|
||||||
|
DenseTileMap { data, rect }
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -47,6 +35,14 @@ impl<T> DenseTileMap<T> {
|
||||||
self.coords_to_index(coords).and_then(|index| self.data.get(index))
|
self.coords_to_index(coords).and_then(|index| self.data.get(index))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn get_mut(&mut self, coords: Vector2I) -> Option<&mut T> {
|
||||||
|
match self.coords_to_index(coords) {
|
||||||
|
None => None,
|
||||||
|
Some(index) => self.data.get_mut(index),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn coords_to_index(&self, coords: Vector2I) -> Option<usize> {
|
pub fn coords_to_index(&self, coords: Vector2I) -> Option<usize> {
|
||||||
if self.rect.contains_point(coords) {
|
if self.rect.contains_point(coords) {
|
||||||
|
|
|
@ -11,8 +11,12 @@
|
||||||
//! Implements the fast lattice-clipping algorithm from Nehab and Hoppe, "Random-Access Rendering
|
//! Implements the fast lattice-clipping algorithm from Nehab and Hoppe, "Random-Access Rendering
|
||||||
//! of General Vector Graphics" 2006.
|
//! of General Vector Graphics" 2006.
|
||||||
|
|
||||||
use crate::builder::{ObjectBuilder, Occluder, SceneBuilder, SolidTiles};
|
use crate::builder::{BuiltPath, BuiltPathBinCPUData, BuiltPathData, ObjectBuilder, SceneBuilder};
|
||||||
use crate::tiles::{PackedTile, TILE_HEIGHT, TILE_WIDTH, TileType, TilingPathInfo};
|
use crate::gpu::options::RendererLevel;
|
||||||
|
use crate::gpu_data::AlphaTileId;
|
||||||
|
use crate::options::PrepareMode;
|
||||||
|
use crate::scene::PathId;
|
||||||
|
use crate::tiles::{DrawTilingPathInfo, TILE_HEIGHT, TILE_WIDTH, TilingPathInfo};
|
||||||
use pathfinder_content::fill::FillRule;
|
use pathfinder_content::fill::FillRule;
|
||||||
use pathfinder_content::outline::{ContourIterFlags, Outline};
|
use pathfinder_content::outline::{ContourIterFlags, Outline};
|
||||||
use pathfinder_content::segment::Segment;
|
use pathfinder_content::segment::Segment;
|
||||||
|
@ -23,102 +27,172 @@ use pathfinder_simd::default::{F32x2, U32x2};
|
||||||
|
|
||||||
const FLATTENING_TOLERANCE: f32 = 0.25;
|
const FLATTENING_TOLERANCE: f32 = 0.25;
|
||||||
|
|
||||||
pub(crate) struct Tiler<'a, 'b> {
|
pub(crate) struct Tiler<'a, 'b, 'c, 'd> {
|
||||||
scene_builder: &'a SceneBuilder<'b, 'a>,
|
scene_builder: &'a SceneBuilder<'b, 'a, 'c, 'd>,
|
||||||
pub(crate) object_builder: ObjectBuilder,
|
pub(crate) object_builder: ObjectBuilder,
|
||||||
outline: &'a Outline,
|
outline: &'a Outline,
|
||||||
path_info: TilingPathInfo<'a>,
|
clip_path: Option<&'a BuiltPath>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'b> Tiler<'a, 'b> {
|
impl<'a, 'b, 'c, 'd> Tiler<'a, 'b, 'c, 'd> {
|
||||||
pub(crate) fn new(scene_builder: &'a SceneBuilder<'b, 'a>,
|
pub(crate) fn new(scene_builder: &'a SceneBuilder<'b, 'a, 'c, 'd>,
|
||||||
|
path_id: PathId,
|
||||||
outline: &'a Outline,
|
outline: &'a Outline,
|
||||||
fill_rule: FillRule,
|
fill_rule: FillRule,
|
||||||
view_box: RectF,
|
view_box: RectF,
|
||||||
path_info: TilingPathInfo<'a>)
|
prepare_mode: &PrepareMode,
|
||||||
-> Tiler<'a, 'b> {
|
built_clip_paths: &'a [BuiltPath],
|
||||||
|
path_info: TilingPathInfo)
|
||||||
|
-> Tiler<'a, 'b, 'c, 'd> {
|
||||||
let bounds = outline.bounds().intersection(view_box).unwrap_or(RectF::default());
|
let bounds = outline.bounds().intersection(view_box).unwrap_or(RectF::default());
|
||||||
let object_builder = ObjectBuilder::new(bounds, view_box, fill_rule, &path_info);
|
|
||||||
Tiler { scene_builder, object_builder, outline, path_info }
|
let clip_path = match path_info {
|
||||||
|
TilingPathInfo::Draw(DrawTilingPathInfo { clip_path_id: Some(clip_path_id), .. }) => {
|
||||||
|
Some(&built_clip_paths[clip_path_id.0 as usize])
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
};
|
||||||
|
|
||||||
|
let object_builder = ObjectBuilder::new(path_id,
|
||||||
|
bounds,
|
||||||
|
view_box,
|
||||||
|
fill_rule,
|
||||||
|
prepare_mode,
|
||||||
|
&path_info);
|
||||||
|
|
||||||
|
Tiler { scene_builder, object_builder, outline, clip_path }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn generate_tiles(&mut self) {
|
pub(crate) fn generate_tiles(&mut self) {
|
||||||
|
match self.object_builder.built_path.data {
|
||||||
|
BuiltPathData::CPU(_) => {
|
||||||
|
self.generate_fills();
|
||||||
|
self.prepare_tiles();
|
||||||
|
}
|
||||||
|
BuiltPathData::TransformCPUBinGPU(ref mut data) => {
|
||||||
|
data.outline = (*self.outline).clone();
|
||||||
|
}
|
||||||
|
BuiltPathData::GPU => {
|
||||||
|
panic!("Shouldn't have generated a tiler at all if we're transforming on GPU!")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn generate_fills(&mut self) {
|
||||||
|
debug_assert_eq!(self.scene_builder.sink.renderer_level, RendererLevel::D3D9);
|
||||||
|
|
||||||
for contour in self.outline.contours() {
|
for contour in self.outline.contours() {
|
||||||
for segment in contour.iter(ContourIterFlags::empty()) {
|
for segment in contour.iter(ContourIterFlags::empty()) {
|
||||||
process_segment(&segment, self.scene_builder, &mut self.object_builder);
|
process_segment(&segment, self.scene_builder, &mut self.object_builder);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.propagate_backdrops();
|
|
||||||
self.pack_and_cull();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn propagate_backdrops(&mut self) {
|
fn prepare_tiles(&mut self) {
|
||||||
let tiles_across = self.object_builder.built_path.tiles.rect.width() as usize;
|
// Don't do this here if the GPU will do it.
|
||||||
for (draw_tile_index, draw_tile) in self.object_builder
|
let (backdrops, tiles, clips) = match self.object_builder.built_path.data {
|
||||||
.built_path
|
BuiltPathData::CPU(ref mut tiled_data) => {
|
||||||
.tiles
|
(&mut tiled_data.backdrops, &mut tiled_data.tiles, &mut tiled_data.clip_tiles)
|
||||||
.data
|
}
|
||||||
.iter_mut()
|
BuiltPathData::TransformCPUBinGPU(_) | BuiltPathData::GPU => {
|
||||||
.enumerate() {
|
panic!("We shouldn't be preparing tiles on CPU!")
|
||||||
let column = draw_tile_index % tiles_across;
|
}
|
||||||
let delta = draw_tile.backdrop;
|
|
||||||
draw_tile.backdrop = self.object_builder.current_backdrops[column];
|
|
||||||
self.object_builder.current_backdrops[column] += delta;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn pack_and_cull(&mut self) {
|
|
||||||
let draw_tiling_path_info = match self.path_info {
|
|
||||||
TilingPathInfo::Clip => return,
|
|
||||||
TilingPathInfo::Draw(draw_tiling_path_info) => draw_tiling_path_info,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let blend_mode_is_destructive = draw_tiling_path_info.blend_mode.is_destructive();
|
// Propagate backdrops.
|
||||||
|
let tiles_across = tiles.rect.width() as usize;
|
||||||
|
for (draw_tile_index, draw_tile) in tiles.data.iter_mut().enumerate() {
|
||||||
|
let tile_coords = vec2i(draw_tile.tile_x as i32, draw_tile.tile_y as i32);
|
||||||
|
let column = draw_tile_index % tiles_across;
|
||||||
|
let delta = draw_tile.backdrop as i32;
|
||||||
|
|
||||||
for (draw_tile_index, draw_tile) in self.object_builder
|
let mut draw_alpha_tile_id = draw_tile.alpha_tile_id;
|
||||||
.built_path
|
let mut draw_tile_backdrop = backdrops[column] as i8;
|
||||||
.tiles
|
|
||||||
.data
|
|
||||||
.iter()
|
|
||||||
.enumerate() {
|
|
||||||
let packed_tile = PackedTile::new(draw_tile_index as u32,
|
|
||||||
draw_tile,
|
|
||||||
&draw_tiling_path_info,
|
|
||||||
&self.object_builder);
|
|
||||||
|
|
||||||
match packed_tile.tile_type {
|
if let Some(built_clip_path) = self.clip_path {
|
||||||
TileType::Solid => {
|
let clip_tiles = match built_clip_path.data {
|
||||||
match self.object_builder.built_path.solid_tiles {
|
BuiltPathData::CPU(BuiltPathBinCPUData { ref tiles, .. }) => tiles,
|
||||||
SolidTiles::Occluders(ref mut occluders) => {
|
_ => unreachable!(),
|
||||||
occluders.push(Occluder::new(packed_tile.tile_coords));
|
};
|
||||||
}
|
match clip_tiles.get(tile_coords) {
|
||||||
SolidTiles::Regular(ref mut solid_tiles) => {
|
Some(clip_tile) => {
|
||||||
packed_tile.add_to(solid_tiles,
|
if clip_tile.alpha_tile_id != AlphaTileId(!0) &&
|
||||||
&mut self.object_builder.built_path.clip_tiles,
|
draw_alpha_tile_id != AlphaTileId(!0) {
|
||||||
&draw_tiling_path_info,
|
// Hard case: We have an alpha tile and a clip tile with masks. Add a
|
||||||
&self.scene_builder);
|
// job to combine the two masks. Because the mask combining step
|
||||||
|
// applies the backdrops, zero out the backdrop in the draw tile itself
|
||||||
|
// so that we don't double-count it.
|
||||||
|
let clip = clips.as_mut()
|
||||||
|
.expect("Where are the clips?")
|
||||||
|
.get_mut(tile_coords)
|
||||||
|
.unwrap();
|
||||||
|
clip.dest_tile_id = draw_tile.alpha_tile_id;
|
||||||
|
clip.dest_backdrop = draw_tile_backdrop as i32;
|
||||||
|
clip.src_tile_id = clip_tile.alpha_tile_id;
|
||||||
|
clip.src_backdrop = clip_tile.backdrop as i32;
|
||||||
|
draw_tile_backdrop = 0;
|
||||||
|
} else if clip_tile.alpha_tile_id != AlphaTileId(!0) &&
|
||||||
|
draw_alpha_tile_id == AlphaTileId(!0) &&
|
||||||
|
draw_tile_backdrop != 0 {
|
||||||
|
// This is a solid draw tile, but there's a clip applied. Replace it
|
||||||
|
// with an alpha tile pointing directly to the clip mask.
|
||||||
|
draw_alpha_tile_id = clip_tile.alpha_tile_id;
|
||||||
|
draw_tile_backdrop = clip_tile.backdrop;
|
||||||
|
} else if clip_tile.alpha_tile_id == AlphaTileId(!0) &&
|
||||||
|
clip_tile.backdrop == 0 {
|
||||||
|
// This is a blank clip tile. Cull the draw tile entirely.
|
||||||
|
draw_alpha_tile_id = AlphaTileId(!0);
|
||||||
|
draw_tile_backdrop = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
None => {
|
||||||
TileType::SingleMask => {
|
// This draw tile is outside the clip path rect. Cull the tile.
|
||||||
debug_assert_ne!(packed_tile.draw_tile.alpha_tile_id.page(), !0);
|
draw_alpha_tile_id = AlphaTileId(!0);
|
||||||
packed_tile.add_to(&mut self.object_builder.built_path.single_mask_tiles,
|
draw_tile_backdrop = 0;
|
||||||
&mut self.object_builder.built_path.clip_tiles,
|
}
|
||||||
&draw_tiling_path_info,
|
|
||||||
&self.scene_builder);
|
|
||||||
}
|
|
||||||
TileType::Empty if blend_mode_is_destructive => {
|
|
||||||
packed_tile.add_to(&mut self.object_builder.built_path.empty_tiles,
|
|
||||||
&mut self.object_builder.built_path.clip_tiles,
|
|
||||||
&draw_tiling_path_info,
|
|
||||||
&self.scene_builder);
|
|
||||||
}
|
|
||||||
TileType::Empty => {
|
|
||||||
// Just cull.
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
draw_tile.alpha_tile_id = draw_alpha_tile_id;
|
||||||
|
draw_tile.backdrop = draw_tile_backdrop;
|
||||||
|
|
||||||
|
backdrops[column] += delta;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
// Calculate clips.
|
||||||
|
let built_clip_path = match self.path_info {
|
||||||
|
TilingPathInfo::Draw(DrawTilingPathInfo {
|
||||||
|
built_clip_path: Some(built_clip_path),
|
||||||
|
..
|
||||||
|
}) => built_clip_path,
|
||||||
|
_ => return,
|
||||||
|
};
|
||||||
|
|
||||||
|
let clip_tiles = self.object_builder
|
||||||
|
.built_path
|
||||||
|
.clip_tiles
|
||||||
|
.as_mut()
|
||||||
|
.expect("Where are the clip tiles?");
|
||||||
|
|
||||||
|
for draw_tile in &mut self.object_builder.built_path.tiles.data {
|
||||||
|
let tile_coords = vec2i(draw_tile.tile_x as i32, draw_tile.tile_y as i32);
|
||||||
|
let built_clip_tile = match built_clip_path.tiles.get(tile_coords) {
|
||||||
|
None => {
|
||||||
|
draw_tile.alpha_tile_id = AlphaTileId(!0);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Some(built_clip_tile) => built_clip_tile,
|
||||||
|
};
|
||||||
|
|
||||||
|
let clip_tile = clip_tiles.get_mut(tile_coords).unwrap();
|
||||||
|
clip_tile.dest_tile_id = draw_tile.alpha_tile_id;
|
||||||
|
clip_tile.dest_backdrop = draw_tile.backdrop as i32;
|
||||||
|
clip_tile.src_tile_id = built_clip_tile.alpha_tile_id;
|
||||||
|
clip_tile.src_backdrop = built_clip_tile.backdrop as i32;
|
||||||
|
}
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -165,8 +239,8 @@ fn process_line_segment(line_segment: LineSegment2F,
|
||||||
// Compute `step = vec2f(vector.x < 0 ? -1 : 1, vector.y < 0 ? -1 : 1)`.
|
// Compute `step = vec2f(vector.x < 0 ? -1 : 1, vector.y < 0 ? -1 : 1)`.
|
||||||
let step = Vector2I((vector_is_negative | U32x2::splat(1)).to_i32x2());
|
let step = Vector2I((vector_is_negative | U32x2::splat(1)).to_i32x2());
|
||||||
|
|
||||||
// Compute `first_tile_crossing = (from_tile_coords + vec2i(vector.x > 0 ? 1 : 0,
|
// Compute `first_tile_crossing = (from_tile_coords + vec2i(vector.x >= 0 ? 1 : 0,
|
||||||
// vector.y > 0 ? 1 : 0)) * tile_size`.
|
// vector.y >= 0 ? 1 : 0)) * tile_size`.
|
||||||
let first_tile_crossing = (from_tile_coords +
|
let first_tile_crossing = (from_tile_coords +
|
||||||
Vector2I((!vector_is_negative & U32x2::splat(1)).to_i32x2())).to_f32() * tile_size;
|
Vector2I((!vector_is_negative & U32x2::splat(1)).to_i32x2())).to_f32() * tile_size;
|
||||||
|
|
||||||
|
|
|
@ -8,33 +8,33 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
use crate::builder::{BuiltPath, ObjectBuilder};
|
use crate::gpu_data::{TILE_CTRL_MASK_0_SHIFT, TILE_CTRL_MASK_EVEN_ODD};
|
||||||
use crate::gpu_data::{AlphaTileId, TileObjectPrimitive};
|
use crate::gpu_data::{TILE_CTRL_MASK_WINDING, TileObjectPrimitive};
|
||||||
use crate::paint::{PaintId, PaintMetadata};
|
use crate::paint::PaintId;
|
||||||
|
use crate::scene::ClipPathId;
|
||||||
use pathfinder_content::effects::BlendMode;
|
use pathfinder_content::effects::BlendMode;
|
||||||
use pathfinder_content::fill::FillRule;
|
use pathfinder_content::fill::FillRule;
|
||||||
use pathfinder_geometry::rect::{RectF, RectI};
|
use pathfinder_geometry::rect::{RectF, RectI};
|
||||||
use pathfinder_geometry::vector::{Vector2I, vec2f};
|
use pathfinder_geometry::vector::vec2f;
|
||||||
|
|
||||||
pub const TILE_WIDTH: u32 = 16;
|
pub const TILE_WIDTH: u32 = 16;
|
||||||
pub const TILE_HEIGHT: u32 = 16;
|
pub const TILE_HEIGHT: u32 = 16;
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub(crate) enum TilingPathInfo<'a> {
|
pub(crate) enum TilingPathInfo {
|
||||||
Clip,
|
Clip,
|
||||||
Draw(DrawTilingPathInfo<'a>),
|
Draw(DrawTilingPathInfo),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub(crate) struct DrawTilingPathInfo<'a> {
|
pub(crate) struct DrawTilingPathInfo {
|
||||||
pub(crate) paint_id: PaintId,
|
pub(crate) paint_id: PaintId,
|
||||||
pub(crate) paint_metadata: &'a PaintMetadata,
|
|
||||||
pub(crate) blend_mode: BlendMode,
|
pub(crate) blend_mode: BlendMode,
|
||||||
pub(crate) built_clip_path: Option<&'a BuiltPath>,
|
|
||||||
pub(crate) fill_rule: FillRule,
|
pub(crate) fill_rule: FillRule,
|
||||||
|
pub(crate) clip_path_id: Option<ClipPathId>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> TilingPathInfo<'a> {
|
impl TilingPathInfo {
|
||||||
pub(crate) fn has_destructive_blend_mode(&self) -> bool {
|
pub(crate) fn has_destructive_blend_mode(&self) -> bool {
|
||||||
match *self {
|
match *self {
|
||||||
TilingPathInfo::Draw(ref draw_tiling_path_info) => {
|
TilingPathInfo::Draw(ref draw_tiling_path_info) => {
|
||||||
|
@ -43,126 +43,23 @@ impl<'a> TilingPathInfo<'a> {
|
||||||
TilingPathInfo::Clip => false,
|
TilingPathInfo::Clip => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) struct PackedTile<'a> {
|
pub(crate) fn to_ctrl(&self) -> u8 {
|
||||||
pub(crate) tile_type: TileType,
|
let mut ctrl = 0;
|
||||||
pub(crate) tile_coords: Vector2I,
|
match *self {
|
||||||
pub(crate) draw_tile: &'a TileObjectPrimitive,
|
TilingPathInfo::Draw(ref draw_tiling_path_info) => {
|
||||||
pub(crate) clip_tile: Option<&'a TileObjectPrimitive>,
|
match draw_tiling_path_info.fill_rule {
|
||||||
}
|
FillRule::EvenOdd => {
|
||||||
|
ctrl |= (TILE_CTRL_MASK_EVEN_ODD << TILE_CTRL_MASK_0_SHIFT) as u8
|
||||||
#[derive(Clone, Copy, PartialEq)]
|
|
||||||
pub(crate) enum TileType {
|
|
||||||
Solid,
|
|
||||||
Empty,
|
|
||||||
SingleMask,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> PackedTile<'a> {
|
|
||||||
pub(crate) fn new(draw_tile_index: u32,
|
|
||||||
draw_tile: &'a TileObjectPrimitive,
|
|
||||||
draw_tiling_path_info: &DrawTilingPathInfo<'a>,
|
|
||||||
object_builder: &ObjectBuilder)
|
|
||||||
-> PackedTile<'a> {
|
|
||||||
let tile_coords = object_builder.local_tile_index_to_coords(draw_tile_index as u32);
|
|
||||||
|
|
||||||
// First, if the draw tile is empty, cull it regardless of clip.
|
|
||||||
if draw_tile.is_solid() {
|
|
||||||
match (object_builder.built_path.fill_rule, draw_tile.backdrop) {
|
|
||||||
(FillRule::Winding, 0) => {
|
|
||||||
return PackedTile {
|
|
||||||
tile_type: TileType::Empty,
|
|
||||||
tile_coords,
|
|
||||||
draw_tile,
|
|
||||||
clip_tile: None,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
(FillRule::Winding, _) => {}
|
|
||||||
(FillRule::EvenOdd, backdrop) if backdrop % 2 == 0 => {
|
|
||||||
return PackedTile {
|
|
||||||
tile_type: TileType::Empty,
|
|
||||||
tile_coords,
|
|
||||||
draw_tile,
|
|
||||||
clip_tile: None,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
(FillRule::EvenOdd, _) => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Figure out what clip tile we need, if any.
|
|
||||||
let clip_tile = match draw_tiling_path_info.built_clip_path {
|
|
||||||
None => None,
|
|
||||||
Some(built_clip_path) => {
|
|
||||||
match built_clip_path.tiles.get(tile_coords) {
|
|
||||||
None => {
|
|
||||||
// This tile is outside of the bounds of the clip path entirely. We can
|
|
||||||
// cull it.
|
|
||||||
return PackedTile {
|
|
||||||
tile_type: TileType::Empty,
|
|
||||||
tile_coords,
|
|
||||||
draw_tile,
|
|
||||||
clip_tile: None,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
Some(clip_tile) if clip_tile.is_solid() => {
|
FillRule::Winding => {
|
||||||
if clip_tile.backdrop != 0 {
|
ctrl |= (TILE_CTRL_MASK_WINDING << TILE_CTRL_MASK_0_SHIFT) as u8
|
||||||
// The clip tile is fully opaque, so this tile isn't clipped at
|
|
||||||
// all.
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
// This tile is completely clipped out. Cull it.
|
|
||||||
return PackedTile {
|
|
||||||
tile_type: TileType::Empty,
|
|
||||||
tile_coords,
|
|
||||||
draw_tile,
|
|
||||||
clip_tile: None,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Some(clip_tile) => Some(clip_tile),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Choose a tile type.
|
|
||||||
match clip_tile {
|
|
||||||
None if draw_tile.is_solid() => {
|
|
||||||
// This is a solid tile that completely occludes the background.
|
|
||||||
PackedTile { tile_type: TileType::Solid, tile_coords, draw_tile, clip_tile }
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
// We have a draw tile and no clip tile.
|
|
||||||
PackedTile {
|
|
||||||
tile_type: TileType::SingleMask,
|
|
||||||
tile_coords,
|
|
||||||
draw_tile,
|
|
||||||
clip_tile: None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Some(clip_tile) if draw_tile.is_solid() => {
|
|
||||||
// We have a solid draw tile and a clip tile. This is effectively the same as
|
|
||||||
// having a draw tile and no clip tile.
|
|
||||||
//
|
|
||||||
// FIXME(pcwalton): This doesn't preserve the fill rule of the clip path!
|
|
||||||
PackedTile {
|
|
||||||
tile_type: TileType::SingleMask,
|
|
||||||
tile_coords,
|
|
||||||
draw_tile: clip_tile,
|
|
||||||
clip_tile: None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Some(clip_tile) => {
|
|
||||||
// We have both a draw and clip mask. Composite them together.
|
|
||||||
PackedTile {
|
|
||||||
tile_type: TileType::SingleMask,
|
|
||||||
tile_coords,
|
|
||||||
draw_tile,
|
|
||||||
clip_tile: Some(clip_tile),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
TilingPathInfo::Clip => {}
|
||||||
}
|
}
|
||||||
|
ctrl
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -170,13 +67,6 @@ pub fn round_rect_out_to_tile_bounds(rect: RectF) -> RectI {
|
||||||
(rect * vec2f(1.0 / TILE_WIDTH as f32, 1.0 / TILE_HEIGHT as f32)).round_out().to_i32()
|
(rect * vec2f(1.0 / TILE_WIDTH as f32, 1.0 / TILE_HEIGHT as f32)).round_out().to_i32()
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for TileObjectPrimitive {
|
|
||||||
#[inline]
|
|
||||||
fn default() -> TileObjectPrimitive {
|
|
||||||
TileObjectPrimitive { backdrop: 0, alpha_tile_id: AlphaTileId::invalid() }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TileObjectPrimitive {
|
impl TileObjectPrimitive {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn is_solid(&self) -> bool { !self.alpha_tile_id.is_valid() }
|
pub fn is_solid(&self) -> bool { !self.alpha_tile_id.is_valid() }
|
||||||
|
|
Loading…
Reference in New Issue