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.
|
||||
let PaintInfo {
|
||||
data: texture_data,
|
||||
render_commands,
|
||||
metadata: paint_metadata,
|
||||
} = 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);
|
||||
|
||||
|
|
|
@ -20,10 +20,10 @@ use crate::gpu::shaders::{SolidTileVertexArray, StencilProgram, StencilVertexArr
|
|||
use crate::gpu::shaders::{TileFilterBasicProgram, TileFilterBlurProgram, TileFilterProgram};
|
||||
use crate::gpu::shaders::{TileFilterTextProgram, TileFilterVertexArray};
|
||||
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::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::{Effects, Filter};
|
||||
use pathfinder_content::fill::FillRule;
|
||||
|
@ -423,11 +423,20 @@ where
|
|||
}
|
||||
|
||||
pub fn render_command(&mut self, command: &RenderCommand) {
|
||||
println!("{:?}", command);
|
||||
match *command {
|
||||
RenderCommand::Start { 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::FlushFills => {
|
||||
self.draw_buffered_fills();
|
||||
|
@ -570,7 +579,7 @@ where
|
|||
&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.
|
||||
for old_texture_page in self.texture_pages.drain(..) {
|
||||
let old_texture = self.device.destroy_framebuffer(old_texture_page.framebuffer);
|
||||
|
@ -580,33 +589,36 @@ where
|
|||
// Clear out old render targets.
|
||||
self.render_targets.clear();
|
||||
|
||||
// Build up new paint textures and render targets.
|
||||
for texture_page_data in &texture_data.pages {
|
||||
let texture_size = texture_page_data.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,
|
||||
TextureFormat::RGBA8,
|
||||
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);
|
||||
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) {
|
||||
let vertex_array = match fill_rule {
|
||||
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::render_target::RenderTargetId;
|
||||
use pathfinder_geometry::line_segment::{LineSegmentU4, LineSegmentU8};
|
||||
use pathfinder_geometry::rect::RectI;
|
||||
use pathfinder_geometry::vector::Vector2I;
|
||||
use pathfinder_gpu::TextureSamplingFlags;
|
||||
use std::fmt::{Debug, Formatter, Result as DebugResult};
|
||||
|
@ -37,8 +38,16 @@ pub enum RenderCommand {
|
|||
needs_readable_framebuffer: bool,
|
||||
},
|
||||
|
||||
// Uploads texture data for use with subsequent rendering commands to the GPU.
|
||||
AddTextureData(TextureData),
|
||||
// Allocates texture pages for the frame.
|
||||
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.
|
||||
AddFills(Vec<FillBatchPrimitive>),
|
||||
|
@ -73,24 +82,12 @@ pub enum RenderCommand {
|
|||
Finish { build_time: Duration },
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct TextureData {
|
||||
pub pages: Vec<TexturePageData>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Debug)]
|
||||
pub struct TexturePageId(pub u32);
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct TexturePageData {
|
||||
pub struct TexturePageDescriptor {
|
||||
pub size: Vector2I,
|
||||
pub contents: TexturePageContents,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum TexturePageContents {
|
||||
Texels(Vec<ColorU>),
|
||||
RenderTarget(RenderTargetId),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
|
@ -214,8 +211,17 @@ impl Debug for RenderCommand {
|
|||
fn fmt(&self, formatter: &mut Formatter) -> DebugResult {
|
||||
match *self {
|
||||
RenderCommand::Start { .. } => write!(formatter, "Start"),
|
||||
RenderCommand::AddTextureData(ref texture_data) => {
|
||||
write!(formatter, "AddTextureData(x{})", texture_data.pages.len())
|
||||
RenderCommand::AllocateTexturePages(ref pages) => {
|
||||
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::FlushFills => write!(formatter, "FlushFills"),
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
// except according to those terms.
|
||||
|
||||
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::tiles::{TILE_HEIGHT, TILE_WIDTH};
|
||||
use hashbrown::HashMap;
|
||||
|
@ -24,6 +24,7 @@ use pathfinder_geometry::vector::{Vector2F, Vector2I};
|
|||
use pathfinder_gpu::TextureSamplingFlags;
|
||||
use pathfinder_simd::default::{F32x2, F32x4};
|
||||
use std::fmt::{self, Debug, Formatter};
|
||||
use std::mem;
|
||||
|
||||
// The size of a gradient tile.
|
||||
//
|
||||
|
@ -153,8 +154,8 @@ impl Paint {
|
|||
}
|
||||
|
||||
pub struct PaintInfo {
|
||||
/// The data that is sent to the renderer.
|
||||
pub data: TextureData,
|
||||
/// The render commands needed to prepare the textures.
|
||||
pub render_commands: Vec<RenderCommand>,
|
||||
/// The metadata for each paint.
|
||||
///
|
||||
/// The indices of this vector are paint IDs.
|
||||
|
@ -220,8 +221,9 @@ impl Palette {
|
|||
// 1. Use repeating/clamp on the sides.
|
||||
// 2. Choose an optimal size for the gradient that minimizes memory usage while
|
||||
// retaining quality.
|
||||
texture_location = allocator.allocate(Vector2I::splat(GRADIENT_TILE_LENGTH as i32),
|
||||
AllocationMode::Atlas);
|
||||
texture_location =
|
||||
allocator.allocate(Vector2I::splat(GRADIENT_TILE_LENGTH as i32),
|
||||
AllocationMode::Atlas);
|
||||
sampling_flags = TextureSamplingFlags::empty();
|
||||
}
|
||||
Paint::Pattern(ref pattern) => {
|
||||
|
@ -297,67 +299,86 @@ impl Palette {
|
|||
}
|
||||
}
|
||||
|
||||
// Render the actual texels.
|
||||
//
|
||||
// TODO(pcwalton): This is slow. Do more on GPU.
|
||||
let mut texture_data = TextureData { pages: vec![] };
|
||||
// Allocate textures.
|
||||
let mut texture_page_descriptors = vec![];
|
||||
for page_index in 0..allocator.page_count() {
|
||||
let page_index = TexturePageId(page_index);
|
||||
let page_size = allocator.page_size(page_index);
|
||||
if let Some(render_target_id) = allocator.page_render_target_id(page_index) {
|
||||
texture_data.pages.push(TexturePageData {
|
||||
size: page_size,
|
||||
contents: TexturePageContents::RenderTarget(render_target_id),
|
||||
});
|
||||
continue;
|
||||
}
|
||||
|
||||
let page_area = page_size.x() as usize * page_size.y() as usize;
|
||||
let texels = vec![ColorU::default(); page_area];
|
||||
texture_data.pages.push(TexturePageData {
|
||||
size: page_size,
|
||||
contents: TexturePageContents::Texels(texels),
|
||||
});
|
||||
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.
|
||||
let mut page_texels = vec![];
|
||||
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(_) => page_texels.push(vec![]),
|
||||
None => {
|
||||
let page_area = page_size.x() as usize * page_size.y() as usize;
|
||||
page_texels.push(vec![ColorU::default(); page_area]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Draw to texels.
|
||||
//
|
||||
// TODO(pcwalton): Do more of this on GPU.
|
||||
for (paint, metadata) in self.paints.iter().zip(metadata.iter()) {
|
||||
let texture_page = metadata.texture_page;
|
||||
let paint_page_data = &mut texture_data.pages[texture_page.0 as usize];
|
||||
let page_size = paint_page_data.size;
|
||||
let texels = &mut page_texels[texture_page.0 as usize];
|
||||
let page_size = allocator.page_size(texture_page);
|
||||
let page_scale = allocator.page_scale(texture_page);
|
||||
|
||||
match paint_page_data.contents {
|
||||
TexturePageContents::Texels(ref mut texels) => {
|
||||
match paint {
|
||||
Paint::Color(color) => {
|
||||
put_pixel(metadata.texture_rect.origin(), *color, texels, page_size);
|
||||
}
|
||||
Paint::Gradient(ref gradient) => {
|
||||
self.render_gradient(gradient,
|
||||
metadata.texture_rect,
|
||||
&metadata.texture_transform,
|
||||
texels,
|
||||
page_size,
|
||||
page_scale);
|
||||
}
|
||||
Paint::Pattern(ref pattern) => {
|
||||
match pattern.source {
|
||||
PatternSource::RenderTarget(_) => {}
|
||||
PatternSource::Image(ref image) => {
|
||||
self.render_image(image,
|
||||
metadata.texture_rect,
|
||||
texels,
|
||||
page_size);
|
||||
}
|
||||
}
|
||||
match paint {
|
||||
Paint::Color(color) => {
|
||||
put_pixel(metadata.texture_rect.origin(), *color, texels, page_size);
|
||||
}
|
||||
Paint::Gradient(ref gradient) => {
|
||||
self.render_gradient(gradient,
|
||||
metadata.texture_rect,
|
||||
&metadata.texture_transform,
|
||||
texels,
|
||||
page_size,
|
||||
page_scale);
|
||||
}
|
||||
Paint::Pattern(ref pattern) => {
|
||||
match pattern.source {
|
||||
PatternSource::RenderTarget(_) => {}
|
||||
PatternSource::Image(ref image) => {
|
||||
self.render_image(image, 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.
|
||||
|
|
Loading…
Reference in New Issue