vulkan: replace DescriptorBufferCache by generic cache
This commit is contained in:
parent
c16ea9325e
commit
f84934bd9a
4 changed files with 169 additions and 162 deletions
|
|
@ -1,6 +1,7 @@
|
|||
mod allocator;
|
||||
mod blend_buffer;
|
||||
mod bo_allocator;
|
||||
mod buffer_cache;
|
||||
mod command;
|
||||
mod descriptor;
|
||||
mod descriptor_buffer;
|
||||
|
|
|
|||
158
src/gfx_apis/vulkan/buffer_cache.rs
Normal file
158
src/gfx_apis/vulkan/buffer_cache.rs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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(),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue