diff --git a/gpui/src/platform/mac/renderer.rs b/gpui/src/platform/mac/renderer.rs index 6f712f29b3bbbfdf647e7b0ddeaebbcd43594b0c..d650c2d9170ee98d6fdad9fe11d1040b1900ee04 100644 --- a/gpui/src/platform/mac/renderer.rs +++ b/gpui/src/platform/mac/renderer.rs @@ -598,11 +598,6 @@ impl Renderer { mem::size_of::() as u64, [drawable_size.to_float2()].as_ptr() as *const c_void, ); - command_encoder.set_vertex_bytes( - shaders::GPUISpriteVertexInputIndex_GPUISpriteVertexInputIndexAtlasSize as u64, - mem::size_of::() as u64, - [self.sprite_cache.atlas_size().to_float2()].as_ptr() as *const c_void, - ); for (atlas_id, sprites) in sprites_by_atlas { align_offset(offset); @@ -612,13 +607,19 @@ impl Renderer { "instance buffer exhausted" ); + let texture = self.sprite_cache.atlas_texture(atlas_id).unwrap(); command_encoder.set_vertex_buffer( shaders::GPUISpriteVertexInputIndex_GPUISpriteVertexInputIndexSprites as u64, Some(&self.instances), *offset as u64, ); + command_encoder.set_vertex_bytes( + shaders::GPUISpriteVertexInputIndex_GPUISpriteVertexInputIndexAtlasSize as u64, + mem::size_of::() as u64, + [vec2i(texture.width() as i32, texture.height() as i32).to_float2()].as_ptr() + as *const c_void, + ); - let texture = self.sprite_cache.atlas_texture(atlas_id).unwrap(); command_encoder.set_fragment_texture( shaders::GPUISpriteFragmentInputIndex_GPUISpriteFragmentInputIndexAtlas as u64, Some(texture), diff --git a/gpui/src/platform/mac/sprite_cache.rs b/gpui/src/platform/mac/sprite_cache.rs index 4c764ae1ca518a52e6f45b6bd80093345576fe26..7d11a3d2760dc46e42a08747cb922d9a9ef42e75 100644 --- a/gpui/src/platform/mac/sprite_cache.rs +++ b/gpui/src/platform/mac/sprite_cache.rs @@ -1,12 +1,9 @@ +use super::atlas::AtlasAllocator; use crate::{ fonts::{FontId, GlyphId}, - geometry::{ - rect::RectI, - vector::{vec2f, vec2i, Vector2F, Vector2I}, - }, + geometry::vector::{vec2f, Vector2F, Vector2I}, platform, }; -use etagere::BucketedAtlasAllocator; use metal::{MTLPixelFormat, TextureDescriptor}; use ordered_float::OrderedFloat; use std::{borrow::Cow, collections::HashMap, sync::Arc}; @@ -42,10 +39,8 @@ pub struct IconSprite { } pub struct SpriteCache { - device: metal::Device, - atlas_size: Vector2I, fonts: Arc, - atlases: Vec, + atlases: AtlasAllocator, glyphs: HashMap>, icons: HashMap, } @@ -56,21 +51,18 @@ impl SpriteCache { size: Vector2I, fonts: Arc, ) -> Self { - let atlases = vec![Atlas::new(&device, size)]; + let descriptor = TextureDescriptor::new(); + descriptor.set_pixel_format(MTLPixelFormat::A8Unorm); + descriptor.set_width(size.x() as u64); + descriptor.set_height(size.y() as u64); Self { - device, - atlas_size: size, fonts, - atlases, + atlases: AtlasAllocator::new(device, descriptor), glyphs: Default::default(), icons: Default::default(), } } - pub fn atlas_size(&self) -> Vector2I { - self.atlas_size - } - pub fn render_glyph( &mut self, font_id: FontId, @@ -84,8 +76,6 @@ impl SpriteCache { let target_position = target_position * scale_factor; let fonts = &self.fonts; let atlases = &mut self.atlases; - let atlas_size = self.atlas_size; - let device = &self.device; let subpixel_variant = ( (target_position.x().fract() * SUBPIXEL_VARIANTS as f32).round() as u8 % SUBPIXEL_VARIANTS, @@ -111,22 +101,10 @@ impl SpriteCache { subpixel_shift, scale_factor, )?; - assert!(glyph_bounds.width() < atlas_size.x()); - assert!(glyph_bounds.height() < atlas_size.y()); - - let atlas_bounds = atlases - .last_mut() - .unwrap() - .try_insert(glyph_bounds.size(), &mask) - .unwrap_or_else(|| { - let mut atlas = Atlas::new(device, atlas_size); - let bounds = atlas.try_insert(glyph_bounds.size(), &mask).unwrap(); - atlases.push(atlas); - bounds - }); + let (alloc_id, atlas_bounds) = atlases.upload(glyph_bounds.size(), &mask); Some(GlyphSprite { - atlas_id: atlases.len() - 1, + atlas_id: alloc_id.atlas_id, atlas_origin: atlas_bounds.origin(), offset: glyph_bounds.origin(), size: glyph_bounds.size(), @@ -142,10 +120,6 @@ impl SpriteCache { svg: usvg::Tree, ) -> IconSprite { let atlases = &mut self.atlases; - let atlas_size = self.atlas_size; - let device = &self.device; - assert!(size.x() < atlas_size.x()); - assert!(size.y() < atlas_size.y()); self.icons .entry(IconDescriptor { path, @@ -161,19 +135,9 @@ impl SpriteCache { .map(|a| a.alpha()) .collect::>(); - let atlas_bounds = atlases - .last_mut() - .unwrap() - .try_insert(size, &mask) - .unwrap_or_else(|| { - let mut atlas = Atlas::new(device, atlas_size); - let bounds = atlas.try_insert(size, &mask).unwrap(); - atlases.push(atlas); - bounds - }); - + let (alloc_id, atlas_bounds) = atlases.upload(size, &mask); IconSprite { - atlas_id: atlases.len() - 1, + atlas_id: alloc_id.atlas_id, atlas_origin: atlas_bounds.origin(), size, } @@ -182,45 +146,6 @@ impl SpriteCache { } pub fn atlas_texture(&self, atlas_id: usize) -> Option<&metal::TextureRef> { - self.atlases.get(atlas_id).map(|a| a.texture.as_ref()) - } -} - -struct Atlas { - allocator: BucketedAtlasAllocator, - texture: metal::Texture, -} - -impl Atlas { - fn new(device: &metal::DeviceRef, size: Vector2I) -> Self { - let descriptor = TextureDescriptor::new(); - descriptor.set_pixel_format(MTLPixelFormat::A8Unorm); - descriptor.set_width(size.x() as u64); - descriptor.set_height(size.y() as u64); - - Self { - allocator: BucketedAtlasAllocator::new(etagere::Size::new(size.x(), size.y())), - texture: device.new_texture(&descriptor), - } - } - - fn try_insert(&mut self, size: Vector2I, mask: &[u8]) -> Option { - let allocation = self - .allocator - .allocate(etagere::size2(size.x() + 1, size.y() + 1))?; - - let bounds = allocation.rectangle; - let region = metal::MTLRegion::new_2d( - bounds.min.x as u64, - bounds.min.y as u64, - size.x() as u64, - size.y() as u64, - ); - self.texture - .replace_region(region, 0, mask.as_ptr() as *const _, size.x() as u64); - Some(RectI::from_points( - vec2i(bounds.min.x, bounds.min.y), - vec2i(bounds.max.x, bounds.max.y), - )) + self.atlases.texture(atlas_id) } }