vk: create raii buffer abstraction

This commit is contained in:
chyyran 2022-12-11 01:06:28 -05:00
parent 53e3b5c2d1
commit e428e02dfe
7 changed files with 211 additions and 95 deletions

View file

@ -0,0 +1,15 @@
static VBO_OFFSCREEN_MVP: &[f32; 16] = &[
// Offscreen
-1.0, -1.0, 0.0, 0.0,
-1.0, 1.0, 0.0, 1.0,
1.0, -1.0, 1.0, 0.0,
1.0, 1.0, 1.0, 1.0,
];
static VBO_DEFAULT_FINAL_MVP: &[f32; 16] = &[
// Final
0.0, 0.0, 0.0, 0.0,
0.0, 1.0, 0.0, 1.0,
1.0, 0.0, 1.0, 0.0,
1.0, 1.0, 1.0, 1.0,
];

View file

@ -1,8 +1,7 @@
use std::error::Error;
use std::ffi::CStr;
use std::path::Path;
use ash::vk;
use ash::vk::{ColorComponentFlags, PFN_vkGetInstanceProcAddr, StaticFn};
use ash::vk::{PFN_vkGetInstanceProcAddr, StaticFn};
use rustc_hash::FxHashMap;
use librashader_common::ImageFormat;
use librashader_preprocess::ShaderSource;
@ -15,8 +14,7 @@ use librashader_reflect::reflect::semantics::{Semantic, ShaderSemantics, Texture
use librashader_runtime::uniforms::UniformStorage;
use crate::error;
use crate::filter_pass::FilterPass;
use crate::framebuffer::{Framebuffer, VulkanRenderPass};
use crate::vulkan_state::{PipelineLayoutObjects, VulkanGraphicsPipeline};
use crate::vulkan_state::VulkanGraphicsPipeline;
pub struct Vulkan {
physical_device: vk::PhysicalDevice,
@ -59,7 +57,7 @@ impl From<VulkanInfo<'_>> for ash::Device {
pub struct FilterChainVulkan {
pub(crate) common: FilterCommon,
pub(crate) passes: Vec<FilterPass>,
pub(crate) passes: Box<[FilterPass]>,
// pub(crate) output_framebuffers: Box<[OwnedFramebuffer]>,
// pub(crate) feedback_framebuffers: Box<[OwnedFramebuffer]>,
// pub(crate) history_framebuffers: VecDeque<OwnedFramebuffer>,
@ -100,7 +98,10 @@ impl FilterChainVulkan {
// initialize passes
let filters = Self::init_passes(&device, passes, &semantics, 3)?;
eprintln!("filters initialized ok.");
todo!();
Ok(FilterChainVulkan {
common: FilterCommon {},
passes: filters
})
}
fn load_preset(
@ -207,9 +208,7 @@ impl FilterChainVulkan {
let graphics_pipeline = VulkanGraphicsPipeline::new(device,
&pipeline_cache,
&spirv_words, &reflection, source.format, images)
.unwrap();
&spirv_words, &reflection, source.format, images)?;
// shader_vulkan: 2026
filters.push(FilterPass {
compiled: spirv_words,

View file

@ -1,9 +1,10 @@
use ash::vk;
use ash::vk::{AttachmentLoadOp, AttachmentStoreOp, DeviceSize, Extent2D, Extent3D, ImageAspectFlags, ImageLayout, ImageTiling, ImageType, ImageUsageFlags, ImageViewType, PipelineBindPoint, SampleCountFlags, SharingMode};
use glfw::Key::P;
use librashader_common::{ImageFormat, Size};
use ash::vk::{Extent3D, ImageAspectFlags, ImageLayout, ImageTiling, ImageType, ImageUsageFlags, ImageViewType, SampleCountFlags, SharingMode};
use librashader_common::Size;
use crate::error;
use crate::renderpass::VulkanRenderPass;
use crate::util::find_vulkan_memory_type;
use crate::vulkan_primitives::VulkanImageMemory;
pub struct Framebuffer {
device: ash::Device,
@ -20,37 +21,7 @@ pub struct VulkanFramebuffer {
pub image_view: vk::ImageView,
pub fb_view: vk::ImageView,
pub image: vk::Image,
pub memory: VulkanMemory,
}
pub struct VulkanMemory {
pub handle: vk::DeviceMemory,
device: ash::Device
}
impl VulkanMemory {
pub fn new(device: &ash::Device, alloc: &vk::MemoryAllocateInfo) -> error::Result<VulkanMemory> {
unsafe {
Ok(VulkanMemory {
handle: device.allocate_memory(alloc, None)?,
device: device.clone()
})
}
}
pub fn bind(&self, image: &vk::Image) -> error::Result<()>{
unsafe {
Ok(self.device.bind_image_memory(image.clone(), self.handle.clone(), 0)?)
}
}
}
impl Drop for VulkanMemory {
fn drop(&mut self) {
unsafe {
self.device.free_memory(self.handle, None);
}
}
pub memory: VulkanImageMemory,
}
impl Drop for VulkanFramebuffer {
@ -72,56 +43,6 @@ impl Drop for VulkanFramebuffer {
}
}
pub struct VulkanRenderPass {
pub render_pass: vk::RenderPass,
format: ImageFormat
}
impl VulkanRenderPass {
pub fn create_render_pass(device: &ash::Device, mut format: ImageFormat) -> error::Result<Self> {
// default to reasonable choice if unknown
if format == ImageFormat::Unknown {
format = ImageFormat::R8G8B8A8Unorm;
}
let attachment = vk::AttachmentDescription::builder()
.flags(vk::AttachmentDescriptionFlags::empty())
.format(format.into())
.samples(SampleCountFlags::TYPE_1)
.load_op(AttachmentLoadOp::DONT_CARE)
.store_op(AttachmentStoreOp::STORE)
.stencil_load_op(AttachmentLoadOp::DONT_CARE)
.stencil_store_op(AttachmentStoreOp::DONT_CARE)
.initial_layout(ImageLayout::COLOR_ATTACHMENT_OPTIMAL)
.final_layout(ImageLayout::COLOR_ATTACHMENT_OPTIMAL)
.build();
let attachment_ref = vk::AttachmentReference::builder()
.attachment(0)
.layout(ImageLayout::COLOR_ATTACHMENT_OPTIMAL)
.build();
let subpass = vk::SubpassDescription::builder()
.pipeline_bind_point(PipelineBindPoint::GRAPHICS)
.color_attachments(&[attachment_ref])
.build();
let renderpass_info = vk::RenderPassCreateInfo::builder()
.flags(vk::RenderPassCreateFlags::empty())
.attachments(&[attachment])
.subpasses(&[subpass])
.build();
unsafe {
let rp = device.create_render_pass(&renderpass_info, None)?;
Ok(Self {
render_pass: rp,
format
})
}
}
}
impl Framebuffer {
pub fn new(device: &ash::Device, size: Size<u32>, render_pass: VulkanRenderPass, mip_levels: u32, mem_props: vk::PhysicalDeviceMemoryProperties) -> error::Result<Self> {
let mut framebuffer = Framebuffer {
@ -166,7 +87,7 @@ impl Framebuffer {
.build();
// todo: optimize by reusing existing memory.
let memory = VulkanMemory::new(&self.device, &alloc_info)?;
let memory = VulkanImageMemory::new(&self.device, &alloc_info)?;
memory.bind(&image)?;
let image_subresource = vk::ImageSubresourceRange::builder()

View file

@ -8,6 +8,9 @@ mod error;
mod util;
mod framebuffer;
mod vulkan_state;
mod draw_quad;
mod renderpass;
mod vulkan_primitives;
#[cfg(test)]
mod tests {

View file

@ -0,0 +1,54 @@
use ash::vk;
use ash::vk::{AttachmentLoadOp, AttachmentStoreOp, ImageLayout, PipelineBindPoint, SampleCountFlags};
use librashader_common::ImageFormat;
use crate::error;
pub struct VulkanRenderPass {
pub render_pass: vk::RenderPass,
pub format: ImageFormat
}
impl VulkanRenderPass {
pub fn create_render_pass(device: &ash::Device, mut format: ImageFormat) -> error::Result<Self> {
// default to reasonable choice if unknown
if format == ImageFormat::Unknown {
format = ImageFormat::R8G8B8A8Unorm;
}
let attachment = vk::AttachmentDescription::builder()
.flags(vk::AttachmentDescriptionFlags::empty())
.format(format.into())
.samples(SampleCountFlags::TYPE_1)
.load_op(AttachmentLoadOp::DONT_CARE)
.store_op(AttachmentStoreOp::STORE)
.stencil_load_op(AttachmentLoadOp::DONT_CARE)
.stencil_store_op(AttachmentStoreOp::DONT_CARE)
.initial_layout(ImageLayout::COLOR_ATTACHMENT_OPTIMAL)
.final_layout(ImageLayout::COLOR_ATTACHMENT_OPTIMAL)
.build();
let attachment_ref = vk::AttachmentReference::builder()
.attachment(0)
.layout(ImageLayout::COLOR_ATTACHMENT_OPTIMAL)
.build();
let subpass = vk::SubpassDescription::builder()
.pipeline_bind_point(PipelineBindPoint::GRAPHICS)
.color_attachments(&[attachment_ref])
.build();
let renderpass_info = vk::RenderPassCreateInfo::builder()
.flags(vk::RenderPassCreateFlags::empty())
.attachments(&[attachment])
.subpasses(&[subpass])
.build();
unsafe {
let rp = device.create_render_pass(&renderpass_info, None)?;
Ok(Self {
render_pass: rp,
format
})
}
}
}

View file

@ -0,0 +1,124 @@
use std::ffi::c_void;
use ash::vk;
use crate::{error, util};
pub struct VulkanImageMemory {
pub handle: vk::DeviceMemory,
device: ash::Device
}
impl VulkanImageMemory {
pub fn new(device: &ash::Device, alloc: &vk::MemoryAllocateInfo) -> error::Result<VulkanImageMemory> {
unsafe {
Ok(VulkanImageMemory {
handle: device.allocate_memory(alloc, None)?,
device: device.clone()
})
}
}
pub fn bind(&self, image: &vk::Image) -> error::Result<()>{
unsafe {
Ok(self.device.bind_image_memory(image.clone(), self.handle.clone(), 0)?)
}
}
}
impl Drop for VulkanImageMemory {
fn drop(&mut self) {
unsafe {
self.device.free_memory(self.handle, None);
}
}
}
pub struct VulkanBuffer {
pub handle: vk::Buffer,
device: ash::Device,
pub memory: vk::DeviceMemory,
pub size: vk::DeviceSize,
}
pub struct VulkanBufferMapHandle<'a> {
buffer: &'a mut VulkanBuffer,
ptr: *mut c_void
}
impl VulkanBuffer {
pub fn new(device: &ash::Device, mem_props: &vk::PhysicalDeviceMemoryProperties, usage: vk::BufferUsageFlags,
size: usize) -> error::Result<VulkanBuffer> {
unsafe {
let buffer_info = vk::BufferCreateInfo::builder()
.size(size as vk::DeviceSize)
.usage(usage)
.sharing_mode(vk::SharingMode::EXCLUSIVE)
.build();
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.clone(), alloc.clone(), 0)?;
Ok(VulkanBuffer {
handle: buffer,
memory: alloc,
size: size as vk::DeviceSize,
device: device.clone()
})
}
}
pub unsafe fn copy_from(&mut self, buffer: &[u8]) -> error::Result<()> {
let dst = self.device.map_memory(self.memory, 0, self.size, vk::MemoryMapFlags::empty())?;
std::ptr::copy_nonoverlapping(buffer.as_ptr(), dst.cast(), buffer.len());
self.device.unmap_memory(self.memory);
Ok(())
}
pub fn map(&mut self) -> error::Result<VulkanBufferMapHandle> {
let dst =
unsafe {
self.device.map_memory(self.memory, 0, self.size, vk::MemoryMapFlags::empty())?
};
Ok(VulkanBufferMapHandle {
buffer: self,
ptr: dst,
})
}
}
impl Drop for VulkanBuffer {
fn drop(&mut self) {
unsafe {
if self.memory != vk::DeviceMemory::null() {
self.device.free_memory(self.memory, None);
}
if self.handle != vk::Buffer::null() {
self.device.destroy_buffer(self.handle, None);
}
}
}
}
impl <'a> VulkanBufferMapHandle<'a> {
pub unsafe fn copy_from(&mut self, src: &[u8]) {
std::ptr::copy_nonoverlapping(src.as_ptr(), self.ptr.cast(), src.len());
}
}
impl <'a> Drop for VulkanBufferMapHandle<'a> {
fn drop(&mut self) {
unsafe {
self.buffer.device.unmap_memory(self.buffer.memory)
}
}
}

View file

@ -5,7 +5,7 @@ use librashader_reflect::back::ShaderCompilerOutput;
use librashader_reflect::reflect::semantics::{TextureBinding, UboReflection};
use librashader_reflect::reflect::ShaderReflection;
use crate::{error, util};
use crate::framebuffer::VulkanRenderPass;
use crate::renderpass::VulkanRenderPass;
pub struct PipelineDescriptors {
pub replicas: u32,