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:
parent
c34d36161d
commit
44c50da94f
7 changed files with 36 additions and 124 deletions
|
@ -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::*;
|
||||
|
|
|
@ -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 });
|
||||
}
|
||||
|
||||
|
|
|
@ -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())));
|
||||
}
|
||||
}
|
|
@ -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,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue