diff --git a/librashader-runtime-vk/src/filter_chain.rs b/librashader-runtime-vk/src/filter_chain.rs index 8191ed3..62f1262 100644 --- a/librashader-runtime-vk/src/filter_chain.rs +++ b/librashader-runtime-vk/src/filter_chain.rs @@ -2,7 +2,7 @@ use crate::{error, util}; use crate::filter_pass::FilterPass; use crate::luts::LutTexture; use crate::samplers::SamplerSet; -use crate::texture::{OwnedTexture, Texture, VulkanImage}; +use crate::texture::{OwnedTexture, InputTexture, VulkanImage}; use crate::ubo_ring::VkUboRing; use crate::vulkan_state::VulkanGraphicsPipeline; use ash::vk::{CommandPoolCreateFlags, PFN_vkGetInstanceProcAddr, Queue, StaticFn}; @@ -24,7 +24,7 @@ use std::error::Error; use std::path::Path; use crate::draw_quad::{DrawQuad, VBO_DEFAULT_FINAL, VBO_OFFSCREEN}; use crate::framebuffer::OutputFramebuffer; -use crate::rendertarget::{DEFAULT_MVP, RenderTarget}; +use crate::render_target::{DEFAULT_MVP, RenderTarget}; pub struct Vulkan { // physical_device: vk::PhysicalDevice, @@ -142,13 +142,67 @@ pub(crate) struct FilterCommon { pub samplers: SamplerSet, pub(crate) draw_quad: DrawQuad, - // pub output_textures: Box<[Option]>, + pub output_textures: Box<[Option]>, // pub feedback_textures: Box<[Option]>, // pub history_textures: Box<[Option]>, pub config: FilterMutable, pub device: ash::Device, } +#[must_use] +pub struct FilterChainFrameIntermediates { + device: ash::Device, + framebuffers: Vec, + image_views: Vec +} + +impl FilterChainFrameIntermediates { + pub(crate) fn new(device: &ash::Device) -> Self { + FilterChainFrameIntermediates { + device: device.clone(), + framebuffers: Vec::new(), + image_views: Vec::new(), + } + } + + pub(crate) fn dispose_input(&mut self, input_texture_texture: InputTexture) { + self.image_views.push(input_texture_texture.image_view); + } + + pub(crate) fn dispose_outputs(&mut self, output_framebuffer: OutputFramebuffer) { + self.framebuffers.push(output_framebuffer.framebuffer); + self.image_views.push(output_framebuffer.image_view); + } + + pub(crate) fn dispose_framebuffer(&mut self, framebuffer: vk::Framebuffer) { + self.framebuffers.push(framebuffer) + } + + pub(crate) fn dispose_image_views(&mut self, image_view: vk::ImageView) { + self.image_views.push(image_view) + } +} + +impl Drop for FilterChainFrameIntermediates { + fn drop(&mut self) { + for framebuffer in &self.framebuffers { + if *framebuffer != vk::Framebuffer::null() { + unsafe { + self.device.destroy_framebuffer(*framebuffer, None); + } + } + } + + for image_view in &self.image_views { + if *image_view != vk::ImageView::null() { + unsafe { + self.device.destroy_image_view(*image_view, None); + } + } + } + } +} + pub type FilterChainOptionsVulkan = (); impl FilterChainVulkan { @@ -188,7 +242,8 @@ impl FilterChainVulkan { }); let output_framebuffers: error::Result> = output_framebuffers.into_iter().collect(); - + let mut output_textures = Vec::new(); + output_textures.resize_with(filters.len(), || None); eprintln!("filters initialized ok."); Ok(FilterChainVulkan { common: FilterCommon { @@ -203,7 +258,8 @@ impl FilterChainVulkan { .collect(), }, draw_quad: DrawQuad::new(&device.device, &device.memory_properties)?, - device: device.device.clone() + device: device.device.clone(), + output_textures: output_textures.into_boxed_slice() }, passes: filters, vulkan: device, @@ -401,28 +457,11 @@ impl FilterChainVulkan { input: &VulkanImage, cmd: vk::CommandBuffer, options: Option<()>, - ) -> error::Result<()> { + ) -> error::Result { // limit number of passes to those enabled. let passes = &mut self.passes[0..self.common.config.passes_enabled]; - unsafe { - // todo: see if we can find a less conservative transition, - // but this ensures that the image is rendered at least - util::vulkan_image_layout_transition_levels( - &self.vulkan.device, - cmd, - input.image, - 1, - vk::ImageLayout::UNDEFINED, - vk::ImageLayout::GENERAL, - vk::AccessFlags::empty(), - vk::AccessFlags::SHADER_READ | vk::AccessFlags::COLOR_ATTACHMENT_READ, - vk::PipelineStageFlags::BOTTOM_OF_PIPE, - vk::PipelineStageFlags::FRAGMENT_SHADER, - vk::QUEUE_FAMILY_IGNORED, - vk::QUEUE_FAMILY_IGNORED - ); - } + let mut intermediates = FilterChainFrameIntermediates::new(&self.vulkan.device); let original_image_view = unsafe { let create_info = vk::ImageViewCreateInfo::builder() @@ -448,7 +487,7 @@ impl FilterChainVulkan { let filter = passes[0].config.filter; let wrap_mode = passes[0].config.wrap_mode; - let original = Texture { + let original = InputTexture { image: input.clone(), image_view: original_image_view, wrap_mode, @@ -469,27 +508,30 @@ impl FilterChainVulkan { )?; } - // + for (index, pass) in passes.iter_mut().enumerate() { let target = &self.output_framebuffers[index]; // todo: use proper mode + // todo: the output framebuffers can only be dropped after command queue submission. + let out = RenderTarget { mvp: DEFAULT_MVP, output: OutputFramebuffer::new(&self.vulkan, &pass.graphics_pipeline.render_pass, target.image.image, target.image.size)?, }; pass.draw(cmd, index, &self.common, count as u32, 0, viewport, &original, &source, &out)?; + // for second to last pass, we want to transition to copy instead. + out.output.end_pass(cmd); + + source = target.as_input(pass.config.filter, pass.config.wrap_mode)?; + let prev_frame_output = self.common.output_textures[index].replace(source.clone()); + if let Some(prev_frame_output) = prev_frame_output { + intermediates.dispose_input(prev_frame_output); + } + + intermediates.dispose_outputs(out.output); } - // unsafe { - // self.vulkan.device.queue_submit(self.vulkan.queue, &[vk::SubmitInfo::builder() - // .wait_semaphores(&[wait]) - // .wait_dst_stage_mask(&[vk::PipelineStageFlags::ALL_COMMANDS],) - // .signal_semaphores(&[signal]) - // .command_buffers(&[]) - // .build()], vk::Fence::null())? - // } - - Ok(()) + Ok(intermediates) } } diff --git a/librashader-runtime-vk/src/filter_pass.rs b/librashader-runtime-vk/src/filter_pass.rs index a416c47..a721981 100644 --- a/librashader-runtime-vk/src/filter_pass.rs +++ b/librashader-runtime-vk/src/filter_pass.rs @@ -1,8 +1,8 @@ use crate::{error, util}; use crate::filter_chain::FilterCommon; -use crate::rendertarget::RenderTarget; +use crate::render_target::RenderTarget; use crate::samplers::{SamplerSet, VulkanSampler}; -use crate::texture::Texture; +use crate::texture::InputTexture; use crate::ubo_ring::VkUboRing; use crate::vulkan_state::VulkanGraphicsPipeline; use ash::vk; @@ -35,7 +35,7 @@ impl FilterPass { samplers: &SamplerSet, descriptor_set: vk::DescriptorSet, binding: &TextureBinding, - texture: &Texture, + texture: &InputTexture, ) { let sampler = samplers.get(texture.wrap_mode, texture.filter_mode, texture.mip_filter); let image_info = [vk::DescriptorImageInfo::builder() @@ -74,8 +74,8 @@ impl FilterPass { frame_count: u32, frame_direction: i32, viewport: &vk::Viewport, - original: &Texture, - source: &Texture, + original: &InputTexture, + source: &InputTexture, output: &RenderTarget, ) -> error::Result<()> { let descriptor = *&self.graphics_pipeline.layout.descriptor_sets[0]; @@ -130,7 +130,7 @@ impl FilterPass { parent.device.cmd_push_constants(cmd, self.graphics_pipeline.layout.layout, stage_mask, 0, self.uniform_storage.push_slice()); } - parent.draw_quad.bind_vbo(cmd, VboType::Offscreen); + parent.draw_quad.bind_vbo(cmd, VboType::Final); parent.device.cmd_set_scissor(cmd, 0, &[ vk::Rect2D { @@ -141,17 +141,10 @@ impl FilterPass { parent.device.cmd_set_viewport(cmd, 0, &[output.output.size.into()]); parent.device.cmd_draw(cmd, 4, 1, 0, 0); parent.device.cmd_end_render_pass(cmd); - - output.output.end_pass(cmd); } Ok(()) } - // - // fn bind_ubo(device: &vk::Device, descriptor: &vk::DescriptorSet, binding: u32, buffer: &vk::Buffer, offset: vk::DeviceSize, range: vk::DeviceSize) { - // - // } - fn build_semantics( &mut self, pass_index: usize, @@ -162,8 +155,8 @@ impl FilterPass { fb_size: Size, viewport_size: Size, descriptor_set: &vk::DescriptorSet, - original: &Texture, - source: &Texture, + original: &InputTexture, + source: &InputTexture, ) { if let Some(offset) = self.uniform_bindings.get(&UniqueSemantics::MVP.into()) { self.uniform_storage.bind_mat4(*offset, mvp, None); @@ -304,35 +297,33 @@ impl FilterPass { // } // PassOutput - // for (index, output) in parent.output_textures[0..pass_index].iter().enumerate() { - // let Some(output) = output else { - // eprintln!("no passoutput {index}"); - // - // continue; - // }; - // if let Some(binding) = self - // .reflection - // .meta - // .texture_meta - // .get(&TextureSemantics::PassOutput.semantics(index)) - // { - // FilterPass::bind_texture( - // &self.device, - // &parent.samplers, - // descriptor_set, - // binding, - // output, - // ); - // } - // - // if let Some(offset) = self - // .uniform_bindings - // .get(&TextureSemantics::PassOutput.semantics(index).into()) - // { - // self.uniform_storage - // .bind_vec4(*offset, output.view.size, None); - // } - // } + for (index, output) in parent.output_textures[0..pass_index].iter().enumerate() { + let Some(output) = output else { + continue; + }; + if let Some(binding) = self + .reflection + .meta + .texture_meta + .get(&TextureSemantics::PassOutput.semantics(index)) + { + FilterPass::bind_texture( + &self.device, + &parent.samplers, + *descriptor_set, + binding, + output, + ); + } + + if let Some(offset) = self + .uniform_bindings + .get(&TextureSemantics::PassOutput.semantics(index).into()) + { + self.uniform_storage + .bind_vec4(*offset, output.image.size, None); + } + } // // PassFeedback // for (index, feedback) in parent.feedback_textures.iter().enumerate() { diff --git a/librashader-runtime-vk/src/framebuffer.rs b/librashader-runtime-vk/src/framebuffer.rs index 2917ee3..636f985 100644 --- a/librashader-runtime-vk/src/framebuffer.rs +++ b/librashader-runtime-vk/src/framebuffer.rs @@ -68,8 +68,8 @@ impl Drop for VulkanFramebuffer { pub(crate) struct OutputFramebuffer { pub framebuffer: vk::Framebuffer, pub size: Size, + pub image_view: vk::ImageView, device: ash::Device, - image_view: vk::ImageView, image: vk::Image, } @@ -180,12 +180,12 @@ impl OutputFramebuffer { impl Drop for OutputFramebuffer { fn drop(&mut self) { unsafe { - if self.framebuffer != vk::Framebuffer::null() { - self.device.destroy_framebuffer(self.framebuffer, None); - } - if self.image_view != vk::ImageView::null() { - self.device.destroy_image_view(self.image_view, None); - } + // if self.framebuffer != vk::Framebuffer::null() { + // self.device.destroy_framebuffer(self.framebuffer, None); + // } + // if self.image_view != vk::ImageView::null() { + // self.device.destroy_image_view(self.image_view, None); + // } } } } \ No newline at end of file diff --git a/librashader-runtime-vk/src/lib.rs b/librashader-runtime-vk/src/lib.rs index afa988c..4080f3b 100644 --- a/librashader-runtime-vk/src/lib.rs +++ b/librashader-runtime-vk/src/lib.rs @@ -10,7 +10,7 @@ mod framebuffer; mod hello_triangle; mod luts; mod renderpass; -mod rendertarget; +mod render_target; mod samplers; mod texture; mod ubo_ring; diff --git a/librashader-runtime-vk/src/luts.rs b/librashader-runtime-vk/src/luts.rs index 729b75d..07b93c4 100644 --- a/librashader-runtime-vk/src/luts.rs +++ b/librashader-runtime-vk/src/luts.rs @@ -1,5 +1,5 @@ use crate::filter_chain::Vulkan; -use crate::texture::{Texture, VulkanImage}; +use crate::texture::{InputTexture, VulkanImage}; use crate::vulkan_primitives::{VulkanBuffer, VulkanImageMemory}; use crate::{error, util}; use ash::vk; @@ -10,7 +10,7 @@ use librashader_runtime::scaling::MipmapSize; pub struct LutTexture { pub memory: VulkanImageMemory, pub staging: VulkanBuffer, - pub image: Texture, + pub image: InputTexture, } impl LutTexture { @@ -233,7 +233,7 @@ impl LutTexture { Ok(LutTexture { memory, staging, - image: Texture { + image: InputTexture { image_view: texture_view, image: VulkanImage { size: image.size, diff --git a/librashader-runtime-vk/src/rendertarget.rs b/librashader-runtime-vk/src/render_target.rs similarity index 86% rename from librashader-runtime-vk/src/rendertarget.rs rename to librashader-runtime-vk/src/render_target.rs index 6e19809..81a5704 100644 --- a/librashader-runtime-vk/src/rendertarget.rs +++ b/librashader-runtime-vk/src/render_target.rs @@ -2,7 +2,7 @@ use crate::framebuffer::OutputFramebuffer; use ash::vk; #[rustfmt::skip] -pub static DEFAULT_MVP: &[f32; 16] = &[ +pub(crate) static DEFAULT_MVP: &[f32; 16] = &[ 2f32, 0.0, 0.0, 0.0, 0.0, 2.0, 0.0, 0.0, 0.0, 0.0, 2.0, 0.0, diff --git a/librashader-runtime-vk/src/renderpass.rs b/librashader-runtime-vk/src/renderpass.rs index 93d0952..ade1dbb 100644 --- a/librashader-runtime-vk/src/renderpass.rs +++ b/librashader-runtime-vk/src/renderpass.rs @@ -24,7 +24,7 @@ impl VulkanRenderPass { .flags(vk::AttachmentDescriptionFlags::empty()) .format(format.into()) .samples(SampleCountFlags::TYPE_1) - .load_op(AttachmentLoadOp::DONT_CARE) + .load_op(AttachmentLoadOp::CLEAR) .store_op(AttachmentStoreOp::STORE) .stencil_load_op(AttachmentLoadOp::DONT_CARE) .stencil_store_op(AttachmentStoreOp::DONT_CARE) diff --git a/librashader-runtime-vk/src/texture.rs b/librashader-runtime-vk/src/texture.rs index a316e80..4020338 100644 --- a/librashader-runtime-vk/src/texture.rs +++ b/librashader-runtime-vk/src/texture.rs @@ -1,4 +1,4 @@ -use crate::error; +use crate::{error, util}; use crate::filter_chain::Vulkan; use crate::util::find_vulkan_memory_type; use crate::vulkan_primitives::VulkanImageMemory; @@ -115,8 +115,8 @@ impl OwnedTexture { scaling: Scale2D, format: ImageFormat, viewport_size: &Size, - _original: &Texture, - source: &Texture, + _original: &InputTexture, + source: &InputTexture, ) -> error::Result> { @@ -135,7 +135,7 @@ impl OwnedTexture { } - pub fn create_texture_view(&self) -> error::Result { + pub fn create_image_view(&self) -> error::Result { let image_subresource = vk::ImageSubresourceRange::builder() .base_mip_level(0) .base_array_layer(0) @@ -162,6 +162,16 @@ impl OwnedTexture { let image_view = unsafe { self.device.create_image_view(&view_info, None)? }; Ok(image_view) } + + pub fn as_input(&self, filter: FilterMode, wrap_mode: WrapMode) -> error::Result { + Ok(InputTexture { + image: self.image.clone(), + image_view: self.create_image_view()?, + wrap_mode, + filter_mode: filter, + mip_filter: filter, + }) + } } impl Drop for OwnedTexture { @@ -184,8 +194,9 @@ pub struct VulkanImage { pub format: vk::Format, } + #[derive(Clone)] -pub struct Texture { +pub struct InputTexture { pub image: VulkanImage, pub image_view: vk::ImageView, pub wrap_mode: WrapMode,