1
0
Fork 0
forked from wry/wry

vulkan: replace DescriptorBufferCache by generic cache

This commit is contained in:
Julian Orth 2025-02-27 14:48:10 +01:00
parent c16ea9325e
commit f84934bd9a
4 changed files with 169 additions and 162 deletions

View file

@ -1,6 +1,7 @@
mod allocator;
mod blend_buffer;
mod bo_allocator;
mod buffer_cache;
mod command;
mod descriptor;
mod descriptor_buffer;

View file

@ -0,0 +1,158 @@
use {
crate::{
gfx_apis::vulkan::{
VulkanError,
allocator::{VulkanAllocation, VulkanAllocator},
device::VulkanDevice,
},
utils::on_drop::OnDrop,
},
ash::vk::{
Buffer, BufferCreateInfo, BufferDeviceAddressInfo, BufferUsageFlags, DeviceAddress,
DeviceSize,
},
gpu_alloc::UsageFlags,
std::{cell::RefCell, mem::ManuallyDrop, rc::Rc},
};
pub struct VulkanBufferCache {
device: Rc<VulkanDevice>,
allocator: Rc<VulkanAllocator>,
buffers: RefCell<Vec<VulkanBufferUnused>>,
usage: BufferUsageFlags,
}
pub struct VulkanBuffer {
cache: Rc<VulkanBufferCache>,
pub buffer: ManuallyDrop<VulkanBufferUnused>,
}
pub struct VulkanBufferUnused {
device: Rc<VulkanDevice>,
pub size: DeviceSize,
pub buffer: Buffer,
pub allocation: VulkanAllocation,
pub address: DeviceAddress,
}
impl VulkanBufferCache {
pub fn new(
device: &Rc<VulkanDevice>,
allocator: &Rc<VulkanAllocator>,
usage: BufferUsageFlags,
) -> Rc<Self> {
Rc::new(Self {
device: device.clone(),
allocator: allocator.clone(),
buffers: Default::default(),
usage,
})
}
pub fn for_descriptor_buffer(
device: &Rc<VulkanDevice>,
allocator: &Rc<VulkanAllocator>,
has_sampler: bool,
) -> Rc<Self> {
let mut usage = BufferUsageFlags::RESOURCE_DESCRIPTOR_BUFFER_EXT
| BufferUsageFlags::SHADER_DEVICE_ADDRESS;
if has_sampler {
usage |= BufferUsageFlags::SAMPLER_DESCRIPTOR_BUFFER_EXT;
}
Self::new(device, allocator, usage)
}
pub fn usage(&self) -> BufferUsageFlags {
self.usage
}
pub fn allocate(self: &Rc<Self>, capacity: DeviceSize) -> Result<VulkanBuffer, VulkanError> {
const MIN_ALLOCATION: DeviceSize = 1024;
let capacity = capacity.max(MIN_ALLOCATION);
let mut smallest = None;
let mut smallest_size = DeviceSize::MAX;
let mut fitting = None;
let mut fitting_size = DeviceSize::MAX;
let buffers = &mut *self.buffers.borrow_mut();
for (idx, buffer) in buffers.iter().enumerate() {
if buffer.size >= capacity {
if buffer.size < fitting_size {
fitting = Some(idx);
fitting_size = buffer.size;
}
} else {
if buffer.size < smallest_size {
smallest = Some(idx);
smallest_size = buffer.size;
}
}
}
if let Some(idx) = fitting {
return Ok(VulkanBuffer {
cache: self.clone(),
buffer: ManuallyDrop::new(buffers.swap_remove(idx)),
});
}
if let Some(idx) = smallest {
log::debug!("discarding size {}", smallest_size);
buffers.swap_remove(idx);
}
let size = capacity.checked_next_power_of_two().unwrap();
log::debug!("allocating size {}", size);
let buffer = {
let info = BufferCreateInfo::default().size(size).usage(self.usage);
unsafe {
self.device
.device
.create_buffer(&info, None)
.map_err(VulkanError::CreateBuffer)?
}
};
let destroy_buffer = OnDrop(|| unsafe { self.device.device.destroy_buffer(buffer, None) });
let memory_requirements =
unsafe { self.device.device.get_buffer_memory_requirements(buffer) };
let allocation = {
let flags = UsageFlags::UPLOAD
| UsageFlags::FAST_DEVICE_ACCESS
| UsageFlags::HOST_ACCESS
| UsageFlags::DEVICE_ADDRESS;
self.allocator.alloc(&memory_requirements, flags, true)?
};
unsafe {
self.device
.device
.bind_buffer_memory(buffer, allocation.memory, allocation.offset)
.map_err(VulkanError::BindBufferMemory)?;
}
destroy_buffer.forget();
let address = {
let info = BufferDeviceAddressInfo::default().buffer(buffer);
unsafe { self.device.device.get_buffer_device_address(&info) }
};
Ok(VulkanBuffer {
cache: self.clone(),
buffer: ManuallyDrop::new(VulkanBufferUnused {
device: self.device.clone(),
size,
buffer,
allocation,
address,
}),
})
}
}
impl Drop for VulkanBuffer {
fn drop(&mut self) {
let buffer = unsafe { ManuallyDrop::take(&mut self.buffer) };
self.cache.buffers.borrow_mut().push(buffer);
}
}
impl Drop for VulkanBufferUnused {
fn drop(&mut self) {
unsafe {
self.device.device.destroy_buffer(self.buffer, None);
}
}
}

View file

@ -1,41 +1,8 @@
use {
crate::{
gfx_apis::vulkan::{
VulkanError,
allocator::{VulkanAllocation, VulkanAllocator},
descriptor::VulkanDescriptorSetLayout,
device::VulkanDevice,
},
utils::on_drop::OnDrop,
},
ash::vk::{
Buffer, BufferCreateInfo, BufferDeviceAddressInfo, BufferUsageFlags, DeviceAddress,
DeviceSize,
},
gpu_alloc::UsageFlags,
std::{cell::RefCell, mem::ManuallyDrop, ops::Deref, rc::Rc},
crate::gfx_apis::vulkan::descriptor::VulkanDescriptorSetLayout, ash::vk::DeviceSize,
std::ops::Deref,
};
pub struct VulkanDescriptorBufferCache {
device: Rc<VulkanDevice>,
allocator: Rc<VulkanAllocator>,
buffers: RefCell<Vec<VulkanDescriptorBufferUnused>>,
has_sampler: bool,
}
pub struct VulkanDescriptorBuffer {
cache: Rc<VulkanDescriptorBufferCache>,
pub buffer: ManuallyDrop<VulkanDescriptorBufferUnused>,
}
pub struct VulkanDescriptorBufferUnused {
device: Rc<VulkanDevice>,
pub size: DeviceSize,
pub buffer: Buffer,
pub allocation: VulkanAllocation,
pub address: DeviceAddress,
}
#[derive(Default)]
pub struct VulkanDescriptorBufferWriter {
buffer: Vec<u8>,
@ -45,124 +12,6 @@ pub struct VulkanDescriptorBufferSetWriter<'a> {
set: &'a mut [u8],
}
impl VulkanDescriptorBufferCache {
pub fn new(
device: &Rc<VulkanDevice>,
allocator: &Rc<VulkanAllocator>,
has_sampler: bool,
) -> Self {
Self {
device: device.clone(),
allocator: allocator.clone(),
buffers: Default::default(),
has_sampler,
}
}
pub fn allocate(
self: &Rc<Self>,
capacity: DeviceSize,
) -> Result<VulkanDescriptorBuffer, VulkanError> {
const MIN_ALLOCATION: DeviceSize = 1024;
let capacity = capacity.max(MIN_ALLOCATION);
let mut smallest = None;
let mut smallest_size = DeviceSize::MAX;
let mut fitting = None;
let mut fitting_size = DeviceSize::MAX;
let buffers = &mut *self.buffers.borrow_mut();
for (idx, buffer) in buffers.iter().enumerate() {
if buffer.size >= capacity {
if buffer.size < fitting_size {
fitting = Some(idx);
fitting_size = buffer.size;
}
} else {
if buffer.size < smallest_size {
smallest = Some(idx);
smallest_size = buffer.size;
}
}
}
if let Some(idx) = fitting {
return Ok(VulkanDescriptorBuffer {
cache: self.clone(),
buffer: ManuallyDrop::new(buffers.swap_remove(idx)),
});
}
if let Some(idx) = smallest {
log::debug!("discarding size {}", smallest_size);
buffers.swap_remove(idx);
}
let size = capacity.checked_next_power_of_two().unwrap();
log::debug!("allocating size {}", size);
let buffer = {
let usage = self.usage();
let info = BufferCreateInfo::default().size(size).usage(usage);
unsafe {
self.device
.device
.create_buffer(&info, None)
.map_err(VulkanError::CreateBuffer)?
}
};
let destroy_buffer = OnDrop(|| unsafe { self.device.device.destroy_buffer(buffer, None) });
let memory_requirements =
unsafe { self.device.device.get_buffer_memory_requirements(buffer) };
let allocation = {
let flags = UsageFlags::UPLOAD
| UsageFlags::FAST_DEVICE_ACCESS
| UsageFlags::HOST_ACCESS
| UsageFlags::DEVICE_ADDRESS;
self.allocator.alloc(&memory_requirements, flags, true)?
};
unsafe {
self.device
.device
.bind_buffer_memory(buffer, allocation.memory, allocation.offset)
.map_err(VulkanError::BindBufferMemory)?;
}
destroy_buffer.forget();
let address = {
let info = BufferDeviceAddressInfo::default().buffer(buffer);
unsafe { self.device.device.get_buffer_device_address(&info) }
};
Ok(VulkanDescriptorBuffer {
cache: self.clone(),
buffer: ManuallyDrop::new(VulkanDescriptorBufferUnused {
device: self.device.clone(),
size,
buffer,
allocation,
address,
}),
})
}
pub fn usage(&self) -> BufferUsageFlags {
let mut usage = BufferUsageFlags::RESOURCE_DESCRIPTOR_BUFFER_EXT
| BufferUsageFlags::SHADER_DEVICE_ADDRESS;
if self.has_sampler {
usage |= BufferUsageFlags::SAMPLER_DESCRIPTOR_BUFFER_EXT;
}
usage
}
}
impl Drop for VulkanDescriptorBuffer {
fn drop(&mut self) {
let buffer = unsafe { ManuallyDrop::take(&mut self.buffer) };
self.cache.buffers.borrow_mut().push(buffer);
}
}
impl Drop for VulkanDescriptorBufferUnused {
fn drop(&mut self) {
unsafe {
self.device.device.destroy_buffer(self.buffer, None);
}
}
}
impl VulkanDescriptorBufferWriter {
pub fn clear(&mut self) {
self.buffer.clear();

View file

@ -10,11 +10,10 @@ use {
gfx_apis::vulkan::{
VulkanError,
allocator::{VulkanAllocator, VulkanThreadedAllocator},
buffer_cache::{VulkanBuffer, VulkanBufferCache},
command::{VulkanCommandBuffer, VulkanCommandPool},
descriptor::VulkanDescriptorSetLayout,
descriptor_buffer::{
VulkanDescriptorBuffer, VulkanDescriptorBufferCache, VulkanDescriptorBufferWriter,
},
descriptor_buffer::VulkanDescriptorBufferWriter,
device::VulkanDevice,
fence::VulkanFence,
image::{QueueFamily, QueueState, QueueTransfer, VulkanImage, VulkanImageMemory},
@ -95,8 +94,8 @@ pub struct VulkanRenderer {
pub(super) pending_cpu_jobs: CopyHashMap<u64, PendingJob>,
pub(super) shm_allocator: Rc<VulkanThreadedAllocator>,
pub(super) sampler: Rc<VulkanSampler>,
pub(super) sampler_descriptor_buffer_cache: Rc<VulkanDescriptorBufferCache>,
pub(super) resource_descriptor_buffer_cache: Rc<VulkanDescriptorBufferCache>,
pub(super) sampler_descriptor_buffer_cache: Rc<VulkanBufferCache>,
pub(super) resource_descriptor_buffer_cache: Rc<VulkanBufferCache>,
pub(super) blend_buffers: RefCell<AHashMap<(u32, u32), Weak<VulkanImage>>>,
}
@ -149,7 +148,7 @@ pub(super) struct Memory {
wait_semaphore_infos: Vec<SemaphoreSubmitInfo<'static>>,
release_fence: Option<Rc<VulkanFence>>,
release_sync_file: Option<SyncFile>,
descriptor_buffers: ArrayVec<VulkanDescriptorBuffer, 2>,
descriptor_buffers: ArrayVec<VulkanBuffer, 2>,
paint_bounds: StaticMap<RenderPass, Option<PaintRegion>>,
paint_regions: StaticMap<RenderPass, Vec<PaintRegion>>,
clear_rects: StaticMap<RenderPass, Vec<ClearRect>>,
@ -212,7 +211,7 @@ pub(super) struct PendingFrame {
wait_semaphores: Cell<Vec<Rc<VulkanSemaphore>>>,
waiter: Cell<Option<SpawnedFuture<()>>>,
_release_fence: Option<Rc<VulkanFence>>,
_descriptor_buffers: ArrayVec<VulkanDescriptorBuffer, 2>,
_descriptor_buffers: ArrayVec<VulkanBuffer, 2>,
}
pub(super) struct VulkanFormatPipelines {
@ -289,9 +288,9 @@ impl VulkanDevice {
let allocator = self.create_allocator()?;
let shm_allocator = self.create_threaded_allocator()?;
let sampler_descriptor_buffer_cache =
Rc::new(VulkanDescriptorBufferCache::new(self, &allocator, true));
VulkanBufferCache::for_descriptor_buffer(self, &allocator, true);
let resource_descriptor_buffer_cache =
Rc::new(VulkanDescriptorBufferCache::new(self, &allocator, false));
VulkanBufferCache::for_descriptor_buffer(self, &allocator, false);
let render = Rc::new(VulkanRenderer {
formats: Rc::new(formats),
device: self.clone(),