Use the texture allocator to allocate solid colors
This commit is contained in:
parent
b8f622203a
commit
1e84ddf1ff
|
@ -47,12 +47,14 @@ impl TextureAllocator {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
#[allow(dead_code)]
|
||||
pub fn free(&mut self, location: TextureLocation) {
|
||||
let requested_length = location.rect.width() as u32;
|
||||
self.root.free(Vector2I::default(), self.size, location.rect.origin(), requested_length)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[allow(dead_code)]
|
||||
pub fn is_empty(&self) -> bool {
|
||||
match self.root {
|
||||
TreeNode::EmptyLeaf => true,
|
||||
|
@ -126,6 +128,7 @@ impl TreeNode {
|
|||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn free(&mut self,
|
||||
this_origin: Vector2I,
|
||||
this_size: u32,
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
use crate::concurrent::executor::Executor;
|
||||
use crate::gpu_data::{AlphaTileBatchPrimitive, BuiltObject, FillBatchPrimitive, RenderCommand};
|
||||
use crate::options::{PreparedBuildOptions, RenderCommandListener};
|
||||
use crate::paint::{PaintInfo, PaintMetadata};
|
||||
use crate::scene::Scene;
|
||||
use crate::tile_map::DenseTileMap;
|
||||
use crate::tiles::{self, TILE_HEIGHT, TILE_WIDTH, Tiler};
|
||||
|
@ -59,14 +60,22 @@ impl<'a> SceneBuilder<'a> {
|
|||
let path_count = self.scene.paths.len();
|
||||
self.listener.send(RenderCommand::Start { bounding_quad, path_count });
|
||||
|
||||
self.listener.send(RenderCommand::AddPaintData(self.scene.build_paint_data()));
|
||||
let PaintInfo {
|
||||
data: paint_data,
|
||||
metadata: paint_metadata,
|
||||
} = self.scene.build_paint_info();
|
||||
self.listener.send(RenderCommand::AddPaintData(paint_data));
|
||||
|
||||
let effective_view_box = self.scene.effective_view_box(self.built_options);
|
||||
let alpha_tiles = executor.flatten_into_vector(path_count, |path_index| {
|
||||
self.build_path(path_index, effective_view_box, &self.built_options, &self.scene)
|
||||
self.build_path(path_index,
|
||||
effective_view_box,
|
||||
&self.built_options,
|
||||
&self.scene,
|
||||
&paint_metadata)
|
||||
});
|
||||
|
||||
self.finish_building(alpha_tiles);
|
||||
self.finish_building(&paint_metadata, alpha_tiles);
|
||||
|
||||
let build_time = Instant::now() - start_time;
|
||||
self.listener.send(RenderCommand::Finish { build_time });
|
||||
|
@ -78,18 +87,17 @@ impl<'a> SceneBuilder<'a> {
|
|||
view_box: RectF,
|
||||
built_options: &PreparedBuildOptions,
|
||||
scene: &Scene,
|
||||
paint_metadata: &[PaintMetadata],
|
||||
) -> Vec<AlphaTileBatchPrimitive> {
|
||||
let path_object = &scene.paths[path_index];
|
||||
let outline = scene.apply_render_options(path_object.outline(), built_options);
|
||||
let paint_id = path_object.paint();
|
||||
let object_is_opaque = scene.paints[paint_id.0 as usize].is_opaque();
|
||||
|
||||
let mut tiler = Tiler::new(self,
|
||||
&outline,
|
||||
view_box,
|
||||
path_index as u16,
|
||||
paint_id,
|
||||
object_is_opaque);
|
||||
&paint_metadata[paint_id.0 as usize]);
|
||||
|
||||
tiler.generate_tiles();
|
||||
|
||||
|
@ -114,9 +122,13 @@ impl<'a> SceneBuilder<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
fn pack_alpha_tiles(&mut self, alpha_tiles: Vec<AlphaTileBatchPrimitive>) {
|
||||
fn pack_alpha_tiles(&mut self,
|
||||
paint_metadata: &[PaintMetadata],
|
||||
alpha_tiles: Vec<AlphaTileBatchPrimitive>) {
|
||||
let path_count = self.scene.paths.len() as u32;
|
||||
let solid_tiles = self.z_buffer.build_solid_tiles(&self.scene.paths, 0..path_count);
|
||||
let solid_tiles = self.z_buffer.build_solid_tiles(&self.scene.paths,
|
||||
paint_metadata,
|
||||
0..path_count);
|
||||
if !solid_tiles.is_empty() {
|
||||
self.listener.send(RenderCommand::SolidTile(solid_tiles));
|
||||
}
|
||||
|
@ -125,10 +137,12 @@ impl<'a> SceneBuilder<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
fn finish_building(&mut self, mut alpha_tiles: Vec<AlphaTileBatchPrimitive>) {
|
||||
fn finish_building(&mut self,
|
||||
paint_metadata: &[PaintMetadata],
|
||||
mut alpha_tiles: Vec<AlphaTileBatchPrimitive>) {
|
||||
self.listener.send(RenderCommand::FlushFills);
|
||||
self.cull_alpha_tiles(&mut alpha_tiles);
|
||||
self.pack_alpha_tiles(alpha_tiles);
|
||||
self.pack_alpha_tiles(paint_metadata, alpha_tiles);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -13,8 +13,8 @@
|
|||
use crate::options::BoundingQuad;
|
||||
use crate::tile_map::DenseTileMap;
|
||||
use pathfinder_geometry::line_segment::{LineSegmentU4, LineSegmentU8};
|
||||
use pathfinder_geometry::vector::Vector2I;
|
||||
use pathfinder_geometry::rect::RectF;
|
||||
use pathfinder_geometry::vector::Vector2I;
|
||||
use std::fmt::{Debug, Formatter, Result as DebugResult};
|
||||
use std::time::Duration;
|
||||
|
||||
|
|
|
@ -8,13 +8,18 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use crate::allocator::{TextureAllocator, TextureLocation};
|
||||
use crate::gpu_data::PaintData;
|
||||
use crate::scene::Scene;
|
||||
use pathfinder_color::ColorU;
|
||||
use pathfinder_geometry::rect::RectI;
|
||||
use pathfinder_geometry::vector::Vector2I;
|
||||
|
||||
const PAINT_TEXTURE_WIDTH: i32 = 256;
|
||||
const PAINT_TEXTURE_HEIGHT: i32 = 256;
|
||||
const PAINT_TEXTURE_LENGTH: u32 = 1024;
|
||||
const PAINT_TEXTURE_SCALE: u32 = 65536 / PAINT_TEXTURE_LENGTH;
|
||||
|
||||
const SOLID_COLOR_TILE_LENGTH: u32 = 16;
|
||||
const MAX_SOLID_COLORS_PER_TILE: u32 = SOLID_COLOR_TILE_LENGTH * SOLID_COLOR_TILE_LENGTH;
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||
pub struct Paint {
|
||||
|
@ -36,22 +41,94 @@ impl Paint {
|
|||
}
|
||||
}
|
||||
|
||||
pub struct PaintInfo {
|
||||
/// The data that is sent to the renderer.
|
||||
pub data: PaintData,
|
||||
/// The metadata for each paint.
|
||||
///
|
||||
/// The indices of this vector are paint IDs.
|
||||
pub metadata: Vec<PaintMetadata>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct PaintMetadata {
|
||||
/// The texture coordinates of each paint, in 24.8 fixed point.
|
||||
pub tex_coords: RectI,
|
||||
/// True if this paint is fully opaque.
|
||||
pub is_opaque: bool,
|
||||
}
|
||||
|
||||
impl Scene {
|
||||
pub fn build_paint_data(&self) -> PaintData {
|
||||
let size = Vector2I::new(PAINT_TEXTURE_WIDTH, PAINT_TEXTURE_HEIGHT);
|
||||
let mut texels = vec![0; size.x() as usize * size.y() as usize * 4];
|
||||
for (paint_index, paint) in self.paints.iter().enumerate() {
|
||||
texels[paint_index * 4 + 0] = paint.color.r;
|
||||
texels[paint_index * 4 + 1] = paint.color.g;
|
||||
texels[paint_index * 4 + 2] = paint.color.b;
|
||||
texels[paint_index * 4 + 3] = paint.color.a;
|
||||
pub fn build_paint_info(&self) -> PaintInfo {
|
||||
let mut allocator = TextureAllocator::new(PAINT_TEXTURE_LENGTH);
|
||||
let area = PAINT_TEXTURE_LENGTH as usize * PAINT_TEXTURE_LENGTH as usize;
|
||||
let (mut texels, mut metadata) = (vec![0; area * 4], vec![]);
|
||||
let mut solid_color_tile_builder = SolidColorTileBuilder::new();
|
||||
|
||||
for paint in &self.paints {
|
||||
// TODO(pcwalton): Handle other paint types.
|
||||
let texture_location = solid_color_tile_builder.allocate(&mut allocator);
|
||||
put_pixel(&mut texels, texture_location.rect.origin(), paint.color);
|
||||
let tex_coords =
|
||||
RectI::new(texture_location.rect.origin().scale(PAINT_TEXTURE_SCALE as i32) +
|
||||
Vector2I::splat(PAINT_TEXTURE_SCALE as i32 / 2),
|
||||
Vector2I::default());
|
||||
metadata.push(PaintMetadata { tex_coords, is_opaque: paint.is_opaque() });
|
||||
}
|
||||
|
||||
let size = Vector2I::splat(PAINT_TEXTURE_LENGTH as i32);
|
||||
return PaintInfo { data: PaintData { size, texels }, metadata };
|
||||
|
||||
fn put_pixel(texels: &mut [u8], position: Vector2I, color: ColorU) {
|
||||
let index = (position.y() as usize * PAINT_TEXTURE_LENGTH as usize +
|
||||
position.x() as usize) * 4;
|
||||
texels[index + 0] = color.r;
|
||||
texels[index + 1] = color.g;
|
||||
texels[index + 2] = color.b;
|
||||
texels[index + 3] = color.a;
|
||||
}
|
||||
PaintData { size, texels }
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn paint_id_to_tex_coords(paint_id: PaintId) -> Vector2I {
|
||||
let tex_coords = Vector2I::new(paint_id.0 as i32 % PAINT_TEXTURE_WIDTH,
|
||||
paint_id.0 as i32 / PAINT_TEXTURE_WIDTH);
|
||||
tex_coords.scale(256) + Vector2I::new(128, 128)
|
||||
struct SolidColorTileBuilder(Option<SolidColorTileBuilderData>);
|
||||
|
||||
struct SolidColorTileBuilderData {
|
||||
tile_location: TextureLocation,
|
||||
next_index: u32,
|
||||
}
|
||||
|
||||
impl SolidColorTileBuilder {
|
||||
fn new() -> SolidColorTileBuilder {
|
||||
SolidColorTileBuilder(None)
|
||||
}
|
||||
|
||||
fn allocate(&mut self, allocator: &mut TextureAllocator) -> TextureLocation {
|
||||
if self.0.is_none() {
|
||||
// TODO(pcwalton): Handle allocation failure gracefully!
|
||||
self.0 = Some(SolidColorTileBuilderData {
|
||||
tile_location: allocator.allocate(Vector2I::splat(SOLID_COLOR_TILE_LENGTH as i32))
|
||||
.expect("Failed to allocate a solid color tile!"),
|
||||
next_index: 0,
|
||||
});
|
||||
}
|
||||
|
||||
let (location, tile_full);
|
||||
{
|
||||
let mut data = self.0.as_mut().unwrap();
|
||||
let subtile_origin = Vector2I::new((data.next_index % SOLID_COLOR_TILE_LENGTH) as i32,
|
||||
(data.next_index / SOLID_COLOR_TILE_LENGTH) as i32);
|
||||
location = TextureLocation {
|
||||
rect: RectI::new(data.tile_location.rect.origin() + subtile_origin,
|
||||
Vector2I::splat(1)),
|
||||
};
|
||||
data.next_index += 1;
|
||||
tile_full = data.next_index == MAX_SOLID_COLORS_PER_TILE;
|
||||
}
|
||||
|
||||
if tile_full {
|
||||
self.0 = None;
|
||||
}
|
||||
|
||||
location
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
use crate::builder::SceneBuilder;
|
||||
use crate::gpu_data::{AlphaTileBatchPrimitive, BuiltObject, TileObjectPrimitive};
|
||||
use crate::paint::{self, PaintId};
|
||||
use crate::paint::PaintMetadata;
|
||||
use crate::sorted_vector::SortedVector;
|
||||
use pathfinder_geometry::line_segment::LineSegment2F;
|
||||
use pathfinder_geometry::vector::{Vector2F, Vector2I};
|
||||
|
@ -30,9 +30,8 @@ pub(crate) struct Tiler<'a> {
|
|||
builder: &'a SceneBuilder<'a>,
|
||||
outline: &'a Outline,
|
||||
pub built_object: BuiltObject,
|
||||
paint_id: PaintId,
|
||||
paint_metadata: &'a PaintMetadata,
|
||||
object_index: u16,
|
||||
object_is_opaque: bool,
|
||||
|
||||
point_queue: SortedVector<QueuedEndpoint>,
|
||||
active_edges: SortedVector<ActiveEdge>,
|
||||
|
@ -46,8 +45,7 @@ impl<'a> Tiler<'a> {
|
|||
outline: &'a Outline,
|
||||
view_box: RectF,
|
||||
object_index: u16,
|
||||
paint_id: PaintId,
|
||||
object_is_opaque: bool,
|
||||
paint_metadata: &'a PaintMetadata,
|
||||
) -> Tiler<'a> {
|
||||
let bounds = outline
|
||||
.bounds()
|
||||
|
@ -60,8 +58,7 @@ impl<'a> Tiler<'a> {
|
|||
outline,
|
||||
built_object,
|
||||
object_index,
|
||||
paint_id,
|
||||
object_is_opaque,
|
||||
paint_metadata,
|
||||
|
||||
point_queue: SortedVector::new(),
|
||||
active_edges: SortedVector::new(),
|
||||
|
@ -122,13 +119,13 @@ impl<'a> Tiler<'a> {
|
|||
}
|
||||
|
||||
// If this is a solid tile, poke it into the Z-buffer and stop here.
|
||||
if self.object_is_opaque {
|
||||
if self.paint_metadata.is_opaque {
|
||||
self.builder.z_buffer.update(tile_coords, self.object_index);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
let origin_uv = paint::paint_id_to_tex_coords(self.paint_id);
|
||||
let origin_uv = self.paint_metadata.tex_coords.origin();
|
||||
|
||||
let alpha_tile = AlphaTileBatchPrimitive::new(
|
||||
tile_coords,
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
//! Software occlusion culling.
|
||||
|
||||
use crate::gpu_data::SolidTileBatchPrimitive;
|
||||
use crate::paint;
|
||||
use crate::paint::PaintMetadata;
|
||||
use crate::scene::PathObject;
|
||||
use crate::tile_map::DenseTileMap;
|
||||
use crate::tiles;
|
||||
|
@ -56,7 +56,10 @@ impl ZBuffer {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn build_solid_tiles(&self, paths: &[PathObject], object_range: Range<u32>)
|
||||
pub fn build_solid_tiles(&self,
|
||||
paths: &[PathObject],
|
||||
paint_metadata: &[PaintMetadata],
|
||||
object_range: Range<u32>)
|
||||
-> Vec<SolidTileBatchPrimitive> {
|
||||
let mut solid_tiles = vec![];
|
||||
for tile_index in 0..self.buffer.data.len() {
|
||||
|
@ -71,7 +74,8 @@ impl ZBuffer {
|
|||
continue;
|
||||
}
|
||||
|
||||
let origin_uv = paint::paint_id_to_tex_coords(paths[object_index as usize].paint());
|
||||
let paint_id = paths[object_index as usize].paint();
|
||||
let origin_uv = paint_metadata[paint_id.0 as usize].tex_coords.origin();
|
||||
|
||||
solid_tiles.push(SolidTileBatchPrimitive::new(tile_coords + self.buffer.rect.origin(),
|
||||
object_index as u16,
|
||||
|
|
Loading…
Reference in New Issue