wgpu: Switch to arena
This commit is contained in:
parent
c63aa2cfc8
commit
b62c17577b
|
@ -2,6 +2,12 @@
|
||||||
# It is not intended for manual editing.
|
# It is not intended for manual editing.
|
||||||
version = 3
|
version = 3
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "Inflector"
|
||||||
|
version = "0.11.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "adler"
|
name = "adler"
|
||||||
version = "1.0.2"
|
version = "1.0.2"
|
||||||
|
@ -34,6 +40,12 @@ dependencies = [
|
||||||
"memchr",
|
"memchr",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "aliasable"
|
||||||
|
version = "0.1.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "250f629c0161ad8107cf89319e990051fae62832fd343083bea452d93e2205fd"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "alsa"
|
name = "alsa"
|
||||||
version = "0.6.0"
|
version = "0.6.0"
|
||||||
|
@ -273,9 +285,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bumpalo"
|
name = "bumpalo"
|
||||||
version = "3.10.0"
|
version = "3.11.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "37ccbd214614c6783386c1af30caf03192f17891059cecc394b4fb119e363de3"
|
checksum = "c1ad822118d20d2c234f427000d5acc36eabe1e29a348c89b63dd60b13f28e5d"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bytemuck"
|
name = "bytemuck"
|
||||||
|
@ -2603,6 +2615,29 @@ version = "6.2.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "648001efe5d5c0102d8cea768e348da85d90af8ba91f0bea908f157951493cd4"
|
checksum = "648001efe5d5c0102d8cea768e348da85d90af8ba91f0bea908f157951493cd4"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ouroboros"
|
||||||
|
version = "0.15.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7f56a2b0aa5fc88687aaf63e85a7974422790ce3419a2e1a15870f8a55227822"
|
||||||
|
dependencies = [
|
||||||
|
"aliasable",
|
||||||
|
"ouroboros_macro",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ouroboros_macro"
|
||||||
|
version = "0.15.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6c40641e27d0eb38cae3dee081d920104d2db47a8e853c1a592ef68d33f5ebf4"
|
||||||
|
dependencies = [
|
||||||
|
"Inflector",
|
||||||
|
"proc-macro-error",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "output_vt100"
|
name = "output_vt100"
|
||||||
version = "0.1.3"
|
version = "0.1.3"
|
||||||
|
@ -3181,9 +3216,11 @@ dependencies = [
|
||||||
"futures",
|
"futures",
|
||||||
"image",
|
"image",
|
||||||
"log",
|
"log",
|
||||||
|
"ouroboros",
|
||||||
"raw-window-handle 0.4.3",
|
"raw-window-handle 0.4.3",
|
||||||
"ruffle_render",
|
"ruffle_render",
|
||||||
"swf",
|
"swf",
|
||||||
|
"typed-arena",
|
||||||
"web-sys",
|
"web-sys",
|
||||||
"wgpu",
|
"wgpu",
|
||||||
]
|
]
|
||||||
|
@ -3836,6 +3873,12 @@ dependencies = [
|
||||||
"strength_reduce",
|
"strength_reduce",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "typed-arena"
|
||||||
|
version = "2.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0685c84d5d54d1c26f7d3eb96cd41550adb97baed141a761cf335d3d33bcd0ae"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "typenum"
|
name = "typenum"
|
||||||
version = "1.15.0"
|
version = "1.15.0"
|
||||||
|
|
|
@ -16,6 +16,8 @@ enum-map = "2.4.1"
|
||||||
fnv = "1.0.7"
|
fnv = "1.0.7"
|
||||||
swf = { path = "../../swf" }
|
swf = { path = "../../swf" }
|
||||||
image = { version = "0.24.2", default-features = false }
|
image = { version = "0.24.2", default-features = false }
|
||||||
|
ouroboros = "0.15.4"
|
||||||
|
typed-arena = "2.0.1"
|
||||||
|
|
||||||
# desktop
|
# desktop
|
||||||
[target.'cfg(not(target_family = "wasm"))'.dependencies.futures]
|
[target.'cfg(not(target_family = "wasm"))'.dependencies.futures]
|
||||||
|
|
|
@ -150,7 +150,7 @@ impl<T: RenderTarget> WgpuRenderBackend<T> {
|
||||||
globals.set_resolution(target.width(), target.height());
|
globals.set_resolution(target.width(), target.height());
|
||||||
|
|
||||||
let uniform_buffers_storage =
|
let uniform_buffers_storage =
|
||||||
BufferStorage::new(descriptors.limits.min_uniform_buffer_offset_alignment);
|
BufferStorage::from_alignment(descriptors.limits.min_uniform_buffer_offset_alignment);
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
descriptors,
|
descriptors,
|
||||||
|
|
|
@ -1,23 +1,35 @@
|
||||||
use bytemuck::Pod;
|
use bytemuck::Pod;
|
||||||
use std::pin::Pin;
|
use ouroboros::self_referencing;
|
||||||
|
use std::cell::RefCell;
|
||||||
use std::{marker::PhantomData, mem};
|
use std::{marker::PhantomData, mem};
|
||||||
|
use typed_arena::Arena;
|
||||||
use wgpu::util::StagingBelt;
|
use wgpu::util::StagingBelt;
|
||||||
|
|
||||||
/// A simple chunked bump allacator for managing dynamic uniforms that change per-draw.
|
/// A simple chunked bump allacator for managing dynamic uniforms that change per-draw.
|
||||||
/// Each draw call may use `UniformBuffer::write_uniforms` can be used to queue
|
/// Each draw call may use `UniformBuffer::write_uniforms` can be used to queue
|
||||||
/// the upload of uniform data to the GPU.
|
/// the upload of uniform data to the GPU.
|
||||||
pub struct UniformBuffer<'a, T: Pod> {
|
pub struct UniformBuffer<'a, T: Pod> {
|
||||||
buffers: &'a mut BufferStorage<T>,
|
buffers: &'a BufferStorage<T>,
|
||||||
cur_block: usize,
|
cur_block: usize,
|
||||||
cur_offset: u32,
|
cur_offset: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[self_referencing]
|
||||||
pub struct BufferStorage<T: Pod> {
|
pub struct BufferStorage<T: Pod> {
|
||||||
_phantom: PhantomData<T>,
|
phantom: PhantomData<T>,
|
||||||
blocks: Vec<Pin<Box<Block>>>,
|
arena: Arena<Block>,
|
||||||
staging_belt: StagingBelt,
|
|
||||||
|
#[borrows(arena)]
|
||||||
|
#[not_covariant]
|
||||||
|
allocator: RefCell<Allocator<'this>>,
|
||||||
|
|
||||||
|
staging_belt: RefCell<StagingBelt>,
|
||||||
aligned_uniforms_size: u32,
|
aligned_uniforms_size: u32,
|
||||||
}
|
}
|
||||||
|
struct Allocator<'a> {
|
||||||
|
arena: &'a Arena<Block>,
|
||||||
|
blocks: Vec<&'a Block>,
|
||||||
|
}
|
||||||
|
|
||||||
impl<T: Pod> BufferStorage<T> {
|
impl<T: Pod> BufferStorage<T> {
|
||||||
/// The size of each block.
|
/// The size of each block.
|
||||||
|
@ -28,20 +40,27 @@ impl<T: Pod> BufferStorage<T> {
|
||||||
/// The uniform data size for a single draw call.
|
/// The uniform data size for a single draw call.
|
||||||
pub const UNIFORMS_SIZE: u64 = mem::size_of::<T>() as u64;
|
pub const UNIFORMS_SIZE: u64 = mem::size_of::<T>() as u64;
|
||||||
|
|
||||||
pub fn new(uniform_alignment: u32) -> Self {
|
pub fn from_alignment(uniform_alignment: u32) -> Self {
|
||||||
// Calculate alignment of uniforms.
|
// Calculate alignment of uniforms.
|
||||||
let align_mask = uniform_alignment - 1;
|
let align_mask = uniform_alignment - 1;
|
||||||
let aligned_uniforms_size = (Self::UNIFORMS_SIZE as u32 + align_mask) & !align_mask;
|
let aligned_uniforms_size = (Self::UNIFORMS_SIZE as u32 + align_mask) & !align_mask;
|
||||||
Self {
|
BufferStorageBuilder {
|
||||||
|
arena: Arena::with_capacity(8),
|
||||||
|
allocator_builder: |arena| {
|
||||||
|
RefCell::new(Allocator {
|
||||||
|
arena,
|
||||||
blocks: Vec::with_capacity(8),
|
blocks: Vec::with_capacity(8),
|
||||||
staging_belt: StagingBelt::new(u64::from(Self::BLOCK_SIZE) / 2),
|
})
|
||||||
|
},
|
||||||
|
staging_belt: RefCell::new(StagingBelt::new(u64::from(Self::BLOCK_SIZE) / 2)),
|
||||||
aligned_uniforms_size,
|
aligned_uniforms_size,
|
||||||
_phantom: PhantomData,
|
phantom: PhantomData,
|
||||||
}
|
}
|
||||||
|
.build()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Adds a newly allocated buffer to the block list, and returns it.
|
/// Adds a newly allocated buffer to the block list, and returns it.
|
||||||
pub fn allocate_block(&mut self, device: &wgpu::Device, layout: &wgpu::BindGroupLayout) {
|
pub fn allocate_block(&self, device: &wgpu::Device, layout: &wgpu::BindGroupLayout) {
|
||||||
let buffer_label = create_debug_label!("Dynamic buffer");
|
let buffer_label = create_debug_label!("Dynamic buffer");
|
||||||
let buffer = device.create_buffer(&wgpu::BufferDescriptor {
|
let buffer = device.create_buffer(&wgpu::BufferDescriptor {
|
||||||
label: buffer_label.as_deref(),
|
label: buffer_label.as_deref(),
|
||||||
|
@ -64,12 +83,15 @@ impl<T: Pod> BufferStorage<T> {
|
||||||
}],
|
}],
|
||||||
});
|
});
|
||||||
|
|
||||||
self.blocks
|
self.with_allocator(|alloc| {
|
||||||
.push(Pin::new(Box::new(Block { buffer, bind_group })));
|
let mut alloc = alloc.borrow_mut();
|
||||||
|
let block = alloc.arena.alloc(Block { buffer, bind_group });
|
||||||
|
alloc.blocks.push(block);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn recall(&mut self) {
|
pub fn recall(&mut self) {
|
||||||
self.staging_belt.recall();
|
self.with_staging_belt(|belt| belt.borrow_mut().recall());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -97,14 +119,21 @@ impl<'a, T: Pod> UniformBuffer<'a, T> {
|
||||||
'a: 'b,
|
'a: 'b,
|
||||||
{
|
{
|
||||||
// Allocate a new block if we've exceeded our capacity.
|
// Allocate a new block if we've exceeded our capacity.
|
||||||
if self.cur_block >= self.buffers.blocks.len() {
|
if self.cur_block
|
||||||
|
>= self
|
||||||
|
.buffers
|
||||||
|
.with_allocator(|alloc| alloc.borrow().blocks.len())
|
||||||
|
{
|
||||||
self.buffers.allocate_block(device, layout);
|
self.buffers.allocate_block(device, layout);
|
||||||
}
|
}
|
||||||
let block = &self.buffers.blocks[self.cur_block];
|
|
||||||
|
let block: &'a Block = self
|
||||||
|
.buffers
|
||||||
|
.with_allocator(|alloc| alloc.borrow().blocks[self.cur_block]);
|
||||||
|
|
||||||
// Copy the data into the buffer via the staging belt.
|
// Copy the data into the buffer via the staging belt.
|
||||||
self.buffers
|
self.buffers.with_staging_belt(|belt| {
|
||||||
.staging_belt
|
belt.borrow_mut()
|
||||||
.write_buffer(
|
.write_buffer(
|
||||||
command_encoder,
|
command_encoder,
|
||||||
&block.buffer,
|
&block.buffer,
|
||||||
|
@ -113,18 +142,17 @@ impl<'a, T: Pod> UniformBuffer<'a, T> {
|
||||||
device,
|
device,
|
||||||
)
|
)
|
||||||
.copy_from_slice(bytemuck::cast_slice(std::slice::from_ref(data)));
|
.copy_from_slice(bytemuck::cast_slice(std::slice::from_ref(data)));
|
||||||
|
});
|
||||||
|
|
||||||
// Set the bind group to the final uniform location.
|
// Set the bind group to the final uniform location.
|
||||||
render_pass.set_bind_group(
|
render_pass.set_bind_group(bind_group_index, &block.bind_group, &[self.cur_offset]);
|
||||||
bind_group_index,
|
|
||||||
unsafe { mem::transmute::<_, &'a wgpu::BindGroup>(&block.bind_group) },
|
|
||||||
&[self.cur_offset],
|
|
||||||
);
|
|
||||||
|
|
||||||
// Advance offset.
|
// Advance offset.
|
||||||
self.cur_offset += self.buffers.aligned_uniforms_size;
|
self.cur_offset += self.buffers.borrow_aligned_uniforms_size();
|
||||||
// Advance to next buffer if we are out of room in this buffer.
|
// Advance to next buffer if we are out of room in this buffer.
|
||||||
if BufferStorage::<T>::BLOCK_SIZE - self.cur_offset < self.buffers.aligned_uniforms_size {
|
if BufferStorage::<T>::BLOCK_SIZE - self.cur_offset
|
||||||
|
< *self.buffers.borrow_aligned_uniforms_size()
|
||||||
|
{
|
||||||
self.cur_block += 1;
|
self.cur_block += 1;
|
||||||
self.cur_offset = 0;
|
self.cur_offset = 0;
|
||||||
}
|
}
|
||||||
|
@ -132,7 +160,8 @@ impl<'a, T: Pod> UniformBuffer<'a, T> {
|
||||||
|
|
||||||
/// Should be called at the end of a frame.
|
/// Should be called at the end of a frame.
|
||||||
pub fn finish(self) {
|
pub fn finish(self) {
|
||||||
self.buffers.staging_belt.finish();
|
self.buffers
|
||||||
|
.with_staging_belt(|belt| belt.borrow_mut().finish());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue