diff --git a/Cargo.lock b/Cargo.lock index 16d648c19b..a381dd863a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1509,7 +1509,7 @@ dependencies = [ [[package]] name = "blade-graphics" version = "0.4.0" -source = "git+https://github.com/kvark/blade?rev=9c9cabf69e869fc7d9aef2fc76f7d5c354d5710a#9c9cabf69e869fc7d9aef2fc76f7d5c354d5710a" +source = "git+https://github.com/kvark/blade?rev=bdaf8c534fbbc9fbca71d1cf272f45640b3a068d#bdaf8c534fbbc9fbca71d1cf272f45640b3a068d" dependencies = [ "ash", "ash-window", @@ -1539,13 +1539,24 @@ dependencies = [ [[package]] name = "blade-macros" version = "0.2.1" -source = "git+https://github.com/kvark/blade?rev=9c9cabf69e869fc7d9aef2fc76f7d5c354d5710a#9c9cabf69e869fc7d9aef2fc76f7d5c354d5710a" +source = "git+https://github.com/kvark/blade?rev=bdaf8c534fbbc9fbca71d1cf272f45640b3a068d#bdaf8c534fbbc9fbca71d1cf272f45640b3a068d" dependencies = [ "proc-macro2", "quote", "syn 2.0.59", ] +[[package]] +name = "blade-util" +version = "0.1.0" +source = "git+https://github.com/kvark/blade?rev=bdaf8c534fbbc9fbca71d1cf272f45640b3a068d#bdaf8c534fbbc9fbca71d1cf272f45640b3a068d" +dependencies = [ + "blade-graphics", + "bytemuck", + "log", + "profiling", +] + [[package]] name = "block" version = "0.1.6" @@ -3378,7 +3389,7 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "330c60081dcc4c72131f8eb70510f1ac07223e5d4163db481a04a0befcffa412" dependencies = [ - "libloading 0.8.0", + "libloading 0.7.4", ] [[package]] @@ -4689,6 +4700,7 @@ dependencies = [ "bindgen 0.65.1", "blade-graphics", "blade-macros", + "blade-util", "block", "bytemuck", "calloop", diff --git a/Cargo.toml b/Cargo.toml index 549665f54d..de1d25ee89 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -262,8 +262,9 @@ async-tar = "0.4.2" async-trait = "0.1" async_zip = { version = "0.0.17", features = ["deflate", "deflate64"] } bitflags = "2.4.2" -blade-graphics = { git = "https://github.com/kvark/blade", rev = "9c9cabf69e869fc7d9aef2fc76f7d5c354d5710a" } -blade-macros = { git = "https://github.com/kvark/blade", rev = "9c9cabf69e869fc7d9aef2fc76f7d5c354d5710a" } +blade-graphics = { git = "https://github.com/kvark/blade", rev = "bdaf8c534fbbc9fbca71d1cf272f45640b3a068d" } +blade-macros = { git = "https://github.com/kvark/blade", rev = "bdaf8c534fbbc9fbca71d1cf272f45640b3a068d" } +blade-util = { git = "https://github.com/kvark/blade", rev = "bdaf8c534fbbc9fbca71d1cf272f45640b3a068d" } cap-std = "3.0" cargo_toml = "0.20" chrono = { version = "0.4", features = ["serde"] } diff --git a/crates/gpui/Cargo.toml b/crates/gpui/Cargo.toml index bc2297e053..6d7004e58d 100644 --- a/crates/gpui/Cargo.toml +++ b/crates/gpui/Cargo.toml @@ -14,7 +14,7 @@ workspace = true default = [] test-support = ["backtrace", "collections/test-support", "util/test-support", "http/test-support"] runtime_shaders = [] -macos-blade = ["blade-graphics", "blade-macros", "bytemuck"] +macos-blade = ["blade-graphics", "blade-macros", "blade-util", "bytemuck"] [lib] path = "src/gpui.rs" @@ -26,6 +26,7 @@ async-task = "4.7" backtrace = { version = "0.3", optional = true } blade-graphics = { workspace = true, optional = true } blade-macros = { workspace = true, optional = true } +blade-util = { workspace = true, optional = true } bytemuck = { version = "1", optional = true } collections.workspace = true ctor.workspace = true @@ -96,6 +97,7 @@ flume = "0.11" #TODO: use these on all platforms blade-graphics.workspace = true blade-macros.workspace = true +blade-util.workspace = true bytemuck = "1" cosmic-text = "0.11.2" copypasta = "0.10.1" diff --git a/crates/gpui/src/platform/blade.rs b/crates/gpui/src/platform/blade.rs index 830f69daed..736c1888d8 100644 --- a/crates/gpui/src/platform/blade.rs +++ b/crates/gpui/src/platform/blade.rs @@ -1,8 +1,5 @@ mod blade_atlas; -mod blade_belt; mod blade_renderer; pub(crate) use blade_atlas::*; pub(crate) use blade_renderer::*; - -use blade_belt::*; diff --git a/crates/gpui/src/platform/blade/blade_atlas.rs b/crates/gpui/src/platform/blade/blade_atlas.rs index 22b2e4f3f7..f2cdb7e957 100644 --- a/crates/gpui/src/platform/blade/blade_atlas.rs +++ b/crates/gpui/src/platform/blade/blade_atlas.rs @@ -1,10 +1,10 @@ -use super::{BladeBelt, BladeBeltDescriptor}; use crate::{ AtlasKey, AtlasTextureId, AtlasTextureKind, AtlasTile, Bounds, DevicePixels, PlatformAtlas, Point, Size, }; use anyhow::Result; use blade_graphics as gpu; +use blade_util::{BufferBelt, BufferBeltDescriptor}; use collections::FxHashMap; use etagere::BucketedAtlasAllocator; use parking_lot::Mutex; @@ -22,7 +22,7 @@ struct PendingUpload { struct BladeAtlasState { gpu: Arc, - upload_belt: BladeBelt, + upload_belt: BufferBelt, storage: BladeAtlasStorage, tiles_by_key: FxHashMap, initializations: Vec, @@ -48,7 +48,7 @@ impl BladeAtlas { pub(crate) fn new(gpu: &Arc) -> Self { BladeAtlas(Mutex::new(BladeAtlasState { gpu: Arc::clone(gpu), - upload_belt: BladeBelt::new(BladeBeltDescriptor { + upload_belt: BufferBelt::new(BufferBeltDescriptor { memory: gpu::Memory::Upload, min_chunk_size: 0x10000, alignment: 64, // Vulkan `optimalBufferCopyOffsetAlignment` on Intel XE @@ -212,7 +212,7 @@ impl BladeAtlasState { } fn upload_texture(&mut self, id: AtlasTextureId, bounds: Bounds, bytes: &[u8]) { - let data = unsafe { self.upload_belt.alloc_data(bytes, &self.gpu) }; + let data = self.upload_belt.alloc_bytes(bytes, &self.gpu); self.uploads.push(PendingUpload { id, bounds, data }); } diff --git a/crates/gpui/src/platform/blade/blade_belt.rs b/crates/gpui/src/platform/blade/blade_belt.rs deleted file mode 100644 index 322caaa3ee..0000000000 --- a/crates/gpui/src/platform/blade/blade_belt.rs +++ /dev/null @@ -1,101 +0,0 @@ -use blade_graphics as gpu; -use std::mem; - -struct ReusableBuffer { - raw: gpu::Buffer, - size: u64, -} - -pub struct BladeBeltDescriptor { - pub memory: gpu::Memory, - pub min_chunk_size: u64, - pub alignment: u64, -} - -/// A belt of buffers, used by the BladeAtlas to cheaply -/// find staging space for uploads. -pub struct BladeBelt { - desc: BladeBeltDescriptor, - buffers: Vec<(ReusableBuffer, gpu::SyncPoint)>, - active: Vec<(ReusableBuffer, u64)>, -} - -impl BladeBelt { - pub fn new(desc: BladeBeltDescriptor) -> Self { - assert_ne!(desc.alignment, 0); - Self { - desc, - buffers: Vec::new(), - active: Vec::new(), - } - } - - pub fn destroy(&mut self, gpu: &gpu::Context) { - for (buffer, _) in self.buffers.drain(..) { - gpu.destroy_buffer(buffer.raw); - } - for (buffer, _) in self.active.drain(..) { - gpu.destroy_buffer(buffer.raw); - } - } - - #[profiling::function] - pub fn alloc(&mut self, size: u64, gpu: &gpu::Context) -> gpu::BufferPiece { - for &mut (ref rb, ref mut offset) in self.active.iter_mut() { - let aligned = offset.next_multiple_of(self.desc.alignment); - if aligned + size <= rb.size { - let piece = rb.raw.at(aligned); - *offset = aligned + size; - return piece; - } - } - - let index_maybe = self - .buffers - .iter() - .position(|(rb, sp)| size <= rb.size && gpu.wait_for(sp, 0)); - if let Some(index) = index_maybe { - let (rb, _) = self.buffers.remove(index); - let piece = rb.raw.into(); - self.active.push((rb, size)); - return piece; - } - - let chunk_index = self.buffers.len() + self.active.len(); - let chunk_size = size.max(self.desc.min_chunk_size); - let chunk = gpu.create_buffer(gpu::BufferDesc { - name: &format!("chunk-{}", chunk_index), - size: chunk_size, - memory: self.desc.memory, - }); - let rb = ReusableBuffer { - raw: chunk, - size: chunk_size, - }; - self.active.push((rb, size)); - chunk.into() - } - - // SAFETY: T should be zeroable and ordinary data, no references, pointers, cells or other complicated data type. - pub unsafe fn alloc_data(&mut self, data: &[T], gpu: &gpu::Context) -> gpu::BufferPiece { - assert!(!data.is_empty()); - let type_alignment = mem::align_of::() as u64; - debug_assert_eq!( - self.desc.alignment % type_alignment, - 0, - "Type alignment {} is too big", - type_alignment - ); - let total_bytes = std::mem::size_of_val(data); - let bp = self.alloc(total_bytes as u64, gpu); - unsafe { - std::ptr::copy_nonoverlapping(data.as_ptr() as *const u8, bp.data(), total_bytes); - } - bp - } - - pub fn flush(&mut self, sp: &gpu::SyncPoint) { - self.buffers - .extend(self.active.drain(..).map(|(rb, _)| (rb, sp.clone()))); - } -} diff --git a/crates/gpui/src/platform/blade/blade_renderer.rs b/crates/gpui/src/platform/blade/blade_renderer.rs index b245089878..f8d1b8b983 100644 --- a/crates/gpui/src/platform/blade/blade_renderer.rs +++ b/crates/gpui/src/platform/blade/blade_renderer.rs @@ -1,7 +1,7 @@ // Doing `if let` gives you nice scoping with passes/encoders #![allow(irrefutable_let_patterns)] -use super::{BladeAtlas, BladeBelt, BladeBeltDescriptor, PATH_TEXTURE_FORMAT}; +use super::{BladeAtlas, PATH_TEXTURE_FORMAT}; use crate::{ AtlasTextureKind, AtlasTile, Bounds, ContentMask, Hsla, MonochromeSprite, Path, PathId, PathVertex, PolychromeSprite, PrimitiveBatch, Quad, ScaledPixels, Scene, Shadow, Size, @@ -15,6 +15,7 @@ use media::core_video::CVMetalTextureCache; use std::{ffi::c_void, ptr::NonNull}; use blade_graphics as gpu; +use blade_util::{BufferBelt, BufferBeltDescriptor}; use std::{mem, sync::Arc}; const MAX_FRAME_TIME_MS: u32 = 1000; @@ -346,7 +347,7 @@ pub struct BladeRenderer { command_encoder: gpu::CommandEncoder, last_sync_point: Option, pipelines: BladePipelines, - instance_belt: BladeBelt, + instance_belt: BufferBelt, path_tiles: HashMap, atlas: Arc, atlas_sampler: gpu::Sampler, @@ -371,7 +372,7 @@ impl BladeRenderer { buffer_count: 2, }); let pipelines = BladePipelines::new(&gpu, surface_info); - let instance_belt = BladeBelt::new(BladeBeltDescriptor { + let instance_belt = BufferBelt::new(BufferBeltDescriptor { memory: gpu::Memory::Shared, min_chunk_size: 0x1000, alignment: 0x40, // Vulkan `minStorageBufferOffsetAlignment` on Intel Xe @@ -492,7 +493,7 @@ impl BladeRenderer { pad: 0, }; - let vertex_buf = unsafe { self.instance_belt.alloc_data(&vertices, &self.gpu) }; + let vertex_buf = unsafe { self.instance_belt.alloc_typed(&vertices, &self.gpu) }; let mut pass = self.command_encoder.render(gpu::RenderTargetSet { colors: &[gpu::RenderTarget { view: tex_info.raw_view, @@ -557,7 +558,7 @@ impl BladeRenderer { match batch { PrimitiveBatch::Quads(quads) => { let instance_buf = - unsafe { self.instance_belt.alloc_data(quads, &self.gpu) }; + unsafe { self.instance_belt.alloc_typed(quads, &self.gpu) }; let mut encoder = pass.with(&self.pipelines.quads); encoder.bind( 0, @@ -570,7 +571,7 @@ impl BladeRenderer { } PrimitiveBatch::Shadows(shadows) => { let instance_buf = - unsafe { self.instance_belt.alloc_data(shadows, &self.gpu) }; + unsafe { self.instance_belt.alloc_typed(shadows, &self.gpu) }; let mut encoder = pass.with(&self.pipelines.shadows); encoder.bind( 0, @@ -598,7 +599,7 @@ impl BladeRenderer { }]; let instance_buf = - unsafe { self.instance_belt.alloc_data(&sprites, &self.gpu) }; + unsafe { self.instance_belt.alloc_typed(&sprites, &self.gpu) }; encoder.bind( 0, &ShaderPathsData { @@ -613,7 +614,7 @@ impl BladeRenderer { } PrimitiveBatch::Underlines(underlines) => { let instance_buf = - unsafe { self.instance_belt.alloc_data(underlines, &self.gpu) }; + unsafe { self.instance_belt.alloc_typed(underlines, &self.gpu) }; let mut encoder = pass.with(&self.pipelines.underlines); encoder.bind( 0, @@ -630,7 +631,7 @@ impl BladeRenderer { } => { let tex_info = self.atlas.get_texture_info(texture_id); let instance_buf = - unsafe { self.instance_belt.alloc_data(sprites, &self.gpu) }; + unsafe { self.instance_belt.alloc_typed(sprites, &self.gpu) }; let mut encoder = pass.with(&self.pipelines.mono_sprites); encoder.bind( 0, @@ -649,7 +650,7 @@ impl BladeRenderer { } => { let tex_info = self.atlas.get_texture_info(texture_id); let instance_buf = - unsafe { self.instance_belt.alloc_data(sprites, &self.gpu) }; + unsafe { self.instance_belt.alloc_typed(sprites, &self.gpu) }; let mut encoder = pass.with(&self.pipelines.poly_sprites); encoder.bind( 0,