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