diff --git a/renderer/src/builder.rs b/renderer/src/builder.rs index a8c409e3..8695cee3 100644 --- a/renderer/src/builder.rs +++ b/renderer/src/builder.rs @@ -110,10 +110,10 @@ impl<'a> SceneBuilder<'a> { let path_count = self.scene.paths.len() as u32; let solid_tiles = self.z_buffer.build_solid_tiles(0..path_count); if !solid_tiles.is_empty() { - self.listener.send(RenderCommand::SolidTile(solid_tiles)); + self.listener.send(RenderCommand::AddSolidTiles(solid_tiles)); } if !alpha_tiles.is_empty() { - self.listener.send(RenderCommand::AlphaTile(alpha_tiles)); + self.listener.send(RenderCommand::AddAlphaTiles(alpha_tiles)); } } @@ -121,6 +121,8 @@ impl<'a> SceneBuilder<'a> { self.listener.send(RenderCommand::FlushFills); self.cull_alpha_tiles(&mut alpha_tiles); self.pack_alpha_tiles(alpha_tiles); + self.listener.send(RenderCommand::FlushSolidTiles); + self.listener.send(RenderCommand::FlushAlphaTiles); } } diff --git a/renderer/src/gpu/renderer.rs b/renderer/src/gpu/renderer.rs index e08d35d7..1a025795 100644 --- a/renderer/src/gpu/renderer.rs +++ b/renderer/src/gpu/renderer.rs @@ -45,6 +45,8 @@ const FILL_COLORS_TEXTURE_WIDTH: i32 = 256; const FILL_COLORS_TEXTURE_HEIGHT: i32 = 256; const MAX_FILLS_PER_BATCH: usize = 0x4000; +const MAX_ALPHA_TILES_PER_BATCH: usize = 0x4000; +const MAX_SOLID_TILES_PER_BATCH: usize = 0x4000; pub struct Renderer where @@ -87,6 +89,8 @@ where // Rendering state mask_framebuffer_cleared: bool, buffered_fills: Vec, + buffered_alpha_tiles: Vec, + buffered_solid_tiles: Vec, // Debug pub stats: RenderStats, @@ -216,6 +220,8 @@ where mask_framebuffer_cleared: false, buffered_fills: vec![], + buffered_alpha_tiles: vec![], + buffered_solid_tiles: vec![], render_mode: RenderMode::default(), use_depth: false, @@ -236,7 +242,10 @@ where pub fn render_command(&mut self, command: &RenderCommand) { match *command { - RenderCommand::Start { bounding_quad, path_count } => { + RenderCommand::Start { + bounding_quad, + path_count, + } => { if self.use_depth { self.draw_stencil(&bounding_quad); } @@ -248,17 +257,15 @@ where self.begin_composite_timer_query(); self.draw_buffered_fills(); } - RenderCommand::SolidTile(ref solid_tiles) => { - let count = solid_tiles.len(); - self.stats.solid_tile_count += count; - self.upload_solid_tiles(solid_tiles); - self.draw_solid_tiles(count as u32); + RenderCommand::AddSolidTiles(ref solid_tiles) => self.add_solid_tiles(solid_tiles), + RenderCommand::FlushSolidTiles => { + self.begin_composite_timer_query(); + self.draw_buffered_solid_tiles(); } - RenderCommand::AlphaTile(ref alpha_tiles) => { - let count = alpha_tiles.len(); - self.stats.alpha_tile_count += count; - self.upload_alpha_tiles(alpha_tiles); - self.draw_alpha_tiles(count as u32); + RenderCommand::AddAlphaTiles(ref alpha_tiles) => self.add_alpha_tiles(alpha_tiles), + RenderCommand::FlushAlphaTiles => { + self.begin_composite_timer_query(); + self.draw_buffered_alpha_tiles(); } RenderCommand::Finish { .. } => {} } @@ -270,7 +277,8 @@ where } self.end_composite_timer_query(); - self.pending_timers.push_back(mem::replace(&mut self.current_timers, RenderTimers::new())); + self.pending_timers + .push_back(mem::replace(&mut self.current_timers, RenderTimers::new())); } pub fn draw_debug_ui(&self) { @@ -304,7 +312,10 @@ where self.free_timer_queries.extend(timers.stage_0.into_iter()); self.free_timer_queries.push(timers.stage_1.unwrap()); - Some(RenderTime { stage_0: total_stage_0_time, stage_1: stage_1_time }) + Some(RenderTime { + stage_0: total_stage_0_time, + stage_1: stage_1_time, + }) } #[inline] @@ -322,7 +333,9 @@ where #[inline] pub fn set_main_framebuffer_size(&mut self, new_framebuffer_size: Point2DI32) { - self.debug_ui_presenter.ui_presenter.set_framebuffer_size(new_framebuffer_size); + self.debug_ui_presenter + .ui_presenter + .set_framebuffer_size(new_framebuffer_size); } #[inline] @@ -358,24 +371,6 @@ where .upload_to_texture(&self.fill_colors_texture, size, &fill_colors); } - fn upload_solid_tiles(&mut self, solid_tiles: &[SolidTileBatchPrimitive]) { - self.device.allocate_buffer( - &self.solid_tile_vertex_array().vertex_buffer, - BufferData::Memory(&solid_tiles), - BufferTarget::Vertex, - BufferUploadMode::Dynamic, - ); - } - - fn upload_alpha_tiles(&mut self, alpha_tiles: &[AlphaTileBatchPrimitive]) { - self.device.allocate_buffer( - &self.alpha_tile_vertex_array().vertex_buffer, - BufferData::Memory(&alpha_tiles), - BufferTarget::Vertex, - BufferUploadMode::Dynamic, - ); - } - fn clear_mask_framebuffer(&mut self) { self.device.bind_framebuffer(&self.mask_framebuffer); @@ -409,6 +404,60 @@ where self.current_timers.stage_0.push(timer_query); } + fn add_solid_tiles(&mut self, mut solid_tiles: &[SolidTileBatchPrimitive]) { + if solid_tiles.is_empty() { + return; + } + + let timer_query = self.allocate_timer_query(); + self.device.begin_timer_query(&timer_query); + + self.stats.solid_tile_count += solid_tiles.len(); + + while !solid_tiles.is_empty() { + let count = cmp::min( + solid_tiles.len(), + MAX_SOLID_TILES_PER_BATCH - self.buffered_solid_tiles.len(), + ); + self.buffered_solid_tiles + .extend_from_slice(&solid_tiles[0..count]); + solid_tiles = &solid_tiles[count..]; + if self.buffered_solid_tiles.len() == MAX_SOLID_TILES_PER_BATCH { + self.draw_buffered_solid_tiles(); + } + } + + self.device.end_timer_query(&timer_query); + self.current_timers.stage_0.push(timer_query); + } + + fn add_alpha_tiles(&mut self, mut alpha_tiles: &[AlphaTileBatchPrimitive]) { + if alpha_tiles.is_empty() { + return; + } + + let timer_query = self.allocate_timer_query(); + self.device.begin_timer_query(&timer_query); + + self.stats.alpha_tile_count += alpha_tiles.len(); + + while !alpha_tiles.is_empty() { + let count = cmp::min( + alpha_tiles.len(), + MAX_ALPHA_TILES_PER_BATCH - self.buffered_alpha_tiles.len(), + ); + self.buffered_alpha_tiles + .extend_from_slice(&alpha_tiles[0..count]); + alpha_tiles = &alpha_tiles[count..]; + if self.buffered_alpha_tiles.len() == MAX_ALPHA_TILES_PER_BATCH { + self.draw_buffered_alpha_tiles(); + } + } + + self.device.end_timer_query(&timer_query); + self.current_timers.stage_0.push(timer_query); + } + fn draw_buffered_fills(&mut self) { if self.buffered_fills.is_empty() { return; @@ -461,12 +510,24 @@ where self.buffered_fills.clear() } - fn draw_alpha_tiles(&mut self, count: u32) { - self.bind_draw_framebuffer(); + fn draw_buffered_alpha_tiles(&mut self) { + if self.buffered_alpha_tiles.is_empty() { + return; + } let alpha_tile_vertex_array = self.alpha_tile_vertex_array(); + + self.device.allocate_buffer( + &alpha_tile_vertex_array.vertex_buffer, + BufferData::Memory(&self.buffered_alpha_tiles), + BufferTarget::Vertex, + BufferUploadMode::Dynamic, + ); + let alpha_tile_program = self.alpha_tile_program(); + self.bind_draw_framebuffer(); + self.device .bind_vertex_array(&alpha_tile_vertex_array.vertex_array); self.device.use_program(&alpha_tile_program.program); @@ -534,16 +595,35 @@ where stencil: self.stencil_state(), ..RenderState::default() }; - self.device - .draw_arrays_instanced(Primitive::TriangleFan, 4, count, &render_state); + debug_assert!(self.buffered_alpha_tiles.len() <= u32::MAX as usize); + self.device.draw_arrays_instanced( + Primitive::TriangleFan, + 4, + self.buffered_alpha_tiles.len() as u32, + &render_state, + ); + + self.buffered_alpha_tiles.clear(); } - fn draw_solid_tiles(&mut self, count: u32) { - self.bind_draw_framebuffer(); + fn draw_buffered_solid_tiles(&mut self) { + if self.buffered_solid_tiles.is_empty() { + return; + } let solid_tile_vertex_array = self.solid_tile_vertex_array(); + + self.device.allocate_buffer( + &solid_tile_vertex_array.vertex_buffer, + BufferData::Memory(&self.buffered_solid_tiles), + BufferTarget::Vertex, + BufferUploadMode::Dynamic, + ); + let solid_tile_program = self.solid_tile_program(); + self.bind_draw_framebuffer(); + self.device .bind_vertex_array(&solid_tile_vertex_array.vertex_array); self.device.use_program(&solid_tile_program.program); @@ -598,8 +678,15 @@ where stencil: self.stencil_state(), ..RenderState::default() }; - self.device - .draw_arrays_instanced(Primitive::TriangleFan, 4, count, &render_state); + debug_assert!(self.buffered_solid_tiles.len() <= u32::MAX as usize); + self.device.draw_arrays_instanced( + Primitive::TriangleFan, + 4, + self.buffered_solid_tiles.len() as u32, + &render_state, + ); + + self.buffered_solid_tiles.clear(); } fn postprocess(&mut self) { @@ -888,7 +975,11 @@ where } fn end_composite_timer_query(&mut self) { - let query = self.current_timers.stage_1.as_ref().expect("No stage 1 timer query yet?!"); + let query = self + .current_timers + .stage_1 + .as_ref() + .expect("No stage 1 timer query yet?!"); self.device.end_timer_query(&query); } } @@ -1001,7 +1092,17 @@ where alpha_tile_program: &AlphaTileProgram, quad_vertex_positions_buffer: &D::Buffer, ) -> AlphaTileVertexArray { - let (vertex_array, vertex_buffer) = (device.create_vertex_array(), device.create_buffer()); + let vertex_array = device.create_vertex_array(); + + let vertex_buffer = device.create_buffer(); + let vertex_buffer_data: BufferData = + BufferData::Uninitialized(MAX_ALPHA_TILES_PER_BATCH); + device.allocate_buffer( + &vertex_buffer, + vertex_buffer_data, + BufferTarget::Vertex, + BufferUploadMode::Dynamic, + ); let tess_coord_attr = device.get_vertex_attr(&alpha_tile_program.program, "TessCoord"); let tile_origin_attr = device.get_vertex_attr(&alpha_tile_program.program, "TileOrigin"); @@ -1073,7 +1174,17 @@ where solid_tile_program: &SolidTileProgram, quad_vertex_positions_buffer: &D::Buffer, ) -> SolidTileVertexArray { - let (vertex_array, vertex_buffer) = (device.create_vertex_array(), device.create_buffer()); + let vertex_array = device.create_vertex_array(); + + let vertex_buffer = device.create_buffer(); + let vertex_buffer_data: BufferData = + BufferData::Uninitialized(MAX_SOLID_TILES_PER_BATCH); + device.allocate_buffer( + &vertex_buffer, + vertex_buffer_data, + BufferTarget::Vertex, + BufferUploadMode::Dynamic, + ); let tess_coord_attr = device.get_vertex_attr(&solid_tile_program.program, "TessCoord"); let tile_origin_attr = device.get_vertex_attr(&solid_tile_program.program, "TileOrigin"); @@ -1512,7 +1623,10 @@ where #[inline] pub fn full_window(window_size: Point2DI32) -> DestFramebuffer { let viewport = RectI32::new(Point2DI32::default(), window_size); - DestFramebuffer::Default { viewport, window_size } + DestFramebuffer::Default { + viewport, + window_size, + } } fn window_size(&self, device: &D) -> Point2DI32 { @@ -1575,14 +1689,23 @@ impl Div for RenderStats { } } -struct RenderTimers where D: Device { +struct RenderTimers +where + D: Device, +{ stage_0: Vec, stage_1: Option, } -impl RenderTimers where D: Device { +impl RenderTimers +where + D: Device, +{ fn new() -> RenderTimers { - RenderTimers { stage_0: vec![], stage_1: None } + RenderTimers { + stage_0: vec![], + stage_1: None, + } } } @@ -1595,7 +1718,10 @@ pub struct RenderTime { impl Default for RenderTime { #[inline] fn default() -> RenderTime { - RenderTime { stage_0: Duration::new(0, 0), stage_1: Duration::new(0, 0) } + RenderTime { + stage_0: Duration::new(0, 0), + stage_1: Duration::new(0, 0), + } } } diff --git a/renderer/src/gpu_data.rs b/renderer/src/gpu_data.rs index c130abd6..8a998981 100644 --- a/renderer/src/gpu_data.rs +++ b/renderer/src/gpu_data.rs @@ -31,8 +31,10 @@ pub enum RenderCommand { AddShaders(Vec), AddFills(Vec), FlushFills, - AlphaTile(Vec), - SolidTile(Vec), + AddAlphaTiles(Vec), + FlushAlphaTiles, + AddSolidTiles(Vec), + FlushSolidTiles, Finish { build_time: Duration }, } @@ -89,12 +91,14 @@ impl Debug for RenderCommand { } RenderCommand::AddFills(ref fills) => write!(formatter, "AddFills(x{})", fills.len()), RenderCommand::FlushFills => write!(formatter, "FlushFills"), - RenderCommand::AlphaTile(ref tiles) => { - write!(formatter, "AlphaTile(x{})", tiles.len()) + RenderCommand::AddAlphaTiles(ref tiles) => { + write!(formatter, "AddAlphaTiles(x{})", tiles.len()) } - RenderCommand::SolidTile(ref tiles) => { - write!(formatter, "SolidTile(x{})", tiles.len()) + RenderCommand::FlushAlphaTiles => write!(formatter, "FlushAlphaTiles"), + RenderCommand::AddSolidTiles(ref tiles) => { + write!(formatter, "AddSolidTiles(x{})", tiles.len()) } + RenderCommand::FlushSolidTiles => write!(formatter, "FlushSolidTiles"), RenderCommand::Finish { .. } => write!(formatter, "Finish"), } }