vk: implement feedback framebuffers

This commit is contained in:
chyyran 2023-01-11 23:05:08 -05:00
parent a34bdccc06
commit 857e994570
6 changed files with 102 additions and 123 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, InputTexture, VulkanImage}; use crate::texture::{OwnedImage, InputImage, 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};
@ -23,7 +23,7 @@ use rustc_hash::FxHashMap;
use std::error::Error; use std::error::Error;
use std::path::Path; use std::path::Path;
use crate::draw_quad::DrawQuad; use crate::draw_quad::DrawQuad;
use crate::framebuffer::OutputFramebuffer; use crate::framebuffer::OutputImage;
use crate::render_target::{DEFAULT_MVP, RenderTarget}; use crate::render_target::{DEFAULT_MVP, RenderTarget};
use crate::viewport::Viewport; use crate::viewport::Viewport;
@ -128,8 +128,8 @@ pub struct FilterChainVulkan {
pub(crate) common: FilterCommon, pub(crate) common: FilterCommon,
pub(crate) passes: Box<[FilterPass]>, pub(crate) passes: Box<[FilterPass]>,
pub(crate) vulkan: Vulkan, pub(crate) vulkan: Vulkan,
pub(crate) output_framebuffers: Box<[OwnedTexture]>, pub(crate) output_framebuffers: Box<[OwnedImage]>,
// pub(crate) feedback_framebuffers: Box<[OwnedFramebuffer]>, pub(crate) feedback_framebuffers: Box<[OwnedImage]>,
// pub(crate) history_framebuffers: VecDeque<OwnedFramebuffer>, // pub(crate) history_framebuffers: VecDeque<OwnedFramebuffer>,
} }
@ -143,8 +143,8 @@ 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<InputTexture>]>, pub output_textures: Box<[Option<InputImage>]>,
// pub feedback_textures: Box<[Option<Texture>]>, pub feedback_textures: Box<[Option<InputImage>]>,
// 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,
@ -153,7 +153,6 @@ pub(crate) struct FilterCommon {
#[must_use] #[must_use]
pub struct FilterChainFrameIntermediates { pub struct FilterChainFrameIntermediates {
device: ash::Device, device: ash::Device,
framebuffers: Vec<vk::Framebuffer>,
image_views: Vec<vk::ImageView> image_views: Vec<vk::ImageView>
} }
@ -161,24 +160,15 @@ impl FilterChainFrameIntermediates {
pub(crate) fn new(device: &ash::Device) -> Self { pub(crate) fn new(device: &ash::Device) -> Self {
FilterChainFrameIntermediates { FilterChainFrameIntermediates {
device: device.clone(), device: device.clone(),
framebuffers: Vec::new(),
image_views: Vec::new(), image_views: Vec::new(),
} }
} }
pub(crate) fn dispose_input(&mut self, input_texture_texture: InputTexture) { pub(crate) fn dispose_outputs(&mut self, output_framebuffer: OutputImage) {
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.framebuffers.push(output_framebuffer.framebuffer);
self.image_views.push(output_framebuffer.image_view); 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) { pub(crate) fn dispose_image_views(&mut self, image_view: vk::ImageView) {
self.image_views.push(image_view) self.image_views.push(image_view)
} }
@ -186,14 +176,6 @@ impl FilterChainFrameIntermediates {
impl Drop for FilterChainFrameIntermediates { impl Drop for FilterChainFrameIntermediates {
fn drop(&mut self) { 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 { for image_view in &self.image_views {
if *image_view != vk::ImageView::null() { if *image_view != vk::ImageView::null() {
unsafe { unsafe {
@ -234,7 +216,7 @@ impl FilterChainVulkan {
let mut output_framebuffers = Vec::new(); let mut output_framebuffers = Vec::new();
output_framebuffers.resize_with(filters.len(), || { output_framebuffers.resize_with(filters.len(), || {
OwnedTexture::new( OwnedImage::new(
&device, &device,
Size::new(1, 1), Size::new(1, 1),
ImageFormat::R8G8B8A8Unorm, ImageFormat::R8G8B8A8Unorm,
@ -242,9 +224,24 @@ impl FilterChainVulkan {
) )
}); });
let output_framebuffers: error::Result<Vec<OwnedTexture>> = output_framebuffers.into_iter().collect(); let mut feedback_framebuffers = Vec::new();
feedback_framebuffers.resize_with(filters.len(), || {
OwnedImage::new(
&device,
Size::new(1, 1),
ImageFormat::R8G8B8A8Unorm,
1
)
});
let output_framebuffers: error::Result<Vec<OwnedImage>> = output_framebuffers.into_iter().collect();
let mut output_textures = Vec::new(); let mut output_textures = Vec::new();
output_textures.resize_with(filters.len(), || None); output_textures.resize_with(filters.len(), || None);
let feedback_framebuffers: error::Result<Vec<OwnedImage>> = feedback_framebuffers.into_iter().collect();
let mut feedback_textures = Vec::new();
feedback_textures.resize_with(filters.len(), || None);
eprintln!("filters initialized ok."); eprintln!("filters initialized ok.");
Ok(FilterChainVulkan { Ok(FilterChainVulkan {
common: FilterCommon { common: FilterCommon {
@ -260,11 +257,13 @@ impl FilterChainVulkan {
}, },
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() output_textures: output_textures.into_boxed_slice(),
feedback_textures: feedback_textures.into_boxed_slice()
}, },
passes: filters, passes: filters,
vulkan: device, vulkan: device,
output_framebuffers: output_framebuffers?.into_boxed_slice(), output_framebuffers: output_framebuffers?.into_boxed_slice(),
feedback_framebuffers: feedback_framebuffers?.into_boxed_slice(),
}) })
} }
@ -491,7 +490,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 = InputTexture { let original = InputImage {
image: input.clone(), image: input.clone(),
image_view: original_image_view, image_view: original_image_view,
wrap_mode, wrap_mode,
@ -512,6 +511,16 @@ impl FilterChainVulkan {
// todo: need to check **next** // todo: need to check **next**
pass.config.mipmap_input pass.config.mipmap_input
)?; )?;
self.feedback_framebuffers[index].scale(
pass.config.scaling.clone(),
pass.get_format(),
&viewport.output.size,
&original,
&source,
// todo: need to check **next**
pass.config.mipmap_input
)?;
} }
@ -527,7 +536,7 @@ impl FilterChainVulkan {
x: 0.0, x: 0.0,
y: 0.0, y: 0.0,
mvp: DEFAULT_MVP, mvp: DEFAULT_MVP,
output: OutputFramebuffer::new(&self.vulkan, /*&pass.graphics_pipeline.render_pass,*/ output: OutputImage::new(&self.vulkan, /*&pass.graphics_pipeline.render_pass,*/
target.image.clone())?, target.image.clone())?,
}; };
@ -541,12 +550,8 @@ impl FilterChainVulkan {
} }
source = target.as_input(pass.config.filter, pass.config.wrap_mode)?; 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);
}
self.common.output_textures[index] = Some(source.clone());
intermediates.dispose_outputs(out.output); intermediates.dispose_outputs(out.output);
} }
@ -560,7 +565,7 @@ impl FilterChainVulkan {
x: viewport.x, x: viewport.x,
y: viewport.y, y: viewport.y,
mvp: viewport.mvp.unwrap_or(DEFAULT_MVP), mvp: viewport.mvp.unwrap_or(DEFAULT_MVP),
output: OutputFramebuffer::new(&self.vulkan, output: OutputImage::new(&self.vulkan,
viewport.output.clone())?, viewport.output.clone())?,
}; };
@ -569,6 +574,10 @@ impl FilterChainVulkan {
count as u32, count as u32,
0, viewport, &original, &source, &out)?; 0, viewport, &original, &source, &out)?;
std::mem::swap(
&mut self.output_framebuffers,
&mut self.feedback_framebuffers,
);
intermediates.dispose_outputs(out.output); intermediates.dispose_outputs(out.output);
} }
Ok(intermediates) Ok(intermediates)

View file

@ -2,7 +2,7 @@ use crate::{error, util};
use crate::filter_chain::FilterCommon; use crate::filter_chain::FilterCommon;
use crate::render_target::RenderTarget; use crate::render_target::RenderTarget;
use crate::samplers::{SamplerSet, VulkanSampler}; use crate::samplers::{SamplerSet, VulkanSampler};
use crate::texture::InputTexture; use crate::texture::InputImage;
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;
@ -36,7 +36,7 @@ impl FilterPass {
samplers: &SamplerSet, samplers: &SamplerSet,
descriptor_set: vk::DescriptorSet, descriptor_set: vk::DescriptorSet,
binding: &TextureBinding, binding: &TextureBinding,
texture: &InputTexture, texture: &InputImage,
) { ) {
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()
@ -76,8 +76,8 @@ impl FilterPass {
frame_count: u32, frame_count: u32,
frame_direction: i32, frame_direction: i32,
viewport: &Viewport, viewport: &Viewport,
original: &InputTexture, original: &InputImage,
source: &InputTexture, source: &InputImage,
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];
@ -124,7 +124,6 @@ impl FilterPass {
unsafe { unsafe {
parent.device.cmd_begin_rendering(cmd, &rendering_info); parent.device.cmd_begin_rendering(cmd, &rendering_info);
// parent.device.cmd_begin_render_pass(cmd, &render_pass_info, vk::SubpassContents::INLINE);
parent.device.cmd_bind_pipeline(cmd, vk::PipelineBindPoint::GRAPHICS, self.graphics_pipeline.pipeline); parent.device.cmd_bind_pipeline(cmd, vk::PipelineBindPoint::GRAPHICS, self.graphics_pipeline.pipeline);
// todo: allow frames in flight. // todo: allow frames in flight.
@ -171,8 +170,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: &InputTexture, original: &InputImage,
source: &InputTexture, source: &InputImage,
) { ) {
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);
@ -342,34 +341,34 @@ impl FilterPass {
} }
// // PassFeedback // // PassFeedback
// for (index, feedback) in parent.feedback_textures.iter().enumerate() { for (index, feedback) in parent.feedback_textures.iter().enumerate() {
// let Some(feedback) = feedback else { let Some(feedback) = feedback else {
// eprintln!("no passfeedback {index}"); eprintln!("no passfeedback {index}");
// continue; continue;
// }; };
// if let Some(binding) = self if let Some(binding) = self
// .reflection .reflection
// .meta .meta
// .texture_meta .texture_meta
// .get(&TextureSemantics::PassFeedback.semantics(index)) .get(&TextureSemantics::PassFeedback.semantics(index))
// { {
// FilterPass::bind_texture( FilterPass::bind_texture(
// &parent.samplers, &self.device,
// &mut textures, &parent.samplers,
// &mut samplers, *descriptor_set,
// binding, binding,
// feedback, feedback,
// ); );
// } }
//
// if let Some(offset) = self if let Some(offset) = self
// .uniform_bindings .uniform_bindings
// .get(&TextureSemantics::PassFeedback.semantics(index).into()) .get(&TextureSemantics::PassFeedback.semantics(index).into())
// { {
// self.uniform_storage self.uniform_storage
// .bind_vec4(*offset, feedback.view.size, None); .bind_vec4(*offset, feedback.image.size, None);
// } }
// } }
// bind float parameters // bind float parameters
for (id, offset) in for (id, offset) in

View file

@ -5,16 +5,16 @@ use ash::vk;
use librashader_common::Size; use librashader_common::Size;
#[derive(Clone)] #[derive(Clone)]
pub(crate) struct OutputFramebuffer { pub(crate) struct OutputImage {
pub size: Size<u32>, pub size: Size<u32>,
pub image_view: vk::ImageView, pub image_view: vk::ImageView,
device: ash::Device, device: ash::Device,
image: vk::Image, image: vk::Image,
} }
impl OutputFramebuffer { impl OutputImage {
pub fn new(vulkan: &Vulkan, pub fn new(vulkan: &Vulkan,
image: VulkanImage) -> error::Result<OutputFramebuffer> { image: VulkanImage) -> error::Result<OutputImage> {
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)
@ -41,7 +41,7 @@ impl OutputFramebuffer {
let image_view = unsafe { vulkan.device.create_image_view( let image_view = unsafe { vulkan.device.create_image_view(
&view_info, None)? }; &view_info, None)? };
Ok(OutputFramebuffer { Ok(OutputImage {
device: vulkan.device.clone(), device: vulkan.device.clone(),
size: image.size, size: image.size,
image: image.image, image: image.image,

View file

@ -1,5 +1,5 @@
use crate::filter_chain::Vulkan; use crate::filter_chain::Vulkan;
use crate::texture::{InputTexture, VulkanImage}; use crate::texture::{InputImage, 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: InputTexture, pub image: InputImage,
} }
impl LutTexture { impl LutTexture {
@ -233,7 +233,7 @@ impl LutTexture {
Ok(LutTexture { Ok(LutTexture {
memory, memory,
staging, staging,
image: InputTexture { image: InputImage {
image_view: texture_view, image_view: texture_view,
image: VulkanImage { image: VulkanImage {
size: image.size, size: image.size,

View file

@ -1,4 +1,4 @@
use crate::framebuffer::OutputFramebuffer; use crate::framebuffer::OutputImage;
use ash::vk; use ash::vk;
#[rustfmt::skip] #[rustfmt::skip]
@ -14,5 +14,5 @@ pub(crate) struct RenderTarget<'a> {
pub x: f32, pub x: f32,
pub y: f32, pub y: f32,
pub mvp: &'a [f32; 16], pub mvp: &'a [f32; 16],
pub output: OutputFramebuffer, pub output: OutputImage,
} }

View file

@ -8,7 +8,7 @@ use librashader_common::{FilterMode, ImageFormat, Size, WrapMode};
use librashader_presets::Scale2D; use librashader_presets::Scale2D;
use librashader_runtime::scaling::{MipmapSize, ViewportSize}; use librashader_runtime::scaling::{MipmapSize, ViewportSize};
pub struct OwnedTexture { pub struct OwnedImage {
pub device: ash::Device, pub device: ash::Device,
pub mem_props: vk::PhysicalDeviceMemoryProperties, pub mem_props: vk::PhysicalDeviceMemoryProperties,
pub image_view: vk::ImageView, pub image_view: vk::ImageView,
@ -18,14 +18,14 @@ pub struct OwnedTexture {
pub levels: u32, pub levels: u32,
} }
impl OwnedTexture { impl OwnedImage {
fn new_internal( fn new_internal(
device: ash::Device, device: ash::Device,
mem_props: vk::PhysicalDeviceMemoryProperties, mem_props: vk::PhysicalDeviceMemoryProperties,
size: Size<u32>, size: Size<u32>,
format: ImageFormat, format: ImageFormat,
max_miplevels: u32, max_miplevels: u32,
) -> error::Result<OwnedTexture> { ) -> error::Result<OwnedImage> {
let image_create_info = vk::ImageCreateInfo::builder() let image_create_info = vk::ImageCreateInfo::builder()
.image_type(vk::ImageType::TYPE_2D) .image_type(vk::ImageType::TYPE_2D)
.format(format.into()) .format(format.into())
@ -86,7 +86,7 @@ impl OwnedTexture {
let image_view = unsafe { device.create_image_view(&view_info, None)? }; let image_view = unsafe { device.create_image_view(&view_info, None)? };
Ok(OwnedTexture { Ok(OwnedImage {
device, device,
mem_props, mem_props,
image_view, image_view,
@ -106,7 +106,7 @@ impl OwnedTexture {
size: Size<u32>, size: Size<u32>,
format: ImageFormat, format: ImageFormat,
max_miplevels: u32, max_miplevels: u32,
) -> error::Result<OwnedTexture> { ) -> error::Result<OwnedImage> {
Self::new_internal(vulkan.device.clone(), vulkan.memory_properties, size, format, max_miplevels) Self::new_internal(vulkan.device.clone(), vulkan.memory_properties, size, format, max_miplevels)
} }
@ -115,8 +115,8 @@ impl OwnedTexture {
scaling: Scale2D, scaling: Scale2D,
format: ImageFormat, format: ImageFormat,
viewport_size: &Size<u32>, viewport_size: &Size<u32>,
_original: &InputTexture, _original: &InputImage,
source: &InputTexture, source: &InputImage,
mipmap: bool, mipmap: bool,
) -> error::Result<Size<u32>> { ) -> error::Result<Size<u32>> {
let size = source.image.size.scale_viewport(scaling, *viewport_size); let size = source.image.size.scale_viewport(scaling, *viewport_size);
@ -127,7 +127,7 @@ impl OwnedTexture {
1 1
}; };
let mut new = OwnedTexture::new_internal(self.device.clone(), self.mem_props, size, if format == ImageFormat::Unknown { let mut new = OwnedImage::new_internal(self.device.clone(), self.mem_props, size, if format == ImageFormat::Unknown {
ImageFormat::R8G8B8A8Unorm ImageFormat::R8G8B8A8Unorm
} else { } else {
format format
@ -139,39 +139,10 @@ impl OwnedTexture {
Ok(size) Ok(size)
} }
pub fn as_input(&self, filter: FilterMode, wrap_mode: WrapMode) -> error::Result<InputImage> {
pub fn create_image_view(&self) -> error::Result<vk::ImageView> { Ok(InputImage {
let image_subresource = vk::ImageSubresourceRange::builder()
.base_mip_level(0)
.base_array_layer(0)
.level_count(1)
.layer_count(1)
.aspect_mask(vk::ImageAspectFlags::COLOR)
.build();
let swizzle_components = vk::ComponentMapping::builder()
.r(vk::ComponentSwizzle::R)
.g(vk::ComponentSwizzle::G)
.b(vk::ComponentSwizzle::B)
.a(vk::ComponentSwizzle::A)
.build();
let mut view_info = vk::ImageViewCreateInfo::builder()
.view_type(vk::ImageViewType::TYPE_2D)
.format(self.image.format)
.image(self.image.image.clone())
.subresource_range(image_subresource)
.components(swizzle_components)
.build();
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<InputTexture> {
Ok(InputTexture {
image: self.image.clone(), image: self.image.clone(),
image_view: self.create_image_view()?, image_view: self.image_view.clone(),
wrap_mode, wrap_mode,
filter_mode: filter, filter_mode: filter,
mip_filter: filter, mip_filter: filter,
@ -459,7 +430,7 @@ impl OwnedTexture {
} }
} }
impl Drop for OwnedTexture { impl Drop for OwnedImage {
fn drop(&mut self) { fn drop(&mut self) {
unsafe { unsafe {
if self.image_view != vk::ImageView::null() { if self.image_view != vk::ImageView::null() {
@ -481,7 +452,7 @@ pub struct VulkanImage {
#[derive(Clone)] #[derive(Clone)]
pub struct InputTexture { pub struct InputImage {
pub image: VulkanImage, pub image: VulkanImage,
pub image_view: vk::ImageView, pub image_view: vk::ImageView,
pub wrap_mode: WrapMode, pub wrap_mode: WrapMode,