vk: use gpu-allocator for memory allocations

This commit is contained in:
chyyran 2023-02-09 18:11:34 -05:00
parent 336094cad9
commit 009e740610
16 changed files with 228 additions and 247 deletions

59
Cargo.lock generated
View file

@ -2,6 +2,15 @@
# It is not intended for manual editing.
version = 3
[[package]]
name = "addr2line"
version = "0.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a76fd60b23679b7d19bd066031410fb7e458ccc5e958eb5c325888ce4baedc97"
dependencies = [
"gimli",
]
[[package]]
name = "adler"
version = "1.0.2"
@ -64,6 +73,21 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
[[package]]
name = "backtrace"
version = "0.3.67"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "233d376d6d185f2a3093e58f283f60f880315b6c60075b01f36b3b85154564ca"
dependencies = [
"addr2line",
"cc",
"cfg-if",
"libc",
"miniz_oxide",
"object",
"rustc-demangle",
]
[[package]]
name = "bit-set"
version = "0.5.3"
@ -564,6 +588,12 @@ dependencies = [
"weezl",
]
[[package]]
name = "gimli"
version = "0.27.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "221996f774192f0f718773def8201c4ae31f02616a54ccfc2d358bb0e5cefdec"
[[package]]
name = "gl"
version = "0.14.0"
@ -625,6 +655,18 @@ version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b"
[[package]]
name = "gpu-allocator"
version = "0.22.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ce95f9e2e11c2c6fadfce42b5af60005db06576f231f5c92550fdded43c423e8"
dependencies = [
"ash",
"backtrace",
"log",
"thiserror",
]
[[package]]
name = "hashbrown"
version = "0.12.3"
@ -930,6 +972,7 @@ dependencies = [
"ash-window",
"bytemuck",
"glfw 0.49.1",
"gpu-allocator",
"librashader-common 0.1.0-rc.2",
"librashader-preprocess",
"librashader-presets 0.1.0-rc.2",
@ -937,6 +980,7 @@ dependencies = [
"librashader-runtime",
"librashader-spirv-cross",
"num",
"parking_lot",
"raw-window-handle 0.5.0",
"rayon",
"rustc-hash",
@ -1290,6 +1334,15 @@ dependencies = [
"malloc_buf",
]
[[package]]
name = "object"
version = "0.30.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ea86265d3d3dcb6a27fc51bd29a4bf387fae9d2986b823079d4986af253eb439"
dependencies = [
"memchr",
]
[[package]]
name = "once_cell"
version = "1.17.0"
@ -1483,6 +1536,12 @@ dependencies = [
"spirv",
]
[[package]]
name = "rustc-demangle"
version = "0.1.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342"
[[package]]
name = "rustc-hash"
version = "1.1.0"

View file

@ -121,7 +121,7 @@ Please report an issue if you run into a shader that works in RetroArch, but not
* The Vulkan runtime uses [`VK_KHR_dynamic_rendering`](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_KHR_dynamic_rendering.html) by default.
This extension must be enabled at device creation. Explicit render passes can be used by configuring filter chain options, but may have reduced performance
compared to dynamic rendering.
* UBOs use multiple discontiguous buffers. This may be improved in the future by switching to VMA rather than manually handling allocations.
* Allocations within the runtime are done through [gpu-allocator](https://github.com/Traverse-Research/gpu-allocator) rather than handled manually.
* Direct3D 11
* Framebuffer copies are done via `ID3D11DeviceContext::CopySubresourceRegion` rather than a CPU conversion + copy.
* Direct3D 12

View file

@ -24,7 +24,8 @@ rustc-hash = "1.1.0"
bytemuck = "1.12.3"
thiserror = "1.0.37"
ash = { version = "0.37.1+1.3.235", features = ["linked", "debug"] }
gpu-allocator = { version = "0.22.0", default-features = false, features = ["vulkan"] }
parking_lot = "0.12.1"
rayon = "1.6.1"
[dev-dependencies]

View file

@ -1,7 +1,9 @@
use crate::error;
use crate::vulkan_primitives::VulkanBuffer;
use crate::memory::VulkanBuffer;
use ash::vk;
use gpu_allocator::vulkan::Allocator;
use librashader_runtime::quad::QuadType;
use parking_lot::RwLock;
use std::sync::Arc;
#[rustfmt::skip]
@ -30,25 +32,23 @@ pub struct DrawQuad {
impl DrawQuad {
pub fn new(
device: &Arc<ash::Device>,
mem_props: &vk::PhysicalDeviceMemoryProperties,
allocator: &Arc<RwLock<Allocator>>,
) -> error::Result<DrawQuad> {
let mut buffer = VulkanBuffer::new(
device,
mem_props,
allocator,
vk::BufferUsageFlags::VERTEX_BUFFER,
2 * std::mem::size_of::<[f32; 16]>(),
)?;
{
let mut map = buffer.map()?;
unsafe {
map.copy_from(0, bytemuck::cast_slice(VBO_OFFSCREEN));
map.copy_from(
std::mem::size_of::<[f32; 16]>(),
bytemuck::cast_slice(VBO_DEFAULT_FINAL),
);
}
let slice = buffer.as_mut_slice()?;
slice[0..std::mem::size_of::<[f32; 16]>()]
.copy_from_slice(bytemuck::cast_slice(VBO_OFFSCREEN));
slice[std::mem::size_of::<[f32; 16]>()..]
.copy_from_slice(bytemuck::cast_slice(VBO_DEFAULT_FINAL));
}
Ok(DrawQuad {
buffer,
device: device.clone(),

View file

@ -1,4 +1,5 @@
//! Vulkan shader runtime errors.
use gpu_allocator::AllocationError;
use librashader_preprocess::PreprocessError;
use librashader_presets::ParsePresetError;
use librashader_reflect::error::{ShaderCompileError, ShaderReflectError};
@ -24,6 +25,10 @@ pub enum FilterChainError {
VulkanResult(#[from] ash::vk::Result),
#[error("could not find a valid vulkan memory type")]
VulkanMemoryError(u32),
#[error("could not allocate gpu memory")]
AllocationError(#[from] AllocationError),
#[error("allocation is already freed")]
AllocationDoesNotExist,
}
/// Result type for Vulkan filter chains.

View file

@ -4,15 +4,16 @@ use crate::filter_pass::FilterPass;
use crate::framebuffer::OutputImage;
use crate::graphics_pipeline::VulkanGraphicsPipeline;
use crate::luts::LutTexture;
use crate::memory::RawVulkanBuffer;
use crate::options::{FilterChainOptionsVulkan, FrameOptionsVulkan};
use crate::queue_selection::get_graphics_queue;
use crate::samplers::SamplerSet;
use crate::texture::{InputImage, OwnedImage, OwnedImageLayout, VulkanImage};
use crate::vulkan_primitives::RawVulkanBuffer;
use crate::{error, util};
use ash::vk;
use librashader_common::{ImageFormat, Size, Viewport};
use gpu_allocator::vulkan::Allocator;
use librashader_presets::{ShaderPreset, TextureConfig};
use librashader_reflect::back::targets::SPIRV;
use librashader_reflect::back::{CompileReflectShader, CompileShader};
@ -24,6 +25,7 @@ use librashader_runtime::binding::BindingUtil;
use librashader_runtime::image::{Image, UVDirection};
use librashader_runtime::quad::QuadType;
use librashader_runtime::uniforms::UniformStorage;
use parking_lot::RwLock;
use rustc_hash::FxHashMap;
use std::collections::VecDeque;
use std::path::Path;
@ -36,9 +38,10 @@ use rayon::prelude::*;
/// A Vulkan device and metadata that is required by the shader runtime.
pub struct VulkanObjects {
pub(crate) device: Arc<ash::Device>,
pub(crate) memory_properties: vk::PhysicalDeviceMemoryProperties,
pub(crate) alloc: Arc<RwLock<Allocator>>,
queue: vk::Queue,
pipeline_cache: vk::PipelineCache,
// pub(crate) memory_properties: vk::PhysicalDeviceMemoryProperties,
}
type ShaderPassMeta =
@ -75,26 +78,28 @@ impl TryFrom<VulkanInstance> for VulkanObjects {
device.create_pipeline_cache(&vk::PipelineCacheCreateInfo::default(), None)?;
let queue = get_graphics_queue(&instance, &device, vulkan.physical_device);
let memory_properties =
instance.get_physical_device_memory_properties(vulkan.physical_device);
// let memory_properties =
// instance.get_physical_device_memory_properties(vulkan.physical_device);
let alloc = util::create_allocator(device.clone(), instance, vulkan.physical_device)?;
Ok(VulkanObjects {
device: Arc::new(device),
alloc,
queue,
pipeline_cache,
memory_properties,
// memory_properties,
// debug,
})
}
}
}
impl TryFrom<(vk::PhysicalDevice, ash::Instance, Arc<ash::Device>)> for VulkanObjects {
impl TryFrom<(vk::PhysicalDevice, ash::Instance, ash::Device)> for VulkanObjects {
type Error = FilterChainError;
fn try_from(
value: (vk::PhysicalDevice, ash::Instance, Arc<ash::Device>),
) -> error::Result<Self> {
fn try_from(value: (vk::PhysicalDevice, ash::Instance, ash::Device)) -> error::Result<Self> {
unsafe {
let device = value.2;
@ -103,13 +108,16 @@ impl TryFrom<(vk::PhysicalDevice, ash::Instance, Arc<ash::Device>)> for VulkanOb
let queue = get_graphics_queue(&value.1, &device, value.0);
let memory_properties = value.1.get_physical_device_memory_properties(value.0);
// let memory_properties = value.1.get_physical_device_memory_properties(value.0);
let alloc = util::create_allocator(device.clone(), value.1, value.0)?;
Ok(VulkanObjects {
device,
alloc,
device: Arc::new(device),
queue,
pipeline_cache,
memory_properties,
// memory_properties,
// debug: value.3,
})
}
@ -288,7 +296,7 @@ impl FilterChainVulkan {
.map(|param| (param.name, param.value))
.collect(),
},
draw_quad: DrawQuad::new(&device.device, &device.memory_properties)?,
draw_quad: DrawQuad::new(&device.device, &device.alloc)?,
device: device.device.clone(),
output_inputs: output_textures.into_boxed_slice(),
feedback_inputs: feedback_textures.into_boxed_slice(),
@ -324,7 +332,7 @@ impl FilterChainVulkan {
let uniform_storage = UniformStorage::new_with_ubo_storage(
RawVulkanBuffer::new(
&vulkan.device,
&vulkan.memory_properties,
&vulkan.alloc,
vk::BufferUsageFlags::UNIFORM_BUFFER,
ubo_size,
)?,

View file

@ -1,9 +1,9 @@
use crate::filter_chain::FilterCommon;
use crate::framebuffer::OutputImage;
use crate::graphics_pipeline::VulkanGraphicsPipeline;
use crate::memory::RawVulkanBuffer;
use crate::samplers::SamplerSet;
use crate::texture::InputImage;
use crate::vulkan_primitives::RawVulkanBuffer;
use crate::{error, VulkanImage};
use ash::vk;
use librashader_common::{ImageFormat, Size, Viewport};

View file

@ -22,6 +22,7 @@ use ash::vk;
use librashader_common::Viewport;
use crate::options::FrameOptionsVulkan;
use winit::event::{ElementState, Event, KeyboardInput, VirtualKeyCode, WindowEvent};
use winit::event_loop::{ControlFlow, EventLoop, EventLoopBuilder};
use winit::platform::windows::EventLoopBuilderExtWindows;
@ -256,7 +257,10 @@ impl VulkanWindow {
},
cmd,
frame,
None,
Some(&FrameOptionsVulkan {
clear_history: frame == 0,
frame_direction: 0,
}),
)
.unwrap();

View file

@ -1,7 +1,6 @@
use crate::hello_triangle::surface::VulkanSurface;
use crate::hello_triangle::vulkan_base::VulkanBase;
use crate::util::find_vulkan_memory_type;
use crate::vulkan_primitives::VulkanImageMemory;
use crate::memory::VulkanImageMemory;
use ash::prelude::VkResult;
use ash::vk;
use ash::vk::Extent3D;
@ -95,33 +94,9 @@ impl VulkanSwapchain {
let image = base.device.create_image(&create_info, None)?;
let mem_reqs = unsafe { base.device.get_image_memory_requirements(image) };
// base.debug
// .loader
// .set_debug_utils_object_name(
// base.device.handle(),
// &vk::DebugUtilsObjectNameInfoEXT::builder()
// .object_handle(image.as_raw())
// .object_name(CStr::from_bytes_with_nul_unchecked(b"RenderImage\0"))
// .object_type(vk::ObjectType::IMAGE)
// .build(),
// )
// .expect("could not set object name");
let alloc_info = vk::MemoryAllocateInfo::builder()
.allocation_size(mem_reqs.size)
.memory_type_index(
find_vulkan_memory_type(
&base.mem_props,
mem_reqs.memory_type_bits,
vk::MemoryPropertyFlags::DEVICE_LOCAL,
)
.unwrap(),
)
.build();
// todo: optimize by reusing existing memory.
let memory = VulkanImageMemory::new(&base.device, &alloc_info).unwrap();
memory.bind(&image).unwrap();
let memory =
VulkanImageMemory::new(&base.device, &base.allocator, mem_reqs, &image)
.unwrap();
render_images.push((image, memory))
}

View file

@ -5,7 +5,10 @@ use crate::filter_chain::VulkanObjects;
use crate::hello_triangle::physicaldevice::{find_queue_family, pick_physical_device};
use crate::util;
use ash::prelude::VkResult;
use gpu_allocator::vulkan::{Allocator, AllocatorCreateDesc};
use parking_lot::RwLock;
use std::ffi::CStr;
use std::sync::Arc;
@ -20,6 +23,7 @@ pub struct VulkanBase {
// pub debug: VulkanDebug,
pub physical_device: vk::PhysicalDevice,
pub mem_props: vk::PhysicalDeviceMemoryProperties,
pub allocator: Arc<RwLock<Allocator>>,
}
impl VulkanBase {
@ -61,6 +65,10 @@ impl VulkanBase {
let mem_props = unsafe { instance.get_physical_device_memory_properties(physical_device) };
dbg!("got memprops");
let alloc =
util::create_allocator(device.clone(), instance.clone(), physical_device.clone())
.expect("could not create allocator");
Ok(VulkanBase {
entry,
instance,
@ -69,6 +77,7 @@ impl VulkanBase {
physical_device,
mem_props,
// debug,
allocator: alloc,
})
}
@ -161,10 +170,8 @@ impl TryFrom<&VulkanBase> for VulkanObjects {
type Error = FilterChainError;
fn try_from(value: &VulkanBase) -> Result<Self, Self::Error> {
VulkanObjects::try_from((
value.physical_device,
value.instance.clone(),
value.device.clone(),
))
let device = (*value.device).clone();
VulkanObjects::try_from((value.physical_device, value.instance.clone(), device))
}
}

View file

@ -15,12 +15,12 @@ mod graphics_pipeline;
#[cfg(test)]
mod hello_triangle;
mod luts;
mod memory;
mod parameters;
mod queue_selection;
mod samplers;
mod texture;
mod util;
mod vulkan_primitives;
pub use filter_chain::FilterChainVulkan;
pub use filter_chain::VulkanInstance;

View file

@ -1,6 +1,6 @@
use crate::filter_chain::VulkanObjects;
use crate::memory::{VulkanBuffer, VulkanImageMemory};
use crate::texture::{InputImage, VulkanImage};
use crate::vulkan_primitives::{VulkanBuffer, VulkanImageMemory};
use crate::{error, util};
use ash::vk;
use librashader_presets::TextureConfig;
@ -46,21 +46,14 @@ impl LutTexture {
let memory = unsafe {
let mem_reqs = vulkan.device.get_image_memory_requirements(texture);
let mem_type = util::find_vulkan_memory_type(
&vulkan.memory_properties,
mem_reqs.memory_type_bits,
vk::MemoryPropertyFlags::DEVICE_LOCAL,
)?;
VulkanImageMemory::new(
&vulkan.device,
&vk::MemoryAllocateInfo::builder()
.memory_type_index(mem_type)
.allocation_size(mem_reqs.size),
)?
// let mem_type = util::find_vulkan_memory_type(
// &vulkan.memory_properties,
// mem_reqs.memory_type_bits,
// vk::MemoryPropertyFlags::DEVICE_LOCAL,
// )?;
VulkanImageMemory::new(&vulkan.device, &vulkan.alloc, mem_reqs, &texture)?
};
memory.bind(&texture)?;
let image_subresource = vk::ImageSubresourceRange::builder()
.level_count(image_info.mip_levels)
.layer_count(1)
@ -86,14 +79,12 @@ impl LutTexture {
let mut staging = VulkanBuffer::new(
&vulkan.device,
&vulkan.memory_properties,
&vulkan.alloc,
vk::BufferUsageFlags::TRANSFER_SRC,
image.bytes.len(),
)?;
unsafe {
let mut handle = staging.map()?;
handle.copy_from(0, &image.bytes)
}
staging.as_mut_slice()?.copy_from_slice(&image.bytes);
unsafe {
util::vulkan_image_layout_transition_levels(

View file

@ -1,6 +1,11 @@
use crate::{error, util};
use crate::error;
use crate::error::FilterChainError;
use ash::vk;
use gpu_allocator::vulkan::{Allocation, AllocationCreateDesc, AllocationScheme, Allocator};
use gpu_allocator::MemoryLocation;
use librashader_runtime::uniforms::UniformStorageAccess;
use parking_lot::RwLock;
use std::ffi::c_void;
use std::mem::ManuallyDrop;
use std::ops::{Deref, DerefMut};
@ -8,32 +13,46 @@ use std::ptr::NonNull;
use std::sync::Arc;
pub struct VulkanImageMemory {
pub handle: vk::DeviceMemory,
allocation: Option<Allocation>,
allocator: Arc<RwLock<Allocator>>,
device: Arc<ash::Device>,
}
impl VulkanImageMemory {
pub fn new(
device: &Arc<ash::Device>,
alloc: &vk::MemoryAllocateInfo,
allocator: &Arc<RwLock<Allocator>>,
requirements: vk::MemoryRequirements,
image: &vk::Image,
) -> error::Result<VulkanImageMemory> {
let allocation = allocator.write().allocate(&AllocationCreateDesc {
name: "imagemem",
requirements,
location: MemoryLocation::GpuOnly,
linear: false,
allocation_scheme: AllocationScheme::DedicatedImage(*image),
})?;
unsafe {
device.bind_image_memory(*image, allocation.memory(), 0)?;
Ok(VulkanImageMemory {
handle: device.allocate_memory(alloc, None)?,
device: device.clone(),
allocation: Some(allocation),
allocator: Arc::clone(allocator),
device: Arc::clone(device),
})
}
}
pub fn bind(&self, image: &vk::Image) -> error::Result<()> {
unsafe { Ok(self.device.bind_image_memory(*image, self.handle, 0)?) }
}
}
impl Drop for VulkanImageMemory {
fn drop(&mut self) {
unsafe {
self.device.free_memory(self.handle, None);
let allocation = self.allocation.take();
if let Some(allocation) = allocation {
if let Err(e) = self.allocator.write().free(allocation) {
println!("librashader-runtime-vk: [warn] failed to deallocate image buffer {e}")
}
}
}
}
}
@ -41,19 +60,15 @@ impl Drop for VulkanImageMemory {
pub struct VulkanBuffer {
pub handle: vk::Buffer,
device: Arc<ash::Device>,
memory: vk::DeviceMemory,
memory: Option<Allocation>,
allocator: Arc<RwLock<Allocator>>,
size: vk::DeviceSize,
}
pub struct VulkanBufferMapHandle<'a> {
buffer: &'a mut VulkanBuffer,
ptr: *mut c_void,
}
impl VulkanBuffer {
pub fn new(
device: &Arc<ash::Device>,
mem_props: &vk::PhysicalDeviceMemoryProperties,
allocator: &Arc<RwLock<Allocator>>,
usage: vk::BufferUsageFlags,
size: usize,
) -> error::Result<VulkanBuffer> {
@ -66,45 +81,48 @@ impl VulkanBuffer {
let buffer = device.create_buffer(&buffer_info, None)?;
let memory_reqs = device.get_buffer_memory_requirements(buffer);
let alloc_info = vk::MemoryAllocateInfo::builder()
.allocation_size(memory_reqs.size)
.memory_type_index(util::find_vulkan_memory_type(
mem_props,
memory_reqs.memory_type_bits,
vk::MemoryPropertyFlags::HOST_VISIBLE | vk::MemoryPropertyFlags::HOST_COHERENT,
)?)
.build();
let alloc = device.allocate_memory(&alloc_info, None)?;
device.bind_buffer_memory(buffer, alloc, 0)?;
let alloc = allocator.write().allocate(&AllocationCreateDesc {
name: "buffer",
requirements: memory_reqs,
location: MemoryLocation::CpuToGpu,
linear: true,
allocation_scheme: AllocationScheme::DedicatedBuffer(buffer),
})?;
// let alloc = device.allocate_memory(&alloc_info, None)?;
device.bind_buffer_memory(buffer, alloc.memory(), 0)?;
Ok(VulkanBuffer {
handle: buffer,
memory: alloc,
memory: Some(alloc),
allocator: Arc::clone(allocator),
size: size as vk::DeviceSize,
device: device.clone(),
})
}
}
pub fn map(&mut self) -> error::Result<VulkanBufferMapHandle> {
let dst = unsafe {
self.device
.map_memory(self.memory, 0, self.size, vk::MemoryMapFlags::empty())?
pub fn as_mut_slice(&mut self) -> error::Result<&mut [u8]> {
let Some(allocation) = self.memory.as_mut() else {
return Err(FilterChainError::AllocationDoesNotExist)
};
Ok(VulkanBufferMapHandle {
buffer: self,
ptr: dst,
})
let Some(allocation) = allocation.mapped_slice_mut() else {
return Err(FilterChainError::AllocationDoesNotExist)
};
Ok(allocation)
}
}
impl Drop for VulkanBuffer {
fn drop(&mut self) {
unsafe {
if self.memory != vk::DeviceMemory::null() {
self.device.free_memory(self.memory, None);
if let Some(allocation) = self.memory.take() {
if let Err(e) = self.allocator.write().free(allocation) {
println!(
"librashader-runtime-vk: [warn] failed to deallocate buffer memory {e}"
)
}
}
if self.handle != vk::Buffer::null() {
@ -114,26 +132,6 @@ impl Drop for VulkanBuffer {
}
}
impl<'a> VulkanBufferMapHandle<'a> {
pub unsafe fn copy_from(&mut self, offset: usize, src: &[u8]) {
let mut align = ash::util::Align::new(
self.ptr
.map_addr(|original| original.wrapping_add(offset))
.cast(),
std::mem::align_of::<u8>() as u64,
self.buffer.size,
);
align.copy_from_slice(src);
}
}
impl<'a> Drop for VulkanBufferMapHandle<'a> {
fn drop(&mut self) {
unsafe { self.buffer.device.unmap_memory(self.buffer.memory) }
}
}
/// SAFETY: Creating the pointer should be safe in multithreaded contexts.
///
/// Mutation is guarded by DerefMut<Target=[u8]>
@ -146,18 +144,17 @@ pub struct RawVulkanBuffer {
impl RawVulkanBuffer {
pub fn new(
device: &Arc<ash::Device>,
mem_props: &vk::PhysicalDeviceMemoryProperties,
allocator: &Arc<RwLock<Allocator>>,
usage: vk::BufferUsageFlags,
size: usize,
) -> error::Result<Self> {
let buffer = ManuallyDrop::new(VulkanBuffer::new(device, mem_props, usage, size)?);
let ptr = unsafe {
NonNull::new_unchecked(device.map_memory(
buffer.memory,
0,
buffer.size,
vk::MemoryMapFlags::empty(),
)?)
let buffer = ManuallyDrop::new(VulkanBuffer::new(device, allocator, usage, size)?);
let Some(ptr) = buffer.memory
.as_ref()
.map(|m| m.mapped_ptr())
.flatten() else {
return Err(FilterChainError::AllocationDoesNotExist)
};
Ok(RawVulkanBuffer { buffer, ptr })
@ -193,12 +190,7 @@ impl RawVulkanBuffer {
impl Drop for RawVulkanBuffer {
fn drop(&mut self) {
unsafe {
self.buffer.device.unmap_memory(self.buffer.memory);
self.ptr = NonNull::dangling();
if self.buffer.memory != vk::DeviceMemory::null() {
self.buffer.device.free_memory(self.buffer.memory, None);
}
ManuallyDrop::drop(&mut self.buffer);
if self.buffer.handle != vk::Buffer::null() {
self.buffer.device.destroy_buffer(self.buffer.handle, None);
}

View file

@ -1,8 +1,9 @@
use crate::filter_chain::VulkanObjects;
use crate::util::find_vulkan_memory_type;
use crate::vulkan_primitives::VulkanImageMemory;
use crate::memory::VulkanImageMemory;
use crate::{error, util};
use ash::vk;
use gpu_allocator::vulkan::Allocator;
use parking_lot::RwLock;
use std::sync::Arc;
use crate::error::FilterChainError;
@ -12,7 +13,7 @@ use librashader_runtime::scaling::{MipmapSize, ScaleFramebuffer, ViewportSize};
pub struct OwnedImage {
pub device: Arc<ash::Device>,
pub mem_props: vk::PhysicalDeviceMemoryProperties,
pub allocator: Arc<RwLock<Allocator>>,
pub image_view: vk::ImageView,
pub image: VulkanImage,
pub memory: VulkanImageMemory,
@ -32,7 +33,7 @@ pub struct OwnedImageLayout {
impl OwnedImage {
fn new_internal(
device: Arc<ash::Device>,
mem_props: vk::PhysicalDeviceMemoryProperties,
alloc: &Arc<RwLock<Allocator>>,
size: Size<u32>,
mut format: ImageFormat,
max_miplevels: u32,
@ -63,19 +64,7 @@ impl OwnedImage {
let image = unsafe { device.create_image(&image_create_info, None)? };
let mem_reqs = unsafe { device.get_image_memory_requirements(image) };
let alloc_info = vk::MemoryAllocateInfo::builder()
.allocation_size(mem_reqs.size)
.memory_type_index(find_vulkan_memory_type(
&mem_props,
mem_reqs.memory_type_bits,
vk::MemoryPropertyFlags::DEVICE_LOCAL,
)?)
.build();
// todo: optimize by reusing existing memory.
let memory = VulkanImageMemory::new(&device, &alloc_info)?;
memory.bind(&image)?;
let memory = VulkanImageMemory::new(&device, alloc, mem_reqs, &image)?;
let image_subresource = vk::ImageSubresourceRange::builder()
.base_mip_level(0)
.base_array_layer(0)
@ -103,7 +92,7 @@ impl OwnedImage {
Ok(OwnedImage {
device,
mem_props,
allocator: Arc::clone(alloc),
image_view,
image: VulkanImage {
image,
@ -124,7 +113,7 @@ impl OwnedImage {
) -> error::Result<OwnedImage> {
Self::new_internal(
vulkan.device.clone(),
vulkan.memory_properties,
&vulkan.alloc,
size,
format,
max_miplevels,
@ -150,7 +139,7 @@ impl OwnedImage {
let new = OwnedImage::new_internal(
self.device.clone(),
self.mem_props,
&self.allocator,
size,
if format == ImageFormat::Unknown {
ImageFormat::R8G8B8A8Unorm

View file

@ -1,70 +0,0 @@
use crate::error;
use crate::vulkan_primitives::VulkanBuffer;
use ash::vk;
use librashader_runtime::ringbuffer::{BoxRingBuffer, RingBuffer};
use librashader_runtime::uniforms::UniformStorageAccess;
use std::sync::Arc;
pub struct VkUboRing {
ring: BoxRingBuffer<VulkanBuffer>,
device: Arc<ash::Device>,
}
impl VkUboRing {
pub fn new(
device: &Arc<ash::Device>,
mem_props: &vk::PhysicalDeviceMemoryProperties,
ring_size: usize,
buffer_size: usize,
) -> error::Result<Self> {
let mut ring = Vec::new();
for _ in 0..ring_size {
ring.push(VulkanBuffer::new(
device,
mem_props,
vk::BufferUsageFlags::UNIFORM_BUFFER,
buffer_size,
)?);
}
Ok(VkUboRing {
ring: BoxRingBuffer::from_vec(ring),
device: device.clone(),
})
}
pub fn bind_to_descriptor_set(
&mut self,
descriptor_set: vk::DescriptorSet,
binding: u32,
storage: &impl UniformStorageAccess,
) -> error::Result<()> {
// todo: write directly to allocated buffer.
unsafe {
let buffer = self.ring.current_mut();
let mut map = buffer.map()?;
map.copy_from(0, storage.ubo_slice())
}
let buffer = self.ring.current();
unsafe {
let buffer_info = [vk::DescriptorBufferInfo::builder()
.buffer(buffer.handle)
.offset(0)
.range(storage.ubo_slice().len() as vk::DeviceSize)
.build()];
let write_info = [vk::WriteDescriptorSet::builder()
.descriptor_type(vk::DescriptorType::UNIFORM_BUFFER)
.dst_set(descriptor_set)
.dst_binding(binding)
.dst_array_element(0)
.buffer_info(&buffer_info)
.build()];
self.device.update_descriptor_sets(&write_info, &[])
}
self.ring.next();
Ok(())
}
}

View file

@ -1,4 +1,8 @@
use ash::vk;
use gpu_allocator::vulkan::{Allocator, AllocatorCreateDesc};
use gpu_allocator::AllocatorDebugSettings;
use parking_lot::RwLock;
use std::sync::Arc;
use crate::error;
use crate::error::FilterChainError;
@ -17,6 +21,7 @@ pub fn binding_stage_to_vulkan_stage(stage_mask: BindingStage) -> vk::ShaderStag
mask
}
#[allow(unused)]
pub fn find_vulkan_memory_type(
props: &vk::PhysicalDeviceMemoryProperties,
device_reqs: u32,
@ -81,3 +86,18 @@ pub unsafe fn vulkan_image_layout_transition_levels(
&[barrier],
)
}
pub fn create_allocator(
device: ash::Device,
instance: ash::Instance,
physical_device: vk::PhysicalDevice,
) -> error::Result<Arc<RwLock<Allocator>>> {
let alloc = Allocator::new(&AllocatorCreateDesc {
instance,
device,
physical_device,
debug_settings: Default::default(),
buffer_device_address: false,
})?;
Ok(Arc::new(RwLock::new(alloc)))
}