diff --git a/librashader-runtime-vk/src/draw_quad.rs b/librashader-runtime-vk/src/draw_quad.rs new file mode 100644 index 0000000..5613481 --- /dev/null +++ b/librashader-runtime-vk/src/draw_quad.rs @@ -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, +]; diff --git a/librashader-runtime-vk/src/filter_chain.rs b/librashader-runtime-vk/src/filter_chain.rs index 6d8d6bf..e5a4ddc 100644 --- a/librashader-runtime-vk/src/filter_chain.rs +++ b/librashader-runtime-vk/src/filter_chain.rs @@ -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> for ash::Device { pub struct FilterChainVulkan { pub(crate) common: FilterCommon, - pub(crate) passes: Vec, + pub(crate) passes: Box<[FilterPass]>, // pub(crate) output_framebuffers: Box<[OwnedFramebuffer]>, // pub(crate) feedback_framebuffers: Box<[OwnedFramebuffer]>, // pub(crate) history_framebuffers: VecDeque, @@ -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, diff --git a/librashader-runtime-vk/src/framebuffer.rs b/librashader-runtime-vk/src/framebuffer.rs index 7eaa8af..1265973 100644 --- a/librashader-runtime-vk/src/framebuffer.rs +++ b/librashader-runtime-vk/src/framebuffer.rs @@ -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 { - 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 { - // 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, render_pass: VulkanRenderPass, mip_levels: u32, mem_props: vk::PhysicalDeviceMemoryProperties) -> error::Result { 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() diff --git a/librashader-runtime-vk/src/lib.rs b/librashader-runtime-vk/src/lib.rs index 5ea82a4..7f0c2bb 100644 --- a/librashader-runtime-vk/src/lib.rs +++ b/librashader-runtime-vk/src/lib.rs @@ -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 { diff --git a/librashader-runtime-vk/src/renderpass.rs b/librashader-runtime-vk/src/renderpass.rs new file mode 100644 index 0000000..b0c30b2 --- /dev/null +++ b/librashader-runtime-vk/src/renderpass.rs @@ -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 { + // 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 + }) + } + } +} diff --git a/librashader-runtime-vk/src/vulkan_primitives.rs b/librashader-runtime-vk/src/vulkan_primitives.rs new file mode 100644 index 0000000..e3d1ec4 --- /dev/null +++ b/librashader-runtime-vk/src/vulkan_primitives.rs @@ -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 { + 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 { + 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 { + 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) + } + } +} \ No newline at end of file diff --git a/librashader-runtime-vk/src/vulkan_state.rs b/librashader-runtime-vk/src/vulkan_state.rs index 1c8e487..b3b6a9d 100644 --- a/librashader-runtime-vk/src/vulkan_state.rs +++ b/librashader-runtime-vk/src/vulkan_state.rs @@ -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,