Stop reallocating texture pages every frame
This commit is contained in:
parent
07ce2a2536
commit
5819b8dc60
|
@ -16,12 +16,18 @@ use pathfinder_geometry::vector::{Vector2F, Vector2I, vec2f, vec2i};
|
|||
|
||||
const ATLAS_TEXTURE_LENGTH: u32 = 1024;
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct TextureAllocator {
|
||||
pages: Vec<TexturePageAllocator>,
|
||||
pages: Vec<TexturePage>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct TexturePage {
|
||||
allocator: TexturePageAllocator,
|
||||
is_new: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum TexturePageAllocator {
|
||||
// An atlas allocated with our quadtree allocator.
|
||||
Atlas(TextureAtlasAllocator),
|
||||
|
@ -29,13 +35,13 @@ pub enum TexturePageAllocator {
|
|||
Image { size: Vector2I },
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct TextureAtlasAllocator {
|
||||
root: TreeNode,
|
||||
size: u32,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Clone, Debug)]
|
||||
enum TreeNode {
|
||||
EmptyLeaf,
|
||||
FullLeaf,
|
||||
|
@ -65,7 +71,7 @@ impl TextureAllocator {
|
|||
|
||||
// Try to add to each atlas.
|
||||
for (page_index, page) in self.pages.iter_mut().enumerate() {
|
||||
match *page {
|
||||
match page.allocator {
|
||||
TexturePageAllocator::Image { .. } => {}
|
||||
TexturePageAllocator::Atlas(ref mut allocator) => {
|
||||
if let Some(rect) = allocator.allocate(requested_size) {
|
||||
|
@ -79,26 +85,40 @@ impl TextureAllocator {
|
|||
let page = TexturePageId(self.pages.len() as u32);
|
||||
let mut allocator = TextureAtlasAllocator::new();
|
||||
let rect = allocator.allocate(requested_size).expect("Allocation failed!");
|
||||
self.pages.push(TexturePageAllocator::Atlas(allocator));
|
||||
self.pages.push(TexturePage {
|
||||
is_new: true,
|
||||
allocator: TexturePageAllocator::Atlas(allocator),
|
||||
});
|
||||
TextureLocation { page, rect }
|
||||
}
|
||||
|
||||
pub fn allocate_image(&mut self, requested_size: Vector2I) -> TextureLocation {
|
||||
let page = TexturePageId(self.pages.len() as u32);
|
||||
let rect = RectI::new(Vector2I::default(), requested_size);
|
||||
self.pages.push(TexturePageAllocator::Image { size: rect.size() });
|
||||
self.pages.push(TexturePage {
|
||||
is_new: true,
|
||||
allocator: TexturePageAllocator::Image { size: rect.size() },
|
||||
});
|
||||
TextureLocation { page, rect }
|
||||
}
|
||||
|
||||
pub fn page_size(&self, page_index: TexturePageId) -> Vector2I {
|
||||
match self.pages[page_index.0 as usize] {
|
||||
pub fn page_size(&self, page_id: TexturePageId) -> Vector2I {
|
||||
match self.pages[page_id.0 as usize].allocator {
|
||||
TexturePageAllocator::Atlas(ref atlas) => Vector2I::splat(atlas.size as i32),
|
||||
TexturePageAllocator::Image { size, .. } => size,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn page_scale(&self, page_index: TexturePageId) -> Vector2F {
|
||||
vec2f(1.0, 1.0) / self.page_size(page_index).to_f32()
|
||||
pub fn page_scale(&self, page_id: TexturePageId) -> Vector2F {
|
||||
vec2f(1.0, 1.0) / self.page_size(page_id).to_f32()
|
||||
}
|
||||
|
||||
pub fn page_is_new(&self, page_id: TexturePageId) -> bool {
|
||||
self.pages[page_id.0 as usize].is_new
|
||||
}
|
||||
|
||||
pub fn mark_page_as_allocated(&mut self, page_id: TexturePageId) {
|
||||
self.pages[page_id.0 as usize].is_new = false;
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
|
|
@ -35,9 +35,9 @@ use std::sync::atomic::{AtomicUsize, Ordering};
|
|||
use instant::Instant;
|
||||
use std::u32;
|
||||
|
||||
pub(crate) struct SceneBuilder<'a> {
|
||||
scene: &'a Scene,
|
||||
built_options: &'a PreparedBuildOptions,
|
||||
pub(crate) struct SceneBuilder<'a, 'b> {
|
||||
scene: &'a mut Scene,
|
||||
built_options: &'b PreparedBuildOptions,
|
||||
next_alpha_tile_index: AtomicUsize,
|
||||
pub(crate) listener: Box<dyn RenderCommandListener>,
|
||||
}
|
||||
|
@ -87,12 +87,12 @@ pub(crate) struct Occluder {
|
|||
pub(crate) coords: Vector2I,
|
||||
}
|
||||
|
||||
impl<'a> SceneBuilder<'a> {
|
||||
impl<'a, 'b> SceneBuilder<'a, 'b> {
|
||||
pub(crate) fn new(
|
||||
scene: &'a Scene,
|
||||
built_options: &'a PreparedBuildOptions,
|
||||
scene: &'a mut Scene,
|
||||
built_options: &'b PreparedBuildOptions,
|
||||
listener: Box<dyn RenderCommandListener>,
|
||||
) -> SceneBuilder<'a> {
|
||||
) -> SceneBuilder<'a, 'b> {
|
||||
SceneBuilder {
|
||||
scene,
|
||||
built_options,
|
||||
|
@ -120,7 +120,7 @@ impl<'a> SceneBuilder<'a> {
|
|||
});
|
||||
|
||||
let render_transform = match self.built_options.transform {
|
||||
PreparedRenderTransform::Transform2D(tr) => tr.inverse(),
|
||||
PreparedRenderTransform::Transform2D(transform) => transform.inverse(),
|
||||
_ => Transform2F::default()
|
||||
};
|
||||
|
||||
|
|
|
@ -123,7 +123,7 @@ where
|
|||
alpha_tile_pages: Vec<AlphaTilePage<D>>,
|
||||
dest_blend_framebuffer: D::Framebuffer,
|
||||
intermediate_dest_framebuffer: D::Framebuffer,
|
||||
texture_pages: Vec<TexturePage<D>>,
|
||||
texture_pages: Vec<Option<TexturePage<D>>>,
|
||||
render_targets: Vec<RenderTargetInfo>,
|
||||
render_target_stack: Vec<RenderTargetId>,
|
||||
texture_metadata_texture: D::Texture,
|
||||
|
@ -304,8 +304,8 @@ where
|
|||
RenderCommand::Start { bounding_quad, path_count, needs_readable_framebuffer } => {
|
||||
self.start_rendering(bounding_quad, path_count, needs_readable_framebuffer);
|
||||
}
|
||||
RenderCommand::AllocateTexturePages(ref texture_page_descriptors) => {
|
||||
self.allocate_texture_pages(texture_page_descriptors)
|
||||
RenderCommand::AllocateTexturePage { page_id, ref descriptor } => {
|
||||
self.allocate_texture_page(page_id, descriptor)
|
||||
}
|
||||
RenderCommand::UploadTexelData { ref texels, location } => {
|
||||
self.upload_texel_data(texels, location)
|
||||
|
@ -379,6 +379,8 @@ where
|
|||
|
||||
self.flags.set(RendererFlags::INTERMEDIATE_DEST_FRAMEBUFFER_NEEDED,
|
||||
needs_readable_framebuffer);
|
||||
|
||||
self.render_targets.clear();
|
||||
}
|
||||
|
||||
pub fn draw_debug_ui(&self) {
|
||||
|
@ -440,29 +442,37 @@ where
|
|||
&self.quad_vertex_indices_buffer
|
||||
}
|
||||
|
||||
fn allocate_texture_pages(&mut self, texture_page_descriptors: &[TexturePageDescriptor]) {
|
||||
// Clear out old paint textures.
|
||||
for old_texture_page in self.texture_pages.drain(..) {
|
||||
fn allocate_texture_page(&mut self,
|
||||
page_id: TexturePageId,
|
||||
descriptor: &TexturePageDescriptor) {
|
||||
// Fill in IDs up to the requested page ID.
|
||||
let page_index = page_id.0 as usize;
|
||||
while self.texture_pages.len() < page_index + 1 {
|
||||
self.texture_pages.push(None);
|
||||
}
|
||||
|
||||
// Clear out any existing texture.
|
||||
if let Some(old_texture_page) = self.texture_pages[page_index].take() {
|
||||
let old_texture = self.device.destroy_framebuffer(old_texture_page.framebuffer);
|
||||
self.texture_cache.release_texture(old_texture);
|
||||
}
|
||||
|
||||
// Clear out old render targets.
|
||||
self.render_targets.clear();
|
||||
|
||||
// Allocate textures.
|
||||
for texture_page_descriptor in texture_page_descriptors {
|
||||
let texture_size = texture_page_descriptor.size;
|
||||
// Allocate texture.
|
||||
let texture_size = descriptor.size;
|
||||
let texture = self.texture_cache.create_texture(&mut self.device,
|
||||
TextureFormat::RGBA8,
|
||||
texture_size);
|
||||
let framebuffer = self.device.create_framebuffer(texture);
|
||||
self.texture_pages.push(TexturePage { framebuffer, must_preserve_contents: false });
|
||||
}
|
||||
self.texture_pages[page_index] = Some(TexturePage {
|
||||
framebuffer,
|
||||
must_preserve_contents: false,
|
||||
});
|
||||
}
|
||||
|
||||
fn upload_texel_data(&mut self, texels: &[ColorU], location: TextureLocation) {
|
||||
let texture_page = &mut self.texture_pages[location.page.0 as usize];
|
||||
let texture_page = self.texture_pages[location.page.0 as usize]
|
||||
.as_mut()
|
||||
.expect("Texture page not allocated yet!");
|
||||
let texture = self.device.framebuffer_texture(&texture_page.framebuffer);
|
||||
let texels = color::color_slice_to_u8_slice(texels);
|
||||
self.device.upload_to_texture(texture, location.rect, TextureDataRef::U8(texels));
|
||||
|
@ -1024,7 +1034,10 @@ where
|
|||
let must_preserve_contents = match self.render_target_stack.last() {
|
||||
Some(&render_target_id) => {
|
||||
let texture_page = self.render_target_location(render_target_id).page;
|
||||
self.texture_pages[texture_page.0 as usize].must_preserve_contents
|
||||
self.texture_pages[texture_page.0 as usize]
|
||||
.as_ref()
|
||||
.expect("Draw target texture page not allocated!")
|
||||
.must_preserve_contents
|
||||
}
|
||||
None => {
|
||||
self.framebuffer_flags
|
||||
|
@ -1045,7 +1058,10 @@ where
|
|||
match self.render_target_stack.last() {
|
||||
Some(&render_target_id) => {
|
||||
let texture_page = self.render_target_location(render_target_id).page;
|
||||
self.texture_pages[texture_page.0 as usize].must_preserve_contents = true;
|
||||
self.texture_pages[texture_page.0 as usize]
|
||||
.as_mut()
|
||||
.expect("Draw target texture page not allocated!")
|
||||
.must_preserve_contents = true;
|
||||
}
|
||||
None => {
|
||||
self.framebuffer_flags
|
||||
|
@ -1082,7 +1098,10 @@ where
|
|||
}
|
||||
|
||||
fn texture_page_framebuffer(&self, id: TexturePageId) -> &D::Framebuffer {
|
||||
&self.texture_pages[id.0 as usize].framebuffer
|
||||
&self.texture_pages[id.0 as usize]
|
||||
.as_ref()
|
||||
.expect("Texture page not allocated!")
|
||||
.framebuffer
|
||||
}
|
||||
|
||||
fn texture_page(&self, id: TexturePageId) -> &D::Texture {
|
||||
|
|
|
@ -41,8 +41,8 @@ pub enum RenderCommand {
|
|||
needs_readable_framebuffer: bool,
|
||||
},
|
||||
|
||||
// Allocates texture pages for the frame.
|
||||
AllocateTexturePages(Vec<TexturePageDescriptor>),
|
||||
// Allocates a texture page.
|
||||
AllocateTexturePage { page_id: TexturePageId, descriptor: TexturePageDescriptor },
|
||||
|
||||
// Uploads data to a texture page.
|
||||
UploadTexelData { texels: Arc<Vec<ColorU>>, location: TextureLocation },
|
||||
|
@ -81,7 +81,7 @@ pub enum RenderCommand {
|
|||
#[derive(Clone, Copy, PartialEq, Debug, Default)]
|
||||
pub struct TexturePageId(pub u32);
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct TexturePageDescriptor {
|
||||
pub size: Vector2I,
|
||||
}
|
||||
|
@ -190,8 +190,8 @@ impl Debug for RenderCommand {
|
|||
fn fmt(&self, formatter: &mut Formatter) -> DebugResult {
|
||||
match *self {
|
||||
RenderCommand::Start { .. } => write!(formatter, "Start"),
|
||||
RenderCommand::AllocateTexturePages(ref pages) => {
|
||||
write!(formatter, "AllocateTexturePages(x{})", pages.len())
|
||||
RenderCommand::AllocateTexturePage { page_id, descriptor: _ } => {
|
||||
write!(formatter, "AllocateTexturePage({})", page_id.0)
|
||||
}
|
||||
RenderCommand::UploadTexelData { ref texels, location } => {
|
||||
write!(formatter, "UploadTexelData(x{:?}, {:?})", texels.len(), location)
|
||||
|
|
|
@ -34,12 +34,19 @@ const GRADIENT_TILE_LENGTH: u32 = 256;
|
|||
|
||||
#[derive(Clone)]
|
||||
pub struct Palette {
|
||||
pub(crate) paints: Vec<Paint>,
|
||||
pub(crate) render_targets: Vec<RenderTarget>,
|
||||
pub paints: Vec<Paint>,
|
||||
render_targets: Vec<RenderTargetData>,
|
||||
cache: HashMap<Paint, PaintId>,
|
||||
allocator: TextureAllocator,
|
||||
scene_id: SceneId,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct RenderTargetData {
|
||||
render_target: RenderTarget,
|
||||
metadata: RenderTargetMetadata,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
|
||||
pub struct Paint {
|
||||
base_color: ColorU,
|
||||
|
@ -86,7 +93,13 @@ impl Debug for PaintContents {
|
|||
impl Palette {
|
||||
#[inline]
|
||||
pub fn new(scene_id: SceneId) -> Palette {
|
||||
Palette { paints: vec![], render_targets: vec![], cache: HashMap::new(), scene_id }
|
||||
Palette {
|
||||
paints: vec![],
|
||||
render_targets: vec![],
|
||||
cache: HashMap::new(),
|
||||
allocator: TextureAllocator::new(),
|
||||
scene_id,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -305,7 +318,7 @@ pub struct RadialGradientMetadata {
|
|||
pub radii: F32x2,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct RenderTargetMetadata {
|
||||
/// The location of the render target.
|
||||
pub location: TextureLocation,
|
||||
|
@ -338,31 +351,30 @@ impl Palette {
|
|||
|
||||
pub fn push_render_target(&mut self, render_target: RenderTarget) -> RenderTargetId {
|
||||
let id = self.render_targets.len() as u32;
|
||||
self.render_targets.push(render_target);
|
||||
|
||||
let metadata = RenderTargetMetadata {
|
||||
location: self.allocator.allocate_image(render_target.size()),
|
||||
};
|
||||
|
||||
self.render_targets.push(RenderTargetData { render_target, metadata });
|
||||
RenderTargetId { scene: self.scene_id.0, render_target: id }
|
||||
}
|
||||
|
||||
pub fn build_paint_info(&self, render_transform: Transform2F) -> PaintInfo {
|
||||
let mut allocator = TextureAllocator::new();
|
||||
let (mut paint_metadata, mut render_target_metadata) = (vec![], vec![]);
|
||||
|
||||
// Assign render target locations.
|
||||
for render_target in &self.render_targets {
|
||||
render_target_metadata.push(RenderTargetMetadata {
|
||||
location: allocator.allocate_image(render_target.size()),
|
||||
});
|
||||
}
|
||||
pub fn build_paint_info(&mut self, render_transform: Transform2F) -> PaintInfo {
|
||||
let mut paint_metadata = vec![];
|
||||
|
||||
// Assign paint locations.
|
||||
let mut gradient_tile_builder = GradientTileBuilder::new();
|
||||
let mut image_texel_info = vec![];
|
||||
for paint in &self.paints {
|
||||
let allocator = &mut self.allocator;
|
||||
let render_targets = &self.render_targets;
|
||||
let color_texture_metadata = paint.overlay.as_ref().map(|overlay| {
|
||||
match overlay.contents {
|
||||
PaintContents::Gradient(ref gradient) => {
|
||||
// FIXME(pcwalton): The gradient size might not be big enough. Detect this.
|
||||
PaintColorTextureMetadata {
|
||||
location: gradient_tile_builder.allocate(&mut allocator, gradient),
|
||||
location: gradient_tile_builder.allocate(allocator, gradient),
|
||||
sampling_flags: TextureSamplingFlags::empty(),
|
||||
filter: match gradient.radii() {
|
||||
None => PaintFilter::None,
|
||||
|
@ -379,7 +391,7 @@ impl Palette {
|
|||
match *pattern.source() {
|
||||
PatternSource::RenderTarget { id: render_target_id, .. } => {
|
||||
let index = render_target_id.render_target as usize;
|
||||
location = render_target_metadata[index].location;
|
||||
location = render_targets[index].metadata.location;
|
||||
}
|
||||
PatternSource::Image(ref image) => {
|
||||
// TODO(pcwalton): We should be able to use tile cleverness to
|
||||
|
@ -435,7 +447,7 @@ impl Palette {
|
|||
Some(ref mut color_texture_metadata) => color_texture_metadata,
|
||||
};
|
||||
|
||||
let texture_scale = allocator.page_scale(color_texture_metadata.location.page);
|
||||
let texture_scale = self.allocator.page_scale(color_texture_metadata.location.page);
|
||||
let texture_rect = color_texture_metadata.location.rect;
|
||||
color_texture_metadata.transform = match paint.overlay
|
||||
.as_ref()
|
||||
|
@ -487,13 +499,6 @@ impl Palette {
|
|||
}
|
||||
}
|
||||
|
||||
// Allocate textures.
|
||||
let mut texture_page_descriptors = vec![];
|
||||
for page_index in 0..allocator.page_count() {
|
||||
let page_size = allocator.page_size(TexturePageId(page_index));
|
||||
texture_page_descriptors.push(TexturePageDescriptor { size: page_size });
|
||||
}
|
||||
|
||||
// Create texture metadata.
|
||||
let texture_metadata = paint_metadata.iter().map(|paint_metadata| {
|
||||
TextureMetadataEntry {
|
||||
|
@ -504,12 +509,28 @@ impl Palette {
|
|||
base_color: paint_metadata.base_color,
|
||||
}
|
||||
}).collect();
|
||||
let mut render_commands = vec![RenderCommand::UploadTextureMetadata(texture_metadata)];
|
||||
|
||||
// Allocate textures.
|
||||
let mut texture_page_descriptors = vec![];
|
||||
for page_index in 0..self.allocator.page_count() {
|
||||
let page_id = TexturePageId(page_index);
|
||||
let page_size = self.allocator.page_size(page_id);
|
||||
let descriptor = TexturePageDescriptor { size: page_size };
|
||||
texture_page_descriptors.push(descriptor);
|
||||
|
||||
if self.allocator.page_is_new(page_id) {
|
||||
render_commands.push(RenderCommand::AllocateTexturePage { page_id, descriptor });
|
||||
self.allocator.mark_page_as_allocated(page_id);
|
||||
}
|
||||
}
|
||||
|
||||
// Gather up render target metadata.
|
||||
let render_target_metadata: Vec<_> = self.render_targets.iter().map(|render_target_data| {
|
||||
render_target_data.metadata
|
||||
}).collect();
|
||||
|
||||
// Create render commands.
|
||||
let mut render_commands = vec![
|
||||
RenderCommand::UploadTextureMetadata(texture_metadata),
|
||||
RenderCommand::AllocateTexturePages(texture_page_descriptors),
|
||||
];
|
||||
for (index, metadata) in render_target_metadata.iter().enumerate() {
|
||||
let id = RenderTargetId { scene: self.scene_id.0, render_target: index as u32 };
|
||||
render_commands.push(RenderCommand::DeclareRenderTarget {
|
||||
|
@ -527,6 +548,58 @@ impl Palette {
|
|||
|
||||
PaintInfo { render_commands, paint_metadata, render_target_metadata }
|
||||
}
|
||||
|
||||
pub(crate) fn append_palette(&mut self, palette: Palette) -> MergedPaletteInfo {
|
||||
// Merge render targets.
|
||||
let mut render_target_mapping = HashMap::new();
|
||||
for (old_render_target_index, render_target) in palette.render_targets
|
||||
.into_iter()
|
||||
.enumerate() {
|
||||
let old_render_target_id = RenderTargetId {
|
||||
scene: palette.scene_id.0,
|
||||
render_target: old_render_target_index as u32,
|
||||
};
|
||||
let new_render_target_id = self.push_render_target(render_target.render_target);
|
||||
render_target_mapping.insert(old_render_target_id, new_render_target_id);
|
||||
}
|
||||
|
||||
// Merge paints.
|
||||
let mut paint_mapping = HashMap::new();
|
||||
for (old_paint_index, old_paint) in palette.paints.iter().enumerate() {
|
||||
let old_paint_id = PaintId(old_paint_index as u16);
|
||||
let new_paint_id = match *old_paint.overlay() {
|
||||
None => self.push_paint(old_paint),
|
||||
Some(ref overlay) => {
|
||||
match *overlay.contents() {
|
||||
PaintContents::Pattern(ref pattern) => {
|
||||
match pattern.source() {
|
||||
PatternSource::RenderTarget { id: old_render_target_id, size } => {
|
||||
let mut new_pattern =
|
||||
Pattern::from_render_target(*old_render_target_id, *size);
|
||||
new_pattern.set_filter(pattern.filter());
|
||||
new_pattern.apply_transform(pattern.transform());
|
||||
new_pattern.set_repeat_x(pattern.repeat_x());
|
||||
new_pattern.set_repeat_y(pattern.repeat_y());
|
||||
new_pattern.set_smoothing_enabled(pattern.smoothing_enabled());
|
||||
self.push_paint(&Paint::from_pattern(new_pattern))
|
||||
}
|
||||
_ => self.push_paint(old_paint),
|
||||
}
|
||||
}
|
||||
_ => self.push_paint(old_paint),
|
||||
}
|
||||
}
|
||||
};
|
||||
paint_mapping.insert(old_paint_id, new_paint_id);
|
||||
}
|
||||
|
||||
MergedPaletteInfo { render_target_mapping, paint_mapping }
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct MergedPaletteInfo {
|
||||
pub(crate) render_target_mapping: HashMap<RenderTargetId, RenderTargetId>,
|
||||
pub(crate) paint_mapping: HashMap<PaintId, PaintId>,
|
||||
}
|
||||
|
||||
impl PaintMetadata {
|
||||
|
|
|
@ -14,16 +14,14 @@ use crate::builder::SceneBuilder;
|
|||
use crate::concurrent::executor::Executor;
|
||||
use crate::options::{BuildOptions, PreparedBuildOptions};
|
||||
use crate::options::{PreparedRenderTransform, RenderCommandListener};
|
||||
use crate::paint::{Paint, PaintContents, PaintId, PaintInfo, Palette};
|
||||
use crate::paint::{MergedPaletteInfo, Paint, PaintId, PaintInfo, Palette};
|
||||
use pathfinder_content::effects::BlendMode;
|
||||
use pathfinder_content::fill::FillRule;
|
||||
use pathfinder_content::outline::Outline;
|
||||
use pathfinder_content::pattern::{Pattern, PatternSource};
|
||||
use pathfinder_content::render_target::RenderTargetId;
|
||||
use pathfinder_geometry::rect::RectF;
|
||||
use pathfinder_geometry::transform2d::Transform2F;
|
||||
use pathfinder_geometry::vector::{Vector2I, vec2f};
|
||||
use std::collections::HashMap;
|
||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||
|
||||
static NEXT_SCENE_ID: AtomicUsize = AtomicUsize::new(0);
|
||||
|
@ -97,49 +95,10 @@ impl Scene {
|
|||
}
|
||||
|
||||
pub fn append_scene(&mut self, scene: Scene) {
|
||||
// Merge render targets.
|
||||
let mut render_target_mapping = HashMap::new();
|
||||
for (old_render_target_index, render_target) in scene.palette
|
||||
.render_targets
|
||||
.into_iter()
|
||||
.enumerate() {
|
||||
let old_render_target_id = RenderTargetId {
|
||||
scene: scene.id.0,
|
||||
render_target: old_render_target_index as u32,
|
||||
};
|
||||
let new_render_target_id = self.palette.push_render_target(render_target);
|
||||
render_target_mapping.insert(old_render_target_id, new_render_target_id);
|
||||
}
|
||||
|
||||
// Merge paints.
|
||||
let mut paint_mapping = HashMap::new();
|
||||
for (old_paint_index, old_paint) in scene.palette.paints.iter().enumerate() {
|
||||
let old_paint_id = PaintId(old_paint_index as u16);
|
||||
let new_paint_id = match *old_paint.overlay() {
|
||||
None => self.palette.push_paint(old_paint),
|
||||
Some(ref overlay) => {
|
||||
match *overlay.contents() {
|
||||
PaintContents::Pattern(ref pattern) => {
|
||||
match pattern.source() {
|
||||
PatternSource::RenderTarget { id: old_render_target_id, size } => {
|
||||
let mut new_pattern =
|
||||
Pattern::from_render_target(*old_render_target_id, *size);
|
||||
new_pattern.set_filter(pattern.filter());
|
||||
new_pattern.apply_transform(pattern.transform());
|
||||
new_pattern.set_repeat_x(pattern.repeat_x());
|
||||
new_pattern.set_repeat_y(pattern.repeat_y());
|
||||
new_pattern.set_smoothing_enabled(pattern.smoothing_enabled());
|
||||
self.palette.push_paint(&Paint::from_pattern(new_pattern))
|
||||
}
|
||||
_ => self.palette.push_paint(old_paint),
|
||||
}
|
||||
}
|
||||
_ => self.palette.push_paint(old_paint),
|
||||
}
|
||||
}
|
||||
};
|
||||
paint_mapping.insert(old_paint_id, new_paint_id);
|
||||
}
|
||||
let MergedPaletteInfo {
|
||||
render_target_mapping,
|
||||
paint_mapping,
|
||||
} = self.palette.append_palette(scene.palette);
|
||||
|
||||
// Merge clip paths.
|
||||
let mut clip_path_mapping = Vec::with_capacity(scene.clip_paths.len());
|
||||
|
@ -187,7 +146,7 @@ impl Scene {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
pub fn build_paint_info(&self, render_transform: Transform2F) -> PaintInfo {
|
||||
pub fn build_paint_info(&mut self, render_transform: Transform2F) -> PaintInfo {
|
||||
self.palette.build_paint_info(render_transform)
|
||||
}
|
||||
|
||||
|
@ -285,7 +244,7 @@ impl Scene {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
pub fn build<E>(&self,
|
||||
pub fn build<E>(&mut self,
|
||||
options: BuildOptions,
|
||||
listener: Box<dyn RenderCommandListener>,
|
||||
executor: &E)
|
||||
|
|
|
@ -28,8 +28,8 @@ const FLATTENING_TOLERANCE: f32 = 0.1;
|
|||
pub const TILE_WIDTH: u32 = 16;
|
||||
pub const TILE_HEIGHT: u32 = 16;
|
||||
|
||||
pub(crate) struct Tiler<'a> {
|
||||
scene_builder: &'a SceneBuilder<'a>,
|
||||
pub(crate) struct Tiler<'a, 'b> {
|
||||
scene_builder: &'a SceneBuilder<'b, 'a>,
|
||||
pub(crate) object_builder: ObjectBuilder,
|
||||
outline: &'a Outline,
|
||||
path_info: TilingPathInfo<'a>,
|
||||
|
@ -53,15 +53,15 @@ pub(crate) struct DrawTilingPathInfo<'a> {
|
|||
pub(crate) built_clip_path: Option<&'a BuiltPath>,
|
||||
}
|
||||
|
||||
impl<'a> Tiler<'a> {
|
||||
impl<'a, 'b> Tiler<'a, 'b> {
|
||||
#[allow(clippy::or_fun_call)]
|
||||
pub(crate) fn new(
|
||||
scene_builder: &'a SceneBuilder<'a>,
|
||||
scene_builder: &'a SceneBuilder<'b, 'a>,
|
||||
outline: &'a Outline,
|
||||
fill_rule: FillRule,
|
||||
view_box: RectF,
|
||||
path_info: TilingPathInfo<'a>,
|
||||
) -> Tiler<'a> {
|
||||
) -> Tiler<'a, 'b> {
|
||||
let bounds = outline
|
||||
.bounds()
|
||||
.intersection(view_box)
|
||||
|
|
Loading…
Reference in New Issue