blade: Use BufferBelt from blade-utils (#12411)

Release Notes:

- N/A

Follow-up to #12340
Carries https://github.com/kvark/blade/pull/122 and
https://github.com/kvark/blade/pull/119
This commit is contained in:
Dzmitry Malyshau 2024-05-29 09:50:45 -07:00 committed by GitHub
parent c34d36161d
commit 44c50da94f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 36 additions and 124 deletions

18
Cargo.lock generated
View File

@ -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",

View File

@ -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"] }

View File

@ -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"

View File

@ -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::*;

View File

@ -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<gpu::Context>,
upload_belt: BladeBelt,
upload_belt: BufferBelt,
storage: BladeAtlasStorage,
tiles_by_key: FxHashMap<AtlasKey, AtlasTile>,
initializations: Vec<AtlasTextureId>,
@ -48,7 +48,7 @@ impl BladeAtlas {
pub(crate) fn new(gpu: &Arc<gpu::Context>) -> 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<DevicePixels>, 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 });
}

View File

@ -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<T>(&mut self, data: &[T], gpu: &gpu::Context) -> gpu::BufferPiece {
assert!(!data.is_empty());
let type_alignment = mem::align_of::<T>() 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())));
}
}

View File

@ -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<gpu::SyncPoint>,
pipelines: BladePipelines,
instance_belt: BladeBelt,
instance_belt: BufferBelt,
path_tiles: HashMap<PathId, AtlasTile>,
atlas: Arc<BladeAtlas>,
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,