Separate the `AddPaintData` render command into different subcommands
This commit is contained in:
parent
e50039f4c2
commit
27357a23d3
|
@ -110,10 +110,12 @@ impl<'a> SceneBuilder<'a> {
|
||||||
|
|
||||||
// Build paint data.
|
// Build paint data.
|
||||||
let PaintInfo {
|
let PaintInfo {
|
||||||
data: texture_data,
|
render_commands,
|
||||||
metadata: paint_metadata,
|
metadata: paint_metadata,
|
||||||
} = self.scene.build_paint_info();
|
} = self.scene.build_paint_info();
|
||||||
self.listener.send(RenderCommand::AddTextureData(texture_data));
|
for render_command in render_commands {
|
||||||
|
self.listener.send(render_command);
|
||||||
|
}
|
||||||
|
|
||||||
let effective_view_box = self.scene.effective_view_box(self.built_options);
|
let effective_view_box = self.scene.effective_view_box(self.built_options);
|
||||||
|
|
||||||
|
|
|
@ -20,10 +20,10 @@ use crate::gpu::shaders::{SolidTileVertexArray, StencilProgram, StencilVertexArr
|
||||||
use crate::gpu::shaders::{TileFilterBasicProgram, TileFilterBlurProgram, TileFilterProgram};
|
use crate::gpu::shaders::{TileFilterBasicProgram, TileFilterBlurProgram, TileFilterProgram};
|
||||||
use crate::gpu::shaders::{TileFilterTextProgram, TileFilterVertexArray};
|
use crate::gpu::shaders::{TileFilterTextProgram, TileFilterVertexArray};
|
||||||
use crate::gpu_data::{AlphaTile, FillBatchPrimitive, MaskTile, RenderCommand, RenderTargetTile};
|
use crate::gpu_data::{AlphaTile, FillBatchPrimitive, MaskTile, RenderCommand, RenderTargetTile};
|
||||||
use crate::gpu_data::{SolidTileVertex, TextureData, TexturePageContents, TexturePageId};
|
use crate::gpu_data::{SolidTileVertex, TexturePageDescriptor, TexturePageId};
|
||||||
use crate::options::BoundingQuad;
|
use crate::options::BoundingQuad;
|
||||||
use crate::tiles::{TILE_HEIGHT, TILE_WIDTH};
|
use crate::tiles::{TILE_HEIGHT, TILE_WIDTH};
|
||||||
use pathfinder_color::{self as color, ColorF};
|
use pathfinder_color::{self as color, ColorF, ColorU};
|
||||||
use pathfinder_content::effects::{BlendMode, BlurDirection, CompositeOp, DefringingKernel};
|
use pathfinder_content::effects::{BlendMode, BlurDirection, CompositeOp, DefringingKernel};
|
||||||
use pathfinder_content::effects::{Effects, Filter};
|
use pathfinder_content::effects::{Effects, Filter};
|
||||||
use pathfinder_content::fill::FillRule;
|
use pathfinder_content::fill::FillRule;
|
||||||
|
@ -423,11 +423,20 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn render_command(&mut self, command: &RenderCommand) {
|
pub fn render_command(&mut self, command: &RenderCommand) {
|
||||||
|
println!("{:?}", command);
|
||||||
match *command {
|
match *command {
|
||||||
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::AddTextureData(ref paint_data) => self.add_texture_data(paint_data),
|
RenderCommand::AllocateTexturePages(ref texture_page_descriptors) => {
|
||||||
|
self.allocate_texture_pages(texture_page_descriptors)
|
||||||
|
}
|
||||||
|
RenderCommand::UploadTexelData { page, ref texels, rect } => {
|
||||||
|
self.upload_texel_data(page, texels, rect)
|
||||||
|
}
|
||||||
|
RenderCommand::DeclareRenderTarget { render_target_id, texture_page_id } => {
|
||||||
|
self.declare_render_target(render_target_id, texture_page_id)
|
||||||
|
}
|
||||||
RenderCommand::AddFills(ref fills) => self.add_fills(fills),
|
RenderCommand::AddFills(ref fills) => self.add_fills(fills),
|
||||||
RenderCommand::FlushFills => {
|
RenderCommand::FlushFills => {
|
||||||
self.draw_buffered_fills();
|
self.draw_buffered_fills();
|
||||||
|
@ -570,7 +579,7 @@ where
|
||||||
&self.quad_vertex_indices_buffer
|
&self.quad_vertex_indices_buffer
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_texture_data(&mut self, texture_data: &TextureData) {
|
fn allocate_texture_pages(&mut self, texture_page_descriptors: &[TexturePageDescriptor]) {
|
||||||
// Clear out old paint textures.
|
// Clear out old paint textures.
|
||||||
for old_texture_page in self.texture_pages.drain(..) {
|
for old_texture_page in self.texture_pages.drain(..) {
|
||||||
let old_texture = self.device.destroy_framebuffer(old_texture_page.framebuffer);
|
let old_texture = self.device.destroy_framebuffer(old_texture_page.framebuffer);
|
||||||
|
@ -580,33 +589,36 @@ where
|
||||||
// Clear out old render targets.
|
// Clear out old render targets.
|
||||||
self.render_targets.clear();
|
self.render_targets.clear();
|
||||||
|
|
||||||
// Build up new paint textures and render targets.
|
// Allocate textures.
|
||||||
for texture_page_data in &texture_data.pages {
|
for texture_page_descriptor in texture_page_descriptors {
|
||||||
let texture_size = texture_page_data.size;
|
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 texture_page_id = TexturePageId(self.texture_pages.len() as u32);
|
|
||||||
let must_preserve_contents;
|
|
||||||
match texture_page_data.contents {
|
|
||||||
TexturePageContents::RenderTarget(render_target_id) => {
|
|
||||||
debug_assert_eq!(render_target_id.0, self.render_targets.len() as u32);
|
|
||||||
self.render_targets.push(RenderTargetInfo { texture_page: texture_page_id });
|
|
||||||
must_preserve_contents = false;
|
|
||||||
}
|
|
||||||
TexturePageContents::Texels(ref texels) => {
|
|
||||||
let texels = color::color_slice_to_u8_slice(texels);
|
|
||||||
self.device.upload_to_texture(&texture,
|
|
||||||
RectI::new(Vector2I::default(), texture_size),
|
|
||||||
TextureDataRef::U8(texels));
|
|
||||||
must_preserve_contents = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let framebuffer = self.device.create_framebuffer(texture);
|
let framebuffer = self.device.create_framebuffer(texture);
|
||||||
self.texture_pages.push(TexturePage { framebuffer, must_preserve_contents });
|
self.texture_pages.push(TexturePage { framebuffer, must_preserve_contents: false });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn upload_texel_data(&mut self, page_id: TexturePageId, texels: &[ColorU], rect: RectI) {
|
||||||
|
let texture_page = &mut self.texture_pages[page_id.0 as usize];
|
||||||
|
let texture = self.device.framebuffer_texture(&texture_page.framebuffer);
|
||||||
|
let texels = color::color_slice_to_u8_slice(texels);
|
||||||
|
self.device.upload_to_texture(texture, rect, TextureDataRef::U8(texels));
|
||||||
|
texture_page.must_preserve_contents = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn declare_render_target(&mut self,
|
||||||
|
render_target_id: RenderTargetId,
|
||||||
|
texture_page_id: TexturePageId) {
|
||||||
|
while self.render_targets.len() < render_target_id.0 as usize + 1 {
|
||||||
|
self.render_targets.push(RenderTargetInfo { texture_page: TexturePageId(!0) });
|
||||||
|
}
|
||||||
|
let mut render_target = &mut self.render_targets[render_target_id.0 as usize];
|
||||||
|
debug_assert_eq!(render_target.texture_page, TexturePageId(!0));
|
||||||
|
render_target.texture_page = texture_page_id;
|
||||||
|
}
|
||||||
|
|
||||||
fn upload_mask_tiles(&mut self, mask_tiles: &[MaskTile], fill_rule: FillRule) {
|
fn upload_mask_tiles(&mut self, mask_tiles: &[MaskTile], fill_rule: FillRule) {
|
||||||
let vertex_array = match fill_rule {
|
let vertex_array = match fill_rule {
|
||||||
FillRule::Winding => &self.mask_winding_tile_vertex_array,
|
FillRule::Winding => &self.mask_winding_tile_vertex_array,
|
||||||
|
|
|
@ -16,6 +16,7 @@ use pathfinder_content::effects::{BlendMode, Effects};
|
||||||
use pathfinder_content::fill::FillRule;
|
use pathfinder_content::fill::FillRule;
|
||||||
use pathfinder_content::render_target::RenderTargetId;
|
use pathfinder_content::render_target::RenderTargetId;
|
||||||
use pathfinder_geometry::line_segment::{LineSegmentU4, LineSegmentU8};
|
use pathfinder_geometry::line_segment::{LineSegmentU4, LineSegmentU8};
|
||||||
|
use pathfinder_geometry::rect::RectI;
|
||||||
use pathfinder_geometry::vector::Vector2I;
|
use pathfinder_geometry::vector::Vector2I;
|
||||||
use pathfinder_gpu::TextureSamplingFlags;
|
use pathfinder_gpu::TextureSamplingFlags;
|
||||||
use std::fmt::{Debug, Formatter, Result as DebugResult};
|
use std::fmt::{Debug, Formatter, Result as DebugResult};
|
||||||
|
@ -37,8 +38,16 @@ pub enum RenderCommand {
|
||||||
needs_readable_framebuffer: bool,
|
needs_readable_framebuffer: bool,
|
||||||
},
|
},
|
||||||
|
|
||||||
// Uploads texture data for use with subsequent rendering commands to the GPU.
|
// Allocates texture pages for the frame.
|
||||||
AddTextureData(TextureData),
|
AllocateTexturePages(Vec<TexturePageDescriptor>),
|
||||||
|
|
||||||
|
// Uploads data to a texture page.
|
||||||
|
UploadTexelData { page: TexturePageId, texels: Vec<ColorU>, rect: RectI },
|
||||||
|
|
||||||
|
// Associates a render target with a texture page.
|
||||||
|
//
|
||||||
|
// TODO(pcwalton): Add a rect to this so we can render to subrects of a page.
|
||||||
|
DeclareRenderTarget { render_target_id: RenderTargetId, texture_page_id: TexturePageId },
|
||||||
|
|
||||||
// Adds fills to the queue.
|
// Adds fills to the queue.
|
||||||
AddFills(Vec<FillBatchPrimitive>),
|
AddFills(Vec<FillBatchPrimitive>),
|
||||||
|
@ -73,24 +82,12 @@ pub enum RenderCommand {
|
||||||
Finish { build_time: Duration },
|
Finish { build_time: Duration },
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
pub struct TextureData {
|
|
||||||
pub pages: Vec<TexturePageData>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq, Debug)]
|
#[derive(Clone, Copy, PartialEq, Debug)]
|
||||||
pub struct TexturePageId(pub u32);
|
pub struct TexturePageId(pub u32);
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct TexturePageData {
|
pub struct TexturePageDescriptor {
|
||||||
pub size: Vector2I,
|
pub size: Vector2I,
|
||||||
pub contents: TexturePageContents,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
pub enum TexturePageContents {
|
|
||||||
Texels(Vec<ColorU>),
|
|
||||||
RenderTarget(RenderTargetId),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
|
@ -214,8 +211,17 @@ 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::AddTextureData(ref texture_data) => {
|
RenderCommand::AllocateTexturePages(ref pages) => {
|
||||||
write!(formatter, "AddTextureData(x{})", texture_data.pages.len())
|
write!(formatter, "AllocateTexturePages(x{})", pages.len())
|
||||||
|
}
|
||||||
|
RenderCommand::UploadTexelData { page, rect, .. } => {
|
||||||
|
write!(formatter, "UploadTexelData({:?}, {:?})", page, rect)
|
||||||
|
}
|
||||||
|
RenderCommand::DeclareRenderTarget { render_target_id, texture_page_id } => {
|
||||||
|
write!(formatter,
|
||||||
|
"DeclareRenderTarget({:?}, {:?})",
|
||||||
|
render_target_id,
|
||||||
|
texture_page_id)
|
||||||
}
|
}
|
||||||
RenderCommand::AddFills(ref fills) => write!(formatter, "AddFills(x{})", fills.len()),
|
RenderCommand::AddFills(ref fills) => write!(formatter, "AddFills(x{})", fills.len()),
|
||||||
RenderCommand::FlushFills => write!(formatter, "FlushFills"),
|
RenderCommand::FlushFills => write!(formatter, "FlushFills"),
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
use crate::allocator::{AllocationMode, TextureAllocator, TextureLocation};
|
use crate::allocator::{AllocationMode, TextureAllocator, TextureLocation};
|
||||||
use crate::gpu_data::{TextureData, TexturePageContents, TexturePageData, TexturePageId};
|
use crate::gpu_data::{RenderCommand, TexturePageDescriptor, TexturePageId};
|
||||||
use crate::scene::RenderTarget;
|
use crate::scene::RenderTarget;
|
||||||
use crate::tiles::{TILE_HEIGHT, TILE_WIDTH};
|
use crate::tiles::{TILE_HEIGHT, TILE_WIDTH};
|
||||||
use hashbrown::HashMap;
|
use hashbrown::HashMap;
|
||||||
|
@ -24,6 +24,7 @@ use pathfinder_geometry::vector::{Vector2F, Vector2I};
|
||||||
use pathfinder_gpu::TextureSamplingFlags;
|
use pathfinder_gpu::TextureSamplingFlags;
|
||||||
use pathfinder_simd::default::{F32x2, F32x4};
|
use pathfinder_simd::default::{F32x2, F32x4};
|
||||||
use std::fmt::{self, Debug, Formatter};
|
use std::fmt::{self, Debug, Formatter};
|
||||||
|
use std::mem;
|
||||||
|
|
||||||
// The size of a gradient tile.
|
// The size of a gradient tile.
|
||||||
//
|
//
|
||||||
|
@ -153,8 +154,8 @@ impl Paint {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct PaintInfo {
|
pub struct PaintInfo {
|
||||||
/// The data that is sent to the renderer.
|
/// The render commands needed to prepare the textures.
|
||||||
pub data: TextureData,
|
pub render_commands: Vec<RenderCommand>,
|
||||||
/// The metadata for each paint.
|
/// The metadata for each paint.
|
||||||
///
|
///
|
||||||
/// The indices of this vector are paint IDs.
|
/// The indices of this vector are paint IDs.
|
||||||
|
@ -220,7 +221,8 @@ impl Palette {
|
||||||
// 1. Use repeating/clamp on the sides.
|
// 1. Use repeating/clamp on the sides.
|
||||||
// 2. Choose an optimal size for the gradient that minimizes memory usage while
|
// 2. Choose an optimal size for the gradient that minimizes memory usage while
|
||||||
// retaining quality.
|
// retaining quality.
|
||||||
texture_location = allocator.allocate(Vector2I::splat(GRADIENT_TILE_LENGTH as i32),
|
texture_location =
|
||||||
|
allocator.allocate(Vector2I::splat(GRADIENT_TILE_LENGTH as i32),
|
||||||
AllocationMode::Atlas);
|
AllocationMode::Atlas);
|
||||||
sampling_flags = TextureSamplingFlags::empty();
|
sampling_flags = TextureSamplingFlags::empty();
|
||||||
}
|
}
|
||||||
|
@ -297,37 +299,38 @@ impl Palette {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Render the actual texels.
|
// 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 });
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allocate the texels.
|
||||||
//
|
//
|
||||||
// TODO(pcwalton): This is slow. Do more on GPU.
|
// TODO(pcwalton): This is slow. Do more on GPU.
|
||||||
let mut texture_data = TextureData { pages: vec![] };
|
let mut page_texels = vec![];
|
||||||
for page_index in 0..allocator.page_count() {
|
for page_index in 0..allocator.page_count() {
|
||||||
let page_index = TexturePageId(page_index);
|
let page_id = TexturePageId(page_index);
|
||||||
let page_size = allocator.page_size(page_index);
|
let page_size = allocator.page_size(page_id);
|
||||||
if let Some(render_target_id) = allocator.page_render_target_id(page_index) {
|
match allocator.page_render_target_id(page_id) {
|
||||||
texture_data.pages.push(TexturePageData {
|
Some(_) => page_texels.push(vec![]),
|
||||||
size: page_size,
|
None => {
|
||||||
contents: TexturePageContents::RenderTarget(render_target_id),
|
|
||||||
});
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
let page_area = page_size.x() as usize * page_size.y() as usize;
|
let page_area = page_size.x() as usize * page_size.y() as usize;
|
||||||
let texels = vec![ColorU::default(); page_area];
|
page_texels.push(vec![ColorU::default(); page_area]);
|
||||||
texture_data.pages.push(TexturePageData {
|
}
|
||||||
size: page_size,
|
}
|
||||||
contents: TexturePageContents::Texels(texels),
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Draw to texels.
|
||||||
|
//
|
||||||
|
// TODO(pcwalton): Do more of this on GPU.
|
||||||
for (paint, metadata) in self.paints.iter().zip(metadata.iter()) {
|
for (paint, metadata) in self.paints.iter().zip(metadata.iter()) {
|
||||||
let texture_page = metadata.texture_page;
|
let texture_page = metadata.texture_page;
|
||||||
let paint_page_data = &mut texture_data.pages[texture_page.0 as usize];
|
let texels = &mut page_texels[texture_page.0 as usize];
|
||||||
let page_size = paint_page_data.size;
|
let page_size = allocator.page_size(texture_page);
|
||||||
let page_scale = allocator.page_scale(texture_page);
|
let page_scale = allocator.page_scale(texture_page);
|
||||||
|
|
||||||
match paint_page_data.contents {
|
|
||||||
TexturePageContents::Texels(ref mut texels) => {
|
|
||||||
match paint {
|
match paint {
|
||||||
Paint::Color(color) => {
|
Paint::Color(color) => {
|
||||||
put_pixel(metadata.texture_rect.origin(), *color, texels, page_size);
|
put_pixel(metadata.texture_rect.origin(), *color, texels, page_size);
|
||||||
|
@ -344,20 +347,38 @@ impl Palette {
|
||||||
match pattern.source {
|
match pattern.source {
|
||||||
PatternSource::RenderTarget(_) => {}
|
PatternSource::RenderTarget(_) => {}
|
||||||
PatternSource::Image(ref image) => {
|
PatternSource::Image(ref image) => {
|
||||||
self.render_image(image,
|
self.render_image(image, metadata.texture_rect, texels, page_size);
|
||||||
metadata.texture_rect,
|
|
||||||
texels,
|
|
||||||
page_size);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TexturePageContents::RenderTarget(_) => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return PaintInfo { data: texture_data, metadata };
|
// Create render commands.
|
||||||
|
let mut render_commands = vec![
|
||||||
|
RenderCommand::AllocateTexturePages(texture_page_descriptors)
|
||||||
|
];
|
||||||
|
for page_index in 0..allocator.page_count() {
|
||||||
|
let page_id = TexturePageId(page_index);
|
||||||
|
let page_size = allocator.page_size(page_id);
|
||||||
|
match allocator.page_render_target_id(page_id) {
|
||||||
|
Some(render_target_id) => {
|
||||||
|
render_commands.push(RenderCommand::DeclareRenderTarget {
|
||||||
|
render_target_id,
|
||||||
|
texture_page_id: page_id,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
render_commands.push(RenderCommand::UploadTexelData {
|
||||||
|
page: page_id,
|
||||||
|
texels: mem::replace(&mut page_texels[page_index as usize], vec![]),
|
||||||
|
rect: RectI::new(Vector2I::default(), page_size),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PaintInfo { render_commands, metadata }
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(pcwalton): This is slow. Do on GPU instead.
|
// TODO(pcwalton): This is slow. Do on GPU instead.
|
||||||
|
|
Loading…
Reference in New Issue