vk: initial binding of previous pass outputs

This commit is contained in:
chyyran 2023-01-10 19:36:07 -05:00
parent 5154ff620a
commit 18a96d5e5e
8 changed files with 142 additions and 98 deletions

View file

@ -2,7 +2,7 @@ use crate::{error, util};
use crate::filter_pass::FilterPass; use crate::filter_pass::FilterPass;
use crate::luts::LutTexture; use crate::luts::LutTexture;
use crate::samplers::SamplerSet; use crate::samplers::SamplerSet;
use crate::texture::{OwnedTexture, Texture, VulkanImage}; use crate::texture::{OwnedTexture, InputTexture, VulkanImage};
use crate::ubo_ring::VkUboRing; use crate::ubo_ring::VkUboRing;
use crate::vulkan_state::VulkanGraphicsPipeline; use crate::vulkan_state::VulkanGraphicsPipeline;
use ash::vk::{CommandPoolCreateFlags, PFN_vkGetInstanceProcAddr, Queue, StaticFn}; use ash::vk::{CommandPoolCreateFlags, PFN_vkGetInstanceProcAddr, Queue, StaticFn};
@ -24,7 +24,7 @@ use std::error::Error;
use std::path::Path; use std::path::Path;
use crate::draw_quad::{DrawQuad, VBO_DEFAULT_FINAL, VBO_OFFSCREEN}; use crate::draw_quad::{DrawQuad, VBO_DEFAULT_FINAL, VBO_OFFSCREEN};
use crate::framebuffer::OutputFramebuffer; use crate::framebuffer::OutputFramebuffer;
use crate::rendertarget::{DEFAULT_MVP, RenderTarget}; use crate::render_target::{DEFAULT_MVP, RenderTarget};
pub struct Vulkan { pub struct Vulkan {
// physical_device: vk::PhysicalDevice, // physical_device: vk::PhysicalDevice,
@ -142,13 +142,67 @@ pub(crate) struct FilterCommon {
pub samplers: SamplerSet, pub samplers: SamplerSet,
pub(crate) draw_quad: DrawQuad, pub(crate) draw_quad: DrawQuad,
// pub output_textures: Box<[Option<Texture>]>, pub output_textures: Box<[Option<InputTexture>]>,
// pub feedback_textures: Box<[Option<Texture>]>, // pub feedback_textures: Box<[Option<Texture>]>,
// pub history_textures: Box<[Option<Texture>]>, // pub history_textures: Box<[Option<Texture>]>,
pub config: FilterMutable, pub config: FilterMutable,
pub device: ash::Device, pub device: ash::Device,
} }
#[must_use]
pub struct FilterChainFrameIntermediates {
device: ash::Device,
framebuffers: Vec<vk::Framebuffer>,
image_views: Vec<vk::ImageView>
}
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 = (); pub type FilterChainOptionsVulkan = ();
impl FilterChainVulkan { impl FilterChainVulkan {
@ -188,7 +242,8 @@ impl FilterChainVulkan {
}); });
let output_framebuffers: error::Result<Vec<OwnedTexture>> = output_framebuffers.into_iter().collect(); let output_framebuffers: error::Result<Vec<OwnedTexture>> = output_framebuffers.into_iter().collect();
let mut output_textures = Vec::new();
output_textures.resize_with(filters.len(), || None);
eprintln!("filters initialized ok."); eprintln!("filters initialized ok.");
Ok(FilterChainVulkan { Ok(FilterChainVulkan {
common: FilterCommon { common: FilterCommon {
@ -203,7 +258,8 @@ impl FilterChainVulkan {
.collect(), .collect(),
}, },
draw_quad: DrawQuad::new(&device.device, &device.memory_properties)?, 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, passes: filters,
vulkan: device, vulkan: device,
@ -401,28 +457,11 @@ impl FilterChainVulkan {
input: &VulkanImage, input: &VulkanImage,
cmd: vk::CommandBuffer, cmd: vk::CommandBuffer,
options: Option<()>, options: Option<()>,
) -> error::Result<()> { ) -> error::Result<FilterChainFrameIntermediates> {
// limit number of passes to those enabled. // limit number of passes to those enabled.
let passes = &mut self.passes[0..self.common.config.passes_enabled]; let passes = &mut self.passes[0..self.common.config.passes_enabled];
unsafe { let mut intermediates = FilterChainFrameIntermediates::new(&self.vulkan.device);
// 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 original_image_view = unsafe { let original_image_view = unsafe {
let create_info = vk::ImageViewCreateInfo::builder() let create_info = vk::ImageViewCreateInfo::builder()
@ -448,7 +487,7 @@ impl FilterChainVulkan {
let filter = passes[0].config.filter; let filter = passes[0].config.filter;
let wrap_mode = passes[0].config.wrap_mode; let wrap_mode = passes[0].config.wrap_mode;
let original = Texture { let original = InputTexture {
image: input.clone(), image: input.clone(),
image_view: original_image_view, image_view: original_image_view,
wrap_mode, wrap_mode,
@ -469,27 +508,30 @@ impl FilterChainVulkan {
)?; )?;
} }
//
for (index, pass) in passes.iter_mut().enumerate() { for (index, pass) in passes.iter_mut().enumerate() {
let target = &self.output_framebuffers[index]; let target = &self.output_framebuffers[index];
// todo: use proper mode // todo: use proper mode
// todo: the output framebuffers can only be dropped after command queue submission.
let out = RenderTarget { let out = RenderTarget {
mvp: DEFAULT_MVP, mvp: DEFAULT_MVP,
output: OutputFramebuffer::new(&self.vulkan, &pass.graphics_pipeline.render_pass, target.image.image, target.image.size)?, 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)?; 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);
} }
// unsafe { intermediates.dispose_outputs(out.output);
// 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)
} }
} }

View file

@ -1,8 +1,8 @@
use crate::{error, util}; use crate::{error, util};
use crate::filter_chain::FilterCommon; use crate::filter_chain::FilterCommon;
use crate::rendertarget::RenderTarget; use crate::render_target::RenderTarget;
use crate::samplers::{SamplerSet, VulkanSampler}; use crate::samplers::{SamplerSet, VulkanSampler};
use crate::texture::Texture; use crate::texture::InputTexture;
use crate::ubo_ring::VkUboRing; use crate::ubo_ring::VkUboRing;
use crate::vulkan_state::VulkanGraphicsPipeline; use crate::vulkan_state::VulkanGraphicsPipeline;
use ash::vk; use ash::vk;
@ -35,7 +35,7 @@ impl FilterPass {
samplers: &SamplerSet, samplers: &SamplerSet,
descriptor_set: vk::DescriptorSet, descriptor_set: vk::DescriptorSet,
binding: &TextureBinding, binding: &TextureBinding,
texture: &Texture, texture: &InputTexture,
) { ) {
let sampler = samplers.get(texture.wrap_mode, texture.filter_mode, texture.mip_filter); let sampler = samplers.get(texture.wrap_mode, texture.filter_mode, texture.mip_filter);
let image_info = [vk::DescriptorImageInfo::builder() let image_info = [vk::DescriptorImageInfo::builder()
@ -74,8 +74,8 @@ impl FilterPass {
frame_count: u32, frame_count: u32,
frame_direction: i32, frame_direction: i32,
viewport: &vk::Viewport, viewport: &vk::Viewport,
original: &Texture, original: &InputTexture,
source: &Texture, source: &InputTexture,
output: &RenderTarget, output: &RenderTarget,
) -> error::Result<()> { ) -> error::Result<()> {
let descriptor = *&self.graphics_pipeline.layout.descriptor_sets[0]; 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.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, &[ parent.device.cmd_set_scissor(cmd, 0, &[
vk::Rect2D { vk::Rect2D {
@ -141,17 +141,10 @@ impl FilterPass {
parent.device.cmd_set_viewport(cmd, 0, &[output.output.size.into()]); parent.device.cmd_set_viewport(cmd, 0, &[output.output.size.into()]);
parent.device.cmd_draw(cmd, 4, 1, 0, 0); parent.device.cmd_draw(cmd, 4, 1, 0, 0);
parent.device.cmd_end_render_pass(cmd); parent.device.cmd_end_render_pass(cmd);
output.output.end_pass(cmd);
} }
Ok(()) Ok(())
} }
//
// fn bind_ubo(device: &vk::Device, descriptor: &vk::DescriptorSet, binding: u32, buffer: &vk::Buffer, offset: vk::DeviceSize, range: vk::DeviceSize) {
//
// }
fn build_semantics( fn build_semantics(
&mut self, &mut self,
pass_index: usize, pass_index: usize,
@ -162,8 +155,8 @@ impl FilterPass {
fb_size: Size<u32>, fb_size: Size<u32>,
viewport_size: Size<u32>, viewport_size: Size<u32>,
descriptor_set: &vk::DescriptorSet, descriptor_set: &vk::DescriptorSet,
original: &Texture, original: &InputTexture,
source: &Texture, source: &InputTexture,
) { ) {
if let Some(offset) = self.uniform_bindings.get(&UniqueSemantics::MVP.into()) { if let Some(offset) = self.uniform_bindings.get(&UniqueSemantics::MVP.into()) {
self.uniform_storage.bind_mat4(*offset, mvp, None); self.uniform_storage.bind_mat4(*offset, mvp, None);
@ -304,35 +297,33 @@ impl FilterPass {
// } // }
// PassOutput // PassOutput
// for (index, output) in parent.output_textures[0..pass_index].iter().enumerate() { for (index, output) in parent.output_textures[0..pass_index].iter().enumerate() {
// let Some(output) = output else { let Some(output) = output else {
// eprintln!("no passoutput {index}"); continue;
// };
// continue; if let Some(binding) = self
// }; .reflection
// if let Some(binding) = self .meta
// .reflection .texture_meta
// .meta .get(&TextureSemantics::PassOutput.semantics(index))
// .texture_meta {
// .get(&TextureSemantics::PassOutput.semantics(index)) FilterPass::bind_texture(
// { &self.device,
// FilterPass::bind_texture( &parent.samplers,
// &self.device, *descriptor_set,
// &parent.samplers, binding,
// descriptor_set, output,
// binding, );
// output, }
// );
// } if let Some(offset) = self
// .uniform_bindings
// if let Some(offset) = self .get(&TextureSemantics::PassOutput.semantics(index).into())
// .uniform_bindings {
// .get(&TextureSemantics::PassOutput.semantics(index).into()) self.uniform_storage
// { .bind_vec4(*offset, output.image.size, None);
// self.uniform_storage }
// .bind_vec4(*offset, output.view.size, None); }
// }
// }
// // PassFeedback // // PassFeedback
// for (index, feedback) in parent.feedback_textures.iter().enumerate() { // for (index, feedback) in parent.feedback_textures.iter().enumerate() {

View file

@ -68,8 +68,8 @@ impl Drop for VulkanFramebuffer {
pub(crate) struct OutputFramebuffer { pub(crate) struct OutputFramebuffer {
pub framebuffer: vk::Framebuffer, pub framebuffer: vk::Framebuffer,
pub size: Size<u32>, pub size: Size<u32>,
pub image_view: vk::ImageView,
device: ash::Device, device: ash::Device,
image_view: vk::ImageView,
image: vk::Image, image: vk::Image,
} }
@ -180,12 +180,12 @@ impl OutputFramebuffer {
impl Drop for OutputFramebuffer { impl Drop for OutputFramebuffer {
fn drop(&mut self) { fn drop(&mut self) {
unsafe { unsafe {
if self.framebuffer != vk::Framebuffer::null() { // if self.framebuffer != vk::Framebuffer::null() {
self.device.destroy_framebuffer(self.framebuffer, None); // self.device.destroy_framebuffer(self.framebuffer, None);
} // }
if self.image_view != vk::ImageView::null() { // if self.image_view != vk::ImageView::null() {
self.device.destroy_image_view(self.image_view, None); // self.device.destroy_image_view(self.image_view, None);
} // }
} }
} }
} }

View file

@ -10,7 +10,7 @@ mod framebuffer;
mod hello_triangle; mod hello_triangle;
mod luts; mod luts;
mod renderpass; mod renderpass;
mod rendertarget; mod render_target;
mod samplers; mod samplers;
mod texture; mod texture;
mod ubo_ring; mod ubo_ring;

View file

@ -1,5 +1,5 @@
use crate::filter_chain::Vulkan; use crate::filter_chain::Vulkan;
use crate::texture::{Texture, VulkanImage}; use crate::texture::{InputTexture, VulkanImage};
use crate::vulkan_primitives::{VulkanBuffer, VulkanImageMemory}; use crate::vulkan_primitives::{VulkanBuffer, VulkanImageMemory};
use crate::{error, util}; use crate::{error, util};
use ash::vk; use ash::vk;
@ -10,7 +10,7 @@ use librashader_runtime::scaling::MipmapSize;
pub struct LutTexture { pub struct LutTexture {
pub memory: VulkanImageMemory, pub memory: VulkanImageMemory,
pub staging: VulkanBuffer, pub staging: VulkanBuffer,
pub image: Texture, pub image: InputTexture,
} }
impl LutTexture { impl LutTexture {
@ -233,7 +233,7 @@ impl LutTexture {
Ok(LutTexture { Ok(LutTexture {
memory, memory,
staging, staging,
image: Texture { image: InputTexture {
image_view: texture_view, image_view: texture_view,
image: VulkanImage { image: VulkanImage {
size: image.size, size: image.size,

View file

@ -2,7 +2,7 @@ use crate::framebuffer::OutputFramebuffer;
use ash::vk; use ash::vk;
#[rustfmt::skip] #[rustfmt::skip]
pub static DEFAULT_MVP: &[f32; 16] = &[ pub(crate) static DEFAULT_MVP: &[f32; 16] = &[
2f32, 0.0, 0.0, 0.0, 2f32, 0.0, 0.0, 0.0,
0.0, 2.0, 0.0, 0.0, 0.0, 2.0, 0.0, 0.0,
0.0, 0.0, 2.0, 0.0, 0.0, 0.0, 2.0, 0.0,

View file

@ -24,7 +24,7 @@ impl VulkanRenderPass {
.flags(vk::AttachmentDescriptionFlags::empty()) .flags(vk::AttachmentDescriptionFlags::empty())
.format(format.into()) .format(format.into())
.samples(SampleCountFlags::TYPE_1) .samples(SampleCountFlags::TYPE_1)
.load_op(AttachmentLoadOp::DONT_CARE) .load_op(AttachmentLoadOp::CLEAR)
.store_op(AttachmentStoreOp::STORE) .store_op(AttachmentStoreOp::STORE)
.stencil_load_op(AttachmentLoadOp::DONT_CARE) .stencil_load_op(AttachmentLoadOp::DONT_CARE)
.stencil_store_op(AttachmentStoreOp::DONT_CARE) .stencil_store_op(AttachmentStoreOp::DONT_CARE)

View file

@ -1,4 +1,4 @@
use crate::error; use crate::{error, util};
use crate::filter_chain::Vulkan; use crate::filter_chain::Vulkan;
use crate::util::find_vulkan_memory_type; use crate::util::find_vulkan_memory_type;
use crate::vulkan_primitives::VulkanImageMemory; use crate::vulkan_primitives::VulkanImageMemory;
@ -115,8 +115,8 @@ impl OwnedTexture {
scaling: Scale2D, scaling: Scale2D,
format: ImageFormat, format: ImageFormat,
viewport_size: &Size<u32>, viewport_size: &Size<u32>,
_original: &Texture, _original: &InputTexture,
source: &Texture, source: &InputTexture,
) -> error::Result<Size<u32>> { ) -> error::Result<Size<u32>> {
@ -135,7 +135,7 @@ impl OwnedTexture {
} }
pub fn create_texture_view(&self) -> error::Result<vk::ImageView> { pub fn create_image_view(&self) -> error::Result<vk::ImageView> {
let image_subresource = vk::ImageSubresourceRange::builder() let image_subresource = vk::ImageSubresourceRange::builder()
.base_mip_level(0) .base_mip_level(0)
.base_array_layer(0) .base_array_layer(0)
@ -162,6 +162,16 @@ impl OwnedTexture {
let image_view = unsafe { self.device.create_image_view(&view_info, None)? }; let image_view = unsafe { self.device.create_image_view(&view_info, None)? };
Ok(image_view) Ok(image_view)
} }
pub fn as_input(&self, filter: FilterMode, wrap_mode: WrapMode) -> error::Result<InputTexture> {
Ok(InputTexture {
image: self.image.clone(),
image_view: self.create_image_view()?,
wrap_mode,
filter_mode: filter,
mip_filter: filter,
})
}
} }
impl Drop for OwnedTexture { impl Drop for OwnedTexture {
@ -184,8 +194,9 @@ pub struct VulkanImage {
pub format: vk::Format, pub format: vk::Format,
} }
#[derive(Clone)] #[derive(Clone)]
pub struct Texture { pub struct InputTexture {
pub image: VulkanImage, pub image: VulkanImage,
pub image_view: vk::ImageView, pub image_view: vk::ImageView,
pub wrap_mode: WrapMode, pub wrap_mode: WrapMode,