From 9ef1afd6d5f4229c1a45988d3b263a900c1044d0 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 bfcb21d5f9db205180ee89d626381615f5265020..4d1afa1763a9acbdfd7b0d60db76f84094dedab9 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 07e7cdd2763226e92948e7b02b2c09383a0aa52f..e33b1169f10afe025ee506f89eeac132bdcf8bfc 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 443ea1424313d843293f0648449192bbea0b0234..8e7a0ac142439b9625d44223194d302e2517195e 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 eb95be1d83b9e10e83eae129b64b51e10d667c2d..b5ec2662d29b9af95f36fdfd989733c0e9ddb1e1 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)]