From 5fa931a5f8a6ce7ef1cd9839f94380e033009dab Mon Sep 17 00:00:00 2001 From: John Tur Date: Tue, 3 Feb 2026 17:15:44 -0500 Subject: [PATCH] Optimize resource upload in D3D11 (#48282) Currently, each time we draw a primitive batch, we fully overwrite the instance buffer with the contents of the new batch. Since we use a write-only mapping to do this, the GPU driver may handle synchronization hazards by transparently creating new allocations if the previous allocation is still in use. We draw many primitive batches in one frame, which stress-tests this mechanism somewhat. If internal driver limits are hit, the resource update will start to block until the GPU catches up and releases in-use allocations. This would result in a significant reduction in framerate. To avoid this, we upload the data for all primitive batches at once at the beginning of the frame. Each primitive batch draw then binds the relevant sub-array of the instance buffer. This way, there are no mid-frame resource updates. Release Notes: - N/A --- .../gpui/src/platform/blade/blade_renderer.rs | 33 ++- .../gpui/src/platform/mac/metal_renderer.rs | 59 ++-- .../src/platform/windows/directx_renderer.rs | 266 +++++++++++++----- crates/gpui/src/scene.rs | 62 ++-- 4 files changed, 256 insertions(+), 164 deletions(-) diff --git a/crates/gpui/src/platform/blade/blade_renderer.rs b/crates/gpui/src/platform/blade/blade_renderer.rs index bfcb21d5f9..4d1afa1763 100644 --- a/crates/gpui/src/platform/blade/blade_renderer.rs +++ b/crates/gpui/src/platform/blade/blade_renderer.rs @@ -719,7 +719,8 @@ impl BladeRenderer { profiling::scope!("render pass"); for batch in scene.batches() { match batch { - PrimitiveBatch::Quads(quads) => { + PrimitiveBatch::Quads(range) => { + let quads = &scene.quads[range]; let instance_buf = unsafe { self.instance_belt.alloc_typed(quads, &self.gpu) }; let mut encoder = pass.with(&self.pipelines.quads); encoder.bind( @@ -731,7 +732,8 @@ impl BladeRenderer { ); encoder.draw(0, 4, 0, quads.len() as u32); } - PrimitiveBatch::Shadows(shadows) => { + PrimitiveBatch::Shadows(range) => { + let shadows = &scene.shadows[range]; let instance_buf = unsafe { self.instance_belt.alloc_typed(shadows, &self.gpu) }; let mut encoder = pass.with(&self.pipelines.shadows); @@ -744,7 +746,8 @@ impl BladeRenderer { ); encoder.draw(0, 4, 0, shadows.len() as u32); } - PrimitiveBatch::Paths(paths) => { + PrimitiveBatch::Paths(range) => { + let paths = &scene.paths[range]; let Some(first_path) = paths.first() else { continue; }; @@ -800,7 +803,8 @@ impl BladeRenderer { ); encoder.draw(0, 4, 0, sprites.len() as u32); } - PrimitiveBatch::Underlines(underlines) => { + PrimitiveBatch::Underlines(range) => { + let underlines = &scene.underlines[range]; let instance_buf = unsafe { self.instance_belt.alloc_typed(underlines, &self.gpu) }; let mut encoder = pass.with(&self.pipelines.underlines); @@ -813,10 +817,8 @@ impl BladeRenderer { ); encoder.draw(0, 4, 0, underlines.len() as u32); } - PrimitiveBatch::MonochromeSprites { - texture_id, - sprites, - } => { + PrimitiveBatch::MonochromeSprites { texture_id, range } => { + let sprites = &scene.monochrome_sprites[range]; let tex_info = self.atlas.get_texture_info(texture_id); let instance_buf = unsafe { self.instance_belt.alloc_typed(sprites, &self.gpu) }; @@ -836,10 +838,8 @@ impl BladeRenderer { ); encoder.draw(0, 4, 0, sprites.len() as u32); } - PrimitiveBatch::PolychromeSprites { - texture_id, - sprites, - } => { + PrimitiveBatch::PolychromeSprites { texture_id, range } => { + let sprites = &scene.polychrome_sprites[range]; let tex_info = self.atlas.get_texture_info(texture_id); let instance_buf = unsafe { self.instance_belt.alloc_typed(sprites, &self.gpu) }; @@ -855,10 +855,8 @@ impl BladeRenderer { ); encoder.draw(0, 4, 0, sprites.len() as u32); } - PrimitiveBatch::SubpixelSprites { - texture_id, - sprites, - } => { + PrimitiveBatch::SubpixelSprites { texture_id, range } => { + let sprites = &scene.subpixel_sprites[range]; let tex_info = self.atlas.get_texture_info(texture_id); let instance_buf = unsafe { self.instance_belt.alloc_typed(sprites, &self.gpu) }; @@ -878,7 +876,8 @@ impl BladeRenderer { ); encoder.draw(0, 4, 0, sprites.len() as u32); } - PrimitiveBatch::Surfaces(surfaces) => { + PrimitiveBatch::Surfaces(range) => { + let surfaces = &scene.surfaces[range]; let mut _encoder = pass.with(&self.pipelines.surfaces); for surface in surfaces { diff --git a/crates/gpui/src/platform/mac/metal_renderer.rs b/crates/gpui/src/platform/mac/metal_renderer.rs index 07e7cdd276..e33b1169f1 100644 --- a/crates/gpui/src/platform/mac/metal_renderer.rs +++ b/crates/gpui/src/platform/mac/metal_renderer.rs @@ -548,21 +548,22 @@ impl MetalRenderer { for batch in scene.batches() { let ok = match batch { - PrimitiveBatch::Shadows(shadows) => self.draw_shadows( - shadows, + PrimitiveBatch::Shadows(range) => self.draw_shadows( + &scene.shadows[range], instance_buffer, &mut instance_offset, viewport_size, command_encoder, ), - PrimitiveBatch::Quads(quads) => self.draw_quads( - quads, + PrimitiveBatch::Quads(range) => self.draw_quads( + &scene.quads[range], instance_buffer, &mut instance_offset, viewport_size, command_encoder, ), - PrimitiveBatch::Paths(paths) => { + PrimitiveBatch::Paths(range) => { + let paths = &scene.paths[range]; command_encoder.end_encoding(); let did_draw = self.draw_paths_to_intermediate( @@ -594,37 +595,33 @@ impl MetalRenderer { false } } - PrimitiveBatch::Underlines(underlines) => self.draw_underlines( - underlines, + PrimitiveBatch::Underlines(range) => self.draw_underlines( + &scene.underlines[range], instance_buffer, &mut instance_offset, viewport_size, command_encoder, ), - PrimitiveBatch::MonochromeSprites { - texture_id, - sprites, - } => self.draw_monochrome_sprites( - texture_id, - sprites, - instance_buffer, - &mut instance_offset, - viewport_size, - command_encoder, - ), - PrimitiveBatch::PolychromeSprites { - texture_id, - sprites, - } => self.draw_polychrome_sprites( - texture_id, - sprites, - instance_buffer, - &mut instance_offset, - viewport_size, - command_encoder, - ), - PrimitiveBatch::Surfaces(surfaces) => self.draw_surfaces( - surfaces, + PrimitiveBatch::MonochromeSprites { texture_id, range } => self + .draw_monochrome_sprites( + texture_id, + &scene.monochrome_sprites[range], + instance_buffer, + &mut instance_offset, + viewport_size, + command_encoder, + ), + PrimitiveBatch::PolychromeSprites { texture_id, range } => self + .draw_polychrome_sprites( + texture_id, + &scene.polychrome_sprites[range], + instance_buffer, + &mut instance_offset, + viewport_size, + command_encoder, + ), + PrimitiveBatch::Surfaces(range) => self.draw_surfaces( + &scene.surfaces[range], instance_buffer, &mut instance_offset, viewport_size, diff --git a/crates/gpui/src/platform/windows/directx_renderer.rs b/crates/gpui/src/platform/windows/directx_renderer.rs index 443ea14243..8e7a0ac142 100644 --- a/crates/gpui/src/platform/windows/directx_renderer.rs +++ b/crates/gpui/src/platform/windows/directx_renderer.rs @@ -315,28 +315,29 @@ impl DirectXRenderer { WindowBackgroundAppearance::Opaque => [1.0f32; 4], _ => [0.0f32; 4], })?; + + self.upload_scene_buffers(scene)?; + for batch in scene.batches() { match batch { - PrimitiveBatch::Shadows(shadows) => self.draw_shadows(shadows), - PrimitiveBatch::Quads(quads) => self.draw_quads(quads), - PrimitiveBatch::Paths(paths) => { + PrimitiveBatch::Shadows(range) => self.draw_shadows(range.start, range.len()), + PrimitiveBatch::Quads(range) => self.draw_quads(range.start, range.len()), + PrimitiveBatch::Paths(range) => { + let paths = &scene.paths[range]; self.draw_paths_to_intermediate(paths)?; self.draw_paths_from_intermediate(paths) } - PrimitiveBatch::Underlines(underlines) => self.draw_underlines(underlines), - PrimitiveBatch::MonochromeSprites { - texture_id, - sprites, - } => self.draw_monochrome_sprites(texture_id, sprites), - PrimitiveBatch::SubpixelSprites { - texture_id, - sprites, - } => self.draw_subpixel_sprites(texture_id, sprites), - PrimitiveBatch::PolychromeSprites { - texture_id, - sprites, - } => self.draw_polychrome_sprites(texture_id, sprites), - PrimitiveBatch::Surfaces(surfaces) => self.draw_surfaces(surfaces), + PrimitiveBatch::Underlines(range) => self.draw_underlines(range.start, range.len()), + PrimitiveBatch::MonochromeSprites { texture_id, range } => { + self.draw_monochrome_sprites(texture_id, range.start, range.len()) + } + PrimitiveBatch::SubpixelSprites { texture_id, range } => { + self.draw_subpixel_sprites(texture_id, range.start, range.len()) + } + PrimitiveBatch::PolychromeSprites { texture_id, range } => { + self.draw_polychrome_sprites(texture_id, range.start, range.len()) + } + PrimitiveBatch::Surfaces(range) => self.draw_surfaces(&scene.surfaces[range]), } .context(format!( "scene too large:\ @@ -398,17 +399,67 @@ impl DirectXRenderer { Ok(()) } - fn draw_shadows(&mut self, shadows: &[Shadow]) -> Result<()> { - if shadows.is_empty() { + fn upload_scene_buffers(&mut self, scene: &Scene) -> Result<()> { + let devices = self.devices.as_ref().context("devices missing")?; + + if !scene.shadows.is_empty() { + self.pipelines.shadow_pipeline.update_buffer( + &devices.device, + &devices.device_context, + &scene.shadows, + )?; + } + + if !scene.quads.is_empty() { + self.pipelines.quad_pipeline.update_buffer( + &devices.device, + &devices.device_context, + &scene.quads, + )?; + } + + if !scene.underlines.is_empty() { + self.pipelines.underline_pipeline.update_buffer( + &devices.device, + &devices.device_context, + &scene.underlines, + )?; + } + + if !scene.monochrome_sprites.is_empty() { + self.pipelines.mono_sprites.update_buffer( + &devices.device, + &devices.device_context, + &scene.monochrome_sprites, + )?; + } + + if !scene.subpixel_sprites.is_empty() { + self.pipelines.subpixel_sprites.update_buffer( + &devices.device, + &devices.device_context, + &scene.subpixel_sprites, + )?; + } + + if !scene.polychrome_sprites.is_empty() { + self.pipelines.poly_sprites.update_buffer( + &devices.device, + &devices.device_context, + &scene.polychrome_sprites, + )?; + } + + Ok(()) + } + + fn draw_shadows(&mut self, start: usize, len: usize) -> Result<()> { + if len == 0 { return Ok(()); } let devices = self.devices.as_ref().context("devices missing")?; - self.pipelines.shadow_pipeline.update_buffer( + self.pipelines.shadow_pipeline.draw_range( &devices.device, - &devices.device_context, - shadows, - )?; - self.pipelines.shadow_pipeline.draw( &devices.device_context, slice::from_ref( &self @@ -418,23 +469,19 @@ impl DirectXRenderer { .viewport, ), slice::from_ref(&self.globals.global_params_buffer), - D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP, 4, - shadows.len() as u32, + start as u32, + len as u32, ) } - fn draw_quads(&mut self, quads: &[Quad]) -> Result<()> { - if quads.is_empty() { + fn draw_quads(&mut self, start: usize, len: usize) -> Result<()> { + if len == 0 { return Ok(()); } let devices = self.devices.as_ref().context("devices missing")?; - self.pipelines.quad_pipeline.update_buffer( + self.pipelines.quad_pipeline.draw_range( &devices.device, - &devices.device_context, - quads, - )?; - self.pipelines.quad_pipeline.draw( &devices.device_context, slice::from_ref( &self @@ -444,9 +491,9 @@ impl DirectXRenderer { .viewport, ), slice::from_ref(&self.globals.global_params_buffer), - D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP, 4, - quads.len() as u32, + start as u32, + len as u32, ) } @@ -561,105 +608,92 @@ impl DirectXRenderer { ) } - fn draw_underlines(&mut self, underlines: &[Underline]) -> Result<()> { - if underlines.is_empty() { + fn draw_underlines(&mut self, start: usize, len: usize) -> Result<()> { + if len == 0 { return Ok(()); } let devices = self.devices.as_ref().context("devices missing")?; let resources = self.resources.as_ref().context("resources missing")?; - self.pipelines.underline_pipeline.update_buffer( + self.pipelines.underline_pipeline.draw_range( &devices.device, - &devices.device_context, - underlines, - )?; - self.pipelines.underline_pipeline.draw( &devices.device_context, slice::from_ref(&resources.viewport), slice::from_ref(&self.globals.global_params_buffer), - D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP, 4, - underlines.len() as u32, + start as u32, + len as u32, ) } fn draw_monochrome_sprites( &mut self, texture_id: AtlasTextureId, - sprites: &[MonochromeSprite], + start: usize, + len: usize, ) -> Result<()> { - if sprites.is_empty() { + if len == 0 { return Ok(()); } let devices = self.devices.as_ref().context("devices missing")?; let resources = self.resources.as_ref().context("resources missing")?; - - self.pipelines.mono_sprites.update_buffer( - &devices.device, - &devices.device_context, - sprites, - )?; let texture_view = self.atlas.get_texture_view(texture_id); - self.pipelines.mono_sprites.draw_with_texture( + self.pipelines.mono_sprites.draw_range_with_texture( + &devices.device, &devices.device_context, &texture_view, slice::from_ref(&resources.viewport), slice::from_ref(&self.globals.global_params_buffer), slice::from_ref(&self.globals.sampler), - sprites.len() as u32, + start as u32, + len as u32, ) } fn draw_subpixel_sprites( &mut self, texture_id: AtlasTextureId, - sprites: &[SubpixelSprite], + start: usize, + len: usize, ) -> Result<()> { - if sprites.is_empty() { + if len == 0 { return Ok(()); } let devices = self.devices.as_ref().context("devices missing")?; let resources = self.resources.as_ref().context("resources missing")?; - - self.pipelines.subpixel_sprites.update_buffer( - &devices.device, - &devices.device_context, - &sprites, - )?; let texture_view = self.atlas.get_texture_view(texture_id); - self.pipelines.subpixel_sprites.draw_with_texture( + self.pipelines.subpixel_sprites.draw_range_with_texture( + &devices.device, &devices.device_context, &texture_view, slice::from_ref(&resources.viewport), slice::from_ref(&self.globals.global_params_buffer), slice::from_ref(&self.globals.sampler), - sprites.len() as u32, + start as u32, + len as u32, ) } fn draw_polychrome_sprites( &mut self, texture_id: AtlasTextureId, - sprites: &[PolychromeSprite], + start: usize, + len: usize, ) -> Result<()> { - if sprites.is_empty() { + if len == 0 { return Ok(()); } - let devices = self.devices.as_ref().context("devices missing")?; let resources = self.resources.as_ref().context("resources missing")?; - self.pipelines.poly_sprites.update_buffer( - &devices.device, - &devices.device_context, - sprites, - )?; let texture_view = self.atlas.get_texture_view(texture_id); - self.pipelines.poly_sprites.draw_with_texture( + self.pipelines.poly_sprites.draw_range_with_texture( + &devices.device, &devices.device_context, &texture_view, slice::from_ref(&resources.viewport), slice::from_ref(&self.globals.global_params_buffer), slice::from_ref(&self.globals.sampler), - sprites.len() as u32, + start as u32, + len as u32, ) } @@ -1050,6 +1084,64 @@ impl PipelineState { } Ok(()) } + + fn draw_range( + &self, + device: &ID3D11Device, + device_context: &ID3D11DeviceContext, + viewport: &[D3D11_VIEWPORT], + global_params: &[Option], + vertex_count: u32, + first_instance: u32, + instance_count: u32, + ) -> Result<()> { + let view = create_buffer_view_range(device, &self.buffer, first_instance, instance_count)?; + set_pipeline_state( + device_context, + slice::from_ref(&view), + D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP, + viewport, + &self.vertex, + &self.fragment, + global_params, + &self.blend_state, + ); + unsafe { + device_context.DrawInstanced(vertex_count, instance_count, 0, 0); + } + Ok(()) + } + + fn draw_range_with_texture( + &self, + device: &ID3D11Device, + device_context: &ID3D11DeviceContext, + texture: &[Option], + viewport: &[D3D11_VIEWPORT], + global_params: &[Option], + sampler: &[Option], + first_instance: u32, + instance_count: u32, + ) -> Result<()> { + let view = create_buffer_view_range(device, &self.buffer, first_instance, instance_count)?; + set_pipeline_state( + device_context, + slice::from_ref(&view), + D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP, + viewport, + &self.vertex, + &self.fragment, + global_params, + &self.blend_state, + ); + unsafe { + device_context.PSSetSamplers(0, Some(sampler)); + device_context.VSSetShaderResources(0, Some(texture)); + device_context.PSSetShaderResources(0, Some(texture)); + device_context.DrawInstanced(4, instance_count, 0, 0); + } + Ok(()) + } } #[derive(Clone, Copy)] @@ -1410,6 +1502,32 @@ fn create_buffer_view( Ok(view) } +#[inline] +fn create_buffer_view_range( + device: &ID3D11Device, + buffer: &ID3D11Buffer, + first_element: u32, + num_elements: u32, +) -> Result> { + let desc = D3D11_SHADER_RESOURCE_VIEW_DESC { + Format: DXGI_FORMAT_UNKNOWN, + ViewDimension: D3D11_SRV_DIMENSION_BUFFER, + Anonymous: D3D11_SHADER_RESOURCE_VIEW_DESC_0 { + Buffer: D3D11_BUFFER_SRV { + Anonymous1: D3D11_BUFFER_SRV_0 { + FirstElement: first_element, + }, + Anonymous2: D3D11_BUFFER_SRV_1 { + NumElements: num_elements, + }, + }, + }, + }; + let mut view = None; + unsafe { device.CreateShaderResourceView(buffer, Some(&desc), Some(&mut view)) }?; + Ok(view) +} + #[inline] fn update_buffer( device_context: &ID3D11DeviceContext, diff --git a/crates/gpui/src/scene.rs b/crates/gpui/src/scene.rs index eb95be1d83..b5ec2662d2 100644 --- a/crates/gpui/src/scene.rs +++ b/crates/gpui/src/scene.rs @@ -151,30 +151,22 @@ impl Scene { ), allow(dead_code) )] - pub(crate) fn batches(&self) -> impl Iterator> { + pub(crate) fn batches(&self) -> impl Iterator + '_ { BatchIterator { - shadows: &self.shadows, shadows_start: 0, shadows_iter: self.shadows.iter().peekable(), - quads: &self.quads, quads_start: 0, quads_iter: self.quads.iter().peekable(), - paths: &self.paths, paths_start: 0, paths_iter: self.paths.iter().peekable(), - underlines: &self.underlines, underlines_start: 0, underlines_iter: self.underlines.iter().peekable(), - monochrome_sprites: &self.monochrome_sprites, monochrome_sprites_start: 0, monochrome_sprites_iter: self.monochrome_sprites.iter().peekable(), - subpixel_sprites: &self.subpixel_sprites, subpixel_sprites_start: 0, subpixel_sprites_iter: self.subpixel_sprites.iter().peekable(), - polychrome_sprites: &self.polychrome_sprites, polychrome_sprites_start: 0, polychrome_sprites_iter: self.polychrome_sprites.iter().peekable(), - surfaces: &self.surfaces, surfaces_start: 0, surfaces_iter: self.surfaces.iter().peekable(), } @@ -255,34 +247,26 @@ impl Primitive { allow(dead_code) )] struct BatchIterator<'a> { - shadows: &'a [Shadow], shadows_start: usize, shadows_iter: Peekable>, - quads: &'a [Quad], quads_start: usize, quads_iter: Peekable>, - paths: &'a [Path], paths_start: usize, paths_iter: Peekable>>, - underlines: &'a [Underline], underlines_start: usize, underlines_iter: Peekable>, - monochrome_sprites: &'a [MonochromeSprite], monochrome_sprites_start: usize, monochrome_sprites_iter: Peekable>, - subpixel_sprites: &'a [SubpixelSprite], subpixel_sprites_start: usize, subpixel_sprites_iter: Peekable>, - polychrome_sprites: &'a [PolychromeSprite], polychrome_sprites_start: usize, polychrome_sprites_iter: Peekable>, - surfaces: &'a [PaintSurface], surfaces_start: usize, surfaces_iter: Peekable>, } impl<'a> Iterator for BatchIterator<'a> { - type Item = PrimitiveBatch<'a>; + type Item = PrimitiveBatch; fn next(&mut self) -> Option { let mut orders_and_kinds = [ @@ -336,9 +320,7 @@ impl<'a> Iterator for BatchIterator<'a> { shadows_end += 1; } self.shadows_start = shadows_end; - Some(PrimitiveBatch::Shadows( - &self.shadows[shadows_start..shadows_end], - )) + Some(PrimitiveBatch::Shadows(shadows_start..shadows_end)) } PrimitiveKind::Quad => { let quads_start = self.quads_start; @@ -352,7 +334,7 @@ impl<'a> Iterator for BatchIterator<'a> { quads_end += 1; } self.quads_start = quads_end; - Some(PrimitiveBatch::Quads(&self.quads[quads_start..quads_end])) + Some(PrimitiveBatch::Quads(quads_start..quads_end)) } PrimitiveKind::Path => { let paths_start = self.paths_start; @@ -366,7 +348,7 @@ impl<'a> Iterator for BatchIterator<'a> { paths_end += 1; } self.paths_start = paths_end; - Some(PrimitiveBatch::Paths(&self.paths[paths_start..paths_end])) + Some(PrimitiveBatch::Paths(paths_start..paths_end)) } PrimitiveKind::Underline => { let underlines_start = self.underlines_start; @@ -380,9 +362,7 @@ impl<'a> Iterator for BatchIterator<'a> { underlines_end += 1; } self.underlines_start = underlines_end; - Some(PrimitiveBatch::Underlines( - &self.underlines[underlines_start..underlines_end], - )) + Some(PrimitiveBatch::Underlines(underlines_start..underlines_end)) } PrimitiveKind::MonochromeSprite => { let texture_id = self.monochrome_sprites_iter.peek().unwrap().tile.texture_id; @@ -402,7 +382,7 @@ impl<'a> Iterator for BatchIterator<'a> { self.monochrome_sprites_start = sprites_end; Some(PrimitiveBatch::MonochromeSprites { texture_id, - sprites: &self.monochrome_sprites[sprites_start..sprites_end], + range: sprites_start..sprites_end, }) } PrimitiveKind::SubpixelSprite => { @@ -423,13 +403,13 @@ impl<'a> Iterator for BatchIterator<'a> { self.subpixel_sprites_start = sprites_end; Some(PrimitiveBatch::SubpixelSprites { texture_id, - sprites: &self.subpixel_sprites[sprites_start..sprites_end], + range: sprites_start..sprites_end, }) } PrimitiveKind::PolychromeSprite => { let texture_id = self.polychrome_sprites_iter.peek().unwrap().tile.texture_id; let sprites_start = self.polychrome_sprites_start; - let mut sprites_end = self.polychrome_sprites_start + 1; + let mut sprites_end = sprites_start + 1; self.polychrome_sprites_iter.next(); while self .polychrome_sprites_iter @@ -444,7 +424,7 @@ impl<'a> Iterator for BatchIterator<'a> { self.polychrome_sprites_start = sprites_end; Some(PrimitiveBatch::PolychromeSprites { texture_id, - sprites: &self.polychrome_sprites[sprites_start..sprites_end], + range: sprites_start..sprites_end, }) } PrimitiveKind::Surface => { @@ -459,9 +439,7 @@ impl<'a> Iterator for BatchIterator<'a> { surfaces_end += 1; } self.surfaces_start = surfaces_end; - Some(PrimitiveBatch::Surfaces( - &self.surfaces[surfaces_start..surfaces_end], - )) + Some(PrimitiveBatch::Surfaces(surfaces_start..surfaces_end)) } } } @@ -475,25 +453,25 @@ impl<'a> Iterator for BatchIterator<'a> { ), allow(dead_code) )] -pub(crate) enum PrimitiveBatch<'a> { - Shadows(&'a [Shadow]), - Quads(&'a [Quad]), - Paths(&'a [Path]), - Underlines(&'a [Underline]), +pub(crate) enum PrimitiveBatch { + Shadows(Range), + Quads(Range), + Paths(Range), + Underlines(Range), MonochromeSprites { texture_id: AtlasTextureId, - sprites: &'a [MonochromeSprite], + range: Range, }, #[cfg_attr(target_os = "macos", allow(dead_code))] SubpixelSprites { texture_id: AtlasTextureId, - sprites: &'a [SubpixelSprite], + range: Range, }, PolychromeSprites { texture_id: AtlasTextureId, - sprites: &'a [PolychromeSprite], + range: Range, }, - Surfaces(&'a [PaintSurface]), + Surfaces(Range), } #[derive(Default, Debug, Clone)]