vk: create raii buffer abstraction
This commit is contained in:
parent
53e3b5c2d1
commit
e428e02dfe
15
librashader-runtime-vk/src/draw_quad.rs
Normal file
15
librashader-runtime-vk/src/draw_quad.rs
Normal 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,
|
||||||
|
];
|
|
@ -1,8 +1,7 @@
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
use std::ffi::CStr;
|
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use ash::vk;
|
use ash::vk;
|
||||||
use ash::vk::{ColorComponentFlags, PFN_vkGetInstanceProcAddr, StaticFn};
|
use ash::vk::{PFN_vkGetInstanceProcAddr, StaticFn};
|
||||||
use rustc_hash::FxHashMap;
|
use rustc_hash::FxHashMap;
|
||||||
use librashader_common::ImageFormat;
|
use librashader_common::ImageFormat;
|
||||||
use librashader_preprocess::ShaderSource;
|
use librashader_preprocess::ShaderSource;
|
||||||
|
@ -15,8 +14,7 @@ use librashader_reflect::reflect::semantics::{Semantic, ShaderSemantics, Texture
|
||||||
use librashader_runtime::uniforms::UniformStorage;
|
use librashader_runtime::uniforms::UniformStorage;
|
||||||
use crate::error;
|
use crate::error;
|
||||||
use crate::filter_pass::FilterPass;
|
use crate::filter_pass::FilterPass;
|
||||||
use crate::framebuffer::{Framebuffer, VulkanRenderPass};
|
use crate::vulkan_state::VulkanGraphicsPipeline;
|
||||||
use crate::vulkan_state::{PipelineLayoutObjects, VulkanGraphicsPipeline};
|
|
||||||
|
|
||||||
pub struct Vulkan {
|
pub struct Vulkan {
|
||||||
physical_device: vk::PhysicalDevice,
|
physical_device: vk::PhysicalDevice,
|
||||||
|
@ -59,7 +57,7 @@ impl From<VulkanInfo<'_>> for ash::Device {
|
||||||
|
|
||||||
pub struct FilterChainVulkan {
|
pub struct FilterChainVulkan {
|
||||||
pub(crate) common: FilterCommon,
|
pub(crate) common: FilterCommon,
|
||||||
pub(crate) passes: Vec<FilterPass>,
|
pub(crate) passes: Box<[FilterPass]>,
|
||||||
// pub(crate) output_framebuffers: Box<[OwnedFramebuffer]>,
|
// pub(crate) output_framebuffers: Box<[OwnedFramebuffer]>,
|
||||||
// pub(crate) feedback_framebuffers: Box<[OwnedFramebuffer]>,
|
// pub(crate) feedback_framebuffers: Box<[OwnedFramebuffer]>,
|
||||||
// pub(crate) history_framebuffers: VecDeque<OwnedFramebuffer>,
|
// pub(crate) history_framebuffers: VecDeque<OwnedFramebuffer>,
|
||||||
|
@ -100,7 +98,10 @@ impl FilterChainVulkan {
|
||||||
// initialize passes
|
// initialize passes
|
||||||
let filters = Self::init_passes(&device, passes, &semantics, 3)?;
|
let filters = Self::init_passes(&device, passes, &semantics, 3)?;
|
||||||
eprintln!("filters initialized ok.");
|
eprintln!("filters initialized ok.");
|
||||||
todo!();
|
Ok(FilterChainVulkan {
|
||||||
|
common: FilterCommon {},
|
||||||
|
passes: filters
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_preset(
|
fn load_preset(
|
||||||
|
@ -207,9 +208,7 @@ impl FilterChainVulkan {
|
||||||
|
|
||||||
let graphics_pipeline = VulkanGraphicsPipeline::new(device,
|
let graphics_pipeline = VulkanGraphicsPipeline::new(device,
|
||||||
&pipeline_cache,
|
&pipeline_cache,
|
||||||
&spirv_words, &reflection, source.format, images)
|
&spirv_words, &reflection, source.format, images)?;
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
// shader_vulkan: 2026
|
// shader_vulkan: 2026
|
||||||
filters.push(FilterPass {
|
filters.push(FilterPass {
|
||||||
compiled: spirv_words,
|
compiled: spirv_words,
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
use ash::vk;
|
use ash::vk;
|
||||||
use ash::vk::{AttachmentLoadOp, AttachmentStoreOp, DeviceSize, Extent2D, Extent3D, ImageAspectFlags, ImageLayout, ImageTiling, ImageType, ImageUsageFlags, ImageViewType, PipelineBindPoint, SampleCountFlags, SharingMode};
|
use ash::vk::{Extent3D, ImageAspectFlags, ImageLayout, ImageTiling, ImageType, ImageUsageFlags, ImageViewType, SampleCountFlags, SharingMode};
|
||||||
use glfw::Key::P;
|
use librashader_common::Size;
|
||||||
use librashader_common::{ImageFormat, Size};
|
|
||||||
use crate::error;
|
use crate::error;
|
||||||
|
use crate::renderpass::VulkanRenderPass;
|
||||||
use crate::util::find_vulkan_memory_type;
|
use crate::util::find_vulkan_memory_type;
|
||||||
|
use crate::vulkan_primitives::VulkanImageMemory;
|
||||||
|
|
||||||
pub struct Framebuffer {
|
pub struct Framebuffer {
|
||||||
device: ash::Device,
|
device: ash::Device,
|
||||||
|
@ -20,37 +21,7 @@ pub struct VulkanFramebuffer {
|
||||||
pub image_view: vk::ImageView,
|
pub image_view: vk::ImageView,
|
||||||
pub fb_view: vk::ImageView,
|
pub fb_view: vk::ImageView,
|
||||||
pub image: vk::Image,
|
pub image: vk::Image,
|
||||||
pub memory: VulkanMemory,
|
pub memory: VulkanImageMemory,
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for VulkanFramebuffer {
|
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 {
|
impl Framebuffer {
|
||||||
pub fn new(device: &ash::Device, size: Size<u32>, render_pass: VulkanRenderPass, mip_levels: u32, mem_props: vk::PhysicalDeviceMemoryProperties) -> error::Result<Self> {
|
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 {
|
let mut framebuffer = Framebuffer {
|
||||||
|
@ -166,7 +87,7 @@ impl Framebuffer {
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
// todo: optimize by reusing existing memory.
|
// 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)?;
|
memory.bind(&image)?;
|
||||||
|
|
||||||
let image_subresource = vk::ImageSubresourceRange::builder()
|
let image_subresource = vk::ImageSubresourceRange::builder()
|
||||||
|
|
|
@ -8,6 +8,9 @@ mod error;
|
||||||
mod util;
|
mod util;
|
||||||
mod framebuffer;
|
mod framebuffer;
|
||||||
mod vulkan_state;
|
mod vulkan_state;
|
||||||
|
mod draw_quad;
|
||||||
|
mod renderpass;
|
||||||
|
mod vulkan_primitives;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
|
54
librashader-runtime-vk/src/renderpass.rs
Normal file
54
librashader-runtime-vk/src/renderpass.rs
Normal 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
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
124
librashader-runtime-vk/src/vulkan_primitives.rs
Normal file
124
librashader-runtime-vk/src/vulkan_primitives.rs
Normal 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,7 +5,7 @@ use librashader_reflect::back::ShaderCompilerOutput;
|
||||||
use librashader_reflect::reflect::semantics::{TextureBinding, UboReflection};
|
use librashader_reflect::reflect::semantics::{TextureBinding, UboReflection};
|
||||||
use librashader_reflect::reflect::ShaderReflection;
|
use librashader_reflect::reflect::ShaderReflection;
|
||||||
use crate::{error, util};
|
use crate::{error, util};
|
||||||
use crate::framebuffer::VulkanRenderPass;
|
use crate::renderpass::VulkanRenderPass;
|
||||||
|
|
||||||
pub struct PipelineDescriptors {
|
pub struct PipelineDescriptors {
|
||||||
pub replicas: u32,
|
pub replicas: u32,
|
||||||
|
|
Loading…
Reference in a new issue