vk: get closer to having shaders render

This commit is contained in:
chyyran 2023-01-10 00:11:05 -05:00
parent 48321d997b
commit 4595a5ccc3
7 changed files with 293 additions and 129 deletions

View file

@ -3,7 +3,7 @@ use crate::vulkan_primitives::VulkanBuffer;
use ash::vk; use ash::vk;
#[rustfmt::skip] #[rustfmt::skip]
static VBO_OFFSCREEN: &[f32; 16] = &[ pub(crate) static VBO_OFFSCREEN: &[f32; 16] = &[
// Offscreen // Offscreen
-1.0, -1.0, 0.0, 0.0, -1.0, -1.0, 0.0, 0.0,
-1.0, 1.0, 0.0, 1.0, -1.0, 1.0, 0.0, 1.0,
@ -12,7 +12,7 @@ static VBO_OFFSCREEN: &[f32; 16] = &[
]; ];
#[rustfmt::skip] #[rustfmt::skip]
static VBO_DEFAULT_FINAL: &[f32; 16] = &[ pub(crate) static VBO_DEFAULT_FINAL: &[f32; 16] = &[
// Final // Final
0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0,

View file

@ -1,13 +1,13 @@
use crate::error; 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::VulkanImage; use crate::texture::{OwnedTexture, Texture, 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};
use ash::{vk, Device}; use ash::{vk, Device};
use librashader_common::ImageFormat; use librashader_common::{ImageFormat, Size};
use librashader_preprocess::ShaderSource; use librashader_preprocess::ShaderSource;
use librashader_presets::{ShaderPassConfig, ShaderPreset, TextureConfig}; use librashader_presets::{ShaderPassConfig, ShaderPreset, TextureConfig};
use librashader_reflect::back::targets::SpirV; use librashader_reflect::back::targets::SpirV;
@ -22,6 +22,9 @@ use librashader_runtime::uniforms::UniformStorage;
use rustc_hash::FxHashMap; use rustc_hash::FxHashMap;
use std::error::Error; use std::error::Error;
use std::path::Path; use std::path::Path;
use crate::draw_quad::{VBO_DEFAULT_FINAL, VBO_OFFSCREEN};
use crate::framebuffer::OutputFramebuffer;
use crate::rendertarget::RenderTarget;
pub struct Vulkan { pub struct Vulkan {
// physical_device: vk::PhysicalDevice, // physical_device: vk::PhysicalDevice,
@ -124,7 +127,7 @@ 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<[OwnedFramebuffer]>, pub(crate) output_framebuffers: Box<[OwnedTexture]>,
// pub(crate) feedback_framebuffers: Box<[OwnedFramebuffer]>, // pub(crate) feedback_framebuffers: Box<[OwnedFramebuffer]>,
// pub(crate) history_framebuffers: VecDeque<OwnedFramebuffer>, // pub(crate) history_framebuffers: VecDeque<OwnedFramebuffer>,
// pub(crate) draw_quad: DrawQuad, // pub(crate) draw_quad: DrawQuad,
@ -172,6 +175,18 @@ impl FilterChainVulkan {
let luts = FilterChainVulkan::load_luts(&device, &preset.textures)?; let luts = FilterChainVulkan::load_luts(&device, &preset.textures)?;
let samplers = SamplerSet::new(&device.device)?; let samplers = SamplerSet::new(&device.device)?;
let mut output_framebuffers = Vec::new();
output_framebuffers.resize_with(filters.len(), || {
OwnedTexture::new(
&device,
Size::new(1, 1),
ImageFormat::R8G8B8A8Unorm,
1
)
});
let output_framebuffers: error::Result<Vec<OwnedTexture>> = output_framebuffers.into_iter().collect();
eprintln!("filters initialized ok."); eprintln!("filters initialized ok.");
Ok(FilterChainVulkan { Ok(FilterChainVulkan {
common: FilterCommon { common: FilterCommon {
@ -188,6 +203,7 @@ impl FilterChainVulkan {
}, },
passes: filters, passes: filters,
vulkan: device, vulkan: device,
output_framebuffers: output_framebuffers?.into_boxed_slice(),
}) })
} }
@ -379,16 +395,87 @@ impl FilterChainVulkan {
count: usize, count: usize,
viewport: &vk::Viewport, viewport: &vk::Viewport,
input: &VulkanImage, input: &VulkanImage,
cmd: vk::CommandBuffer,
options: Option<()>, options: Option<()>,
command_buffer: vk::CommandBuffer,
) -> error::Result<()> { ) -> error::Result<()> {
// 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 {
// 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 create_info = vk::ImageViewCreateInfo::builder()
.image(input.image)
.format(input.format)
.view_type(vk::ImageViewType::TYPE_2D)
.subresource_range(vk::ImageSubresourceRange::builder()
.aspect_mask(vk::ImageAspectFlags::COLOR)
.level_count(1)
.layer_count(1)
.build())
.components(vk::ComponentMapping::builder()
.r(vk::ComponentSwizzle::R)
.g(vk::ComponentSwizzle::G)
.b(vk::ComponentSwizzle::B)
.a(vk::ComponentSwizzle::A)
.build())
.build();
self.vulkan.device.create_image_view(&create_info, None)?
};
let filter = passes[0].config.filter;
let wrap_mode = passes[0].config.wrap_mode;
let original = Texture {
image: input.clone(),
image_view: original_image_view,
wrap_mode,
filter_mode: filter,
mip_filter: filter,
};
let mut source = original.clone();
// rescale render buffers to ensure all bindings are valid.
for (index, pass) in passes.iter_mut().enumerate() {
self.output_framebuffers[index].scale(
pass.config.scaling.clone(),
pass.get_format(),
&viewport.into(),
&original,
&source,
)?;
}
// //
// for (index, pass) in passes.iter_mut().enumerate() { for (index, pass) in passes.iter_mut().enumerate() {
// pass.draw(index, &self.common, count as u32, 0, viewport, &Default::default(), &Texture {}, &Texture {}) let target = &self.output_framebuffers[index];
// } // todo: use proper mode
let out = RenderTarget {
mvp: VBO_DEFAULT_FINAL,
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)?;
}
// unsafe { // unsafe {
// self.vulkan.device.queue_submit(self.vulkan.queue, &[vk::SubmitInfo::builder() // self.vulkan.device.queue_submit(self.vulkan.queue, &[vk::SubmitInfo::builder()

View file

@ -6,7 +6,7 @@ use crate::texture::Texture;
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;
use librashader_common::Size; use librashader_common::{ImageFormat, Size};
use librashader_preprocess::ShaderSource; use librashader_preprocess::ShaderSource;
use librashader_presets::ShaderPassConfig; use librashader_presets::ShaderPassConfig;
use librashader_reflect::back::ShaderCompilerOutput; use librashader_reflect::back::ShaderCompilerOutput;
@ -57,6 +57,16 @@ impl FilterPass {
} }
} }
pub fn get_format(&self) -> ImageFormat {
let mut fb_format = ImageFormat::R8G8B8A8Unorm;
if self.config.srgb_framebuffer {
fb_format = ImageFormat::R8G8B8A8Srgb;
} else if self.config.float_framebuffer {
fb_format = ImageFormat::R16G16B16A16Sfloat;
}
fb_format
}
pub(crate) fn draw( pub(crate) fn draw(
&mut self, &mut self,
cmd: vk::CommandBuffer, cmd: vk::CommandBuffer,

View file

@ -20,55 +20,56 @@ impl Drop for VulkanFramebuffer {
} }
} }
} }
//
// pub struct OwnedFramebuffer {
// pub size: Size<u32>,
// pub image: OwnedTexture,
// pub render_pass: VulkanRenderPass,
// pub framebuffer: VulkanFramebuffer,
// pub view: vk::ImageView,
// }
//
// impl OwnedFramebuffer {
// pub fn new(
// vulkan: &Vulkan,
// size: Size<u32>,
// render_pass: VulkanRenderPass,
// max_miplevels: u32,
// ) -> error::Result<Self> {
// let image = OwnedTexture::new(vulkan, size, render_pass.format, max_miplevels)?;
// let fb_view = image.create_texture_view()?;
// let framebuffer = unsafe {
// vulkan.device.create_framebuffer(
// &vk::FramebufferCreateInfo::builder()
// .render_pass(render_pass.handle)
// .attachments(&[image.image_view])
// .width(image.image.size.width)
// .height(image.image.size.height)
// .layers(1)
// .build(),
// None,
// )?
// };
//
// Ok(OwnedFramebuffer {
// size,
// image,
// view: fb_view,
// render_pass,
// framebuffer: VulkanFramebuffer {
// device: vulkan.device.clone(),
// framebuffer,
// },
// })
// }
// }
pub struct OwnedFramebuffer { #[derive(Clone)]
pub size: Size<u32>,
pub image: OwnedTexture,
pub render_pass: VulkanRenderPass,
pub framebuffer: VulkanFramebuffer,
pub view: vk::ImageView,
}
impl OwnedFramebuffer {
pub fn new(
vulkan: &Vulkan,
size: Size<u32>,
render_pass: VulkanRenderPass,
max_miplevels: u32,
) -> error::Result<Self> {
let image = OwnedTexture::new(vulkan, size, render_pass.format, max_miplevels)?;
let fb_view = image.create_texture_view()?;
let framebuffer = unsafe {
vulkan.device.create_framebuffer(
&vk::FramebufferCreateInfo::builder()
.render_pass(render_pass.handle)
.attachments(&[image.image_view])
.width(image.image.size.width)
.height(image.image.size.height)
.layers(1)
.build(),
None,
)?
};
Ok(OwnedFramebuffer {
size,
image,
view: fb_view,
render_pass,
framebuffer: VulkanFramebuffer {
device: vulkan.device.clone(),
framebuffer,
},
})
}
}
#[derive(Debug, Clone)]
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 viewport: vk::Viewport, device: ash::Device,
image_view: vk::ImageView,
} }
// //
@ -81,66 +82,77 @@ pub(crate) struct OutputFramebuffer {
// pub image_view: vk::ImageView, // pub image_view: vk::ImageView,
// } // }
// //
// impl<'a> OutputFramebuffer<'a> { impl OutputFramebuffer {
// pub fn new(vulkan: &Vulkan, render_pass: &'a VulkanRenderPass, image: vk::Image, size: Size<u32>) -> error::Result<OutputFramebuffer<'a>> { pub fn new(vulkan: &Vulkan, render_pass: &VulkanRenderPass, image: vk::Image, size: Size<u32>) -> error::Result<OutputFramebuffer> {
// 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)
// .level_count(1) .level_count(1)
// .layer_count(1) .layer_count(1)
// .aspect_mask(ImageAspectFlags::COLOR) .aspect_mask(ImageAspectFlags::COLOR)
// .build(); .build();
//
// let swizzle_components = vk::ComponentMapping::builder() let swizzle_components = vk::ComponentMapping::builder()
// .r(vk::ComponentSwizzle::R) .r(vk::ComponentSwizzle::R)
// .g(vk::ComponentSwizzle::G) .g(vk::ComponentSwizzle::G)
// .b(vk::ComponentSwizzle::B) .b(vk::ComponentSwizzle::B)
// .a(vk::ComponentSwizzle::A) .a(vk::ComponentSwizzle::A)
// .build(); .build();
//
// let mut view_info = vk::ImageViewCreateInfo::builder() let mut view_info = vk::ImageViewCreateInfo::builder()
// .view_type(ImageViewType::TYPE_2D) .view_type(ImageViewType::TYPE_2D)
// .format(render_pass.format.into()) .format(render_pass.format.into())
// .image(image.clone()) .image(image.clone())
// .subresource_range(image_subresource) .subresource_range(image_subresource)
// .components(swizzle_components) .components(swizzle_components)
// .build(); .build();
//
// let image_view = unsafe { vulkan.device.create_image_view(&view_info, None)? }; let image_view = unsafe { vulkan.device.create_image_view(&view_info, None)? };
//
// let framebuffer = unsafe { let framebuffer = unsafe {
// vulkan.device.create_framebuffer( vulkan.device.create_framebuffer(
// &vk::FramebufferCreateInfo::builder() &vk::FramebufferCreateInfo::builder()
// .render_pass(render_pass.handle) .render_pass(render_pass.handle)
// .attachments(&[image_view]) .attachments(&[image_view])
// .width(size.width) .width(size.width)
// .height(size.height) .height(size.height)
// .layers(1) .layers(1)
// .build(), .build(),
// None, None,
// )? )?
// }; };
//
// Ok(OutputFramebuffer { Ok(OutputFramebuffer {
// device: vulkan.device.clone(), device: vulkan.device.clone(),
// image, size,
// image_view, framebuffer,
// render_pass, image_view,
// size, })
// handle: framebuffer, }
// })
// } // pub fn get_renderpass_begin_info(&self, area: vk::Rect2D, clear: Option<&[vk::ClearValue]>) -> vk::RenderPassBeginInfo {
// // let mut builder = vk::RenderPassBeginInfo::builder()
// pub fn get_renderpass_begin_info(&self, area: vk::Rect2D, clear: Option<&[vk::ClearValue]>) -> vk::RenderPassBeginInfo { // .render_pass(self.render_pass.handle)
// let mut builder = vk::RenderPassBeginInfo::builder() // .framebuffer(self.handle)
// .render_pass(self.render_pass.handle) // .render_area(area);
// .framebuffer(self.handle) //
// .render_area(area); // if let Some(clear) = clear {
// // builder = builder.clear_values(clear)
// if let Some(clear) = clear { // }
// builder = builder.clear_values(clear) //
// } // builder.build()
// // }
// builder.build() }
// }
// } 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);
}
}
}
}

View file

@ -22,6 +22,7 @@ use ash::vk::RenderingInfo;
use winit::event::{ElementState, Event, KeyboardInput, VirtualKeyCode, WindowEvent}; use winit::event::{ElementState, Event, KeyboardInput, VirtualKeyCode, WindowEvent};
use winit::event_loop::{ControlFlow, EventLoop, EventLoopBuilder}; use winit::event_loop::{ControlFlow, EventLoop, EventLoopBuilder};
use winit::platform::windows::EventLoopBuilderExtWindows; use winit::platform::windows::EventLoopBuilderExtWindows;
use crate::texture::VulkanImage;
// Constants // Constants
const WINDOW_TITLE: &'static str = "librashader Vulkan"; const WINDOW_TITLE: &'static str = "librashader Vulkan";
@ -173,6 +174,20 @@ impl VulkanWindow {
Self::record_command_buffer(vulkan, framebuffer, cmd); Self::record_command_buffer(vulkan, framebuffer, cmd);
filter.frame(0, &vk::Viewport {
x: 0.0,
y: 0.0,
width: vulkan.swapchain.extent.width as f32,
height: vulkan.swapchain.extent.height as f32,
min_depth: 0.0,
max_depth: 1.0,
}, &VulkanImage {
size: vulkan.swapchain.extent.into(),
image: framebuffer_image,
format: vulkan.swapchain.format.format,
}, cmd, None)
.unwrap();
util::vulkan_image_layout_transition_levels( util::vulkan_image_layout_transition_levels(
&vulkan.base.device, &vulkan.base.device,
cmd, cmd,

View file

@ -1,7 +1,7 @@
use crate::framebuffer::OutputFramebuffer; use crate::framebuffer::OutputFramebuffer;
use ash::vk; use ash::vk;
#[derive(Debug, Clone)] #[derive(Clone)]
pub(crate) struct RenderTarget<'a> { pub(crate) struct RenderTarget<'a> {
pub mvp: &'a [f32; 16], pub mvp: &'a [f32; 16],
pub output: OutputFramebuffer, pub output: OutputFramebuffer,

View file

@ -8,10 +8,12 @@ use ash::vk::{
SampleCountFlags, SharingMode, SampleCountFlags, SharingMode,
}; };
use librashader_common::{FilterMode, ImageFormat, Size, WrapMode}; use librashader_common::{FilterMode, ImageFormat, Size, WrapMode};
use librashader_runtime::scaling::MipmapSize; use librashader_presets::Scale2D;
use librashader_runtime::scaling::{MipmapSize, ViewportSize};
pub struct OwnedTexture { pub struct OwnedTexture {
pub device: ash::Device, pub device: ash::Device,
pub mem_props: vk::PhysicalDeviceMemoryProperties,
pub image_view: vk::ImageView, pub image_view: vk::ImageView,
pub image: VulkanImage, pub image: VulkanImage,
pub memory: VulkanImageMemory, pub memory: VulkanImageMemory,
@ -19,8 +21,9 @@ pub struct OwnedTexture {
} }
impl OwnedTexture { impl OwnedTexture {
pub fn new( fn new_internal(
vulkan: &Vulkan, device: ash::Device,
mem_props: vk::PhysicalDeviceMemoryProperties,
size: Size<u32>, size: Size<u32>,
format: ImageFormat, format: ImageFormat,
max_miplevels: u32, max_miplevels: u32,
@ -43,20 +46,20 @@ impl OwnedTexture {
.initial_layout(ImageLayout::UNDEFINED) .initial_layout(ImageLayout::UNDEFINED)
.build(); .build();
let image = unsafe { vulkan.device.create_image(&image_create_info, None)? }; let image = unsafe { device.create_image(&image_create_info, None)? };
let mem_reqs = unsafe { vulkan.device.get_image_memory_requirements(image.clone()) }; let mem_reqs = unsafe { device.get_image_memory_requirements(image.clone()) };
let alloc_info = vk::MemoryAllocateInfo::builder() let alloc_info = vk::MemoryAllocateInfo::builder()
.allocation_size(mem_reqs.size) .allocation_size(mem_reqs.size)
.memory_type_index(find_vulkan_memory_type( .memory_type_index(find_vulkan_memory_type(
&vulkan.memory_properties, &mem_props,
mem_reqs.memory_type_bits, mem_reqs.memory_type_bits,
vk::MemoryPropertyFlags::DEVICE_LOCAL, vk::MemoryPropertyFlags::DEVICE_LOCAL,
)) ))
.build(); .build();
// todo: optimize by reusing existing memory. // todo: optimize by reusing existing memory.
let memory = VulkanImageMemory::new(&vulkan.device, &alloc_info)?; let memory = VulkanImageMemory::new(&device, &alloc_info)?;
memory.bind(&image)?; memory.bind(&image)?;
let image_subresource = vk::ImageSubresourceRange::builder() let image_subresource = vk::ImageSubresourceRange::builder()
@ -82,10 +85,11 @@ impl OwnedTexture {
.components(swizzle_components) .components(swizzle_components)
.build(); .build();
let image_view = unsafe { vulkan.device.create_image_view(&view_info, None)? }; let image_view = unsafe { device.create_image_view(&view_info, None)? };
Ok(OwnedTexture { Ok(OwnedTexture {
device: vulkan.device.clone(), device,
mem_props,
image_view, image_view,
image: VulkanImage { image: VulkanImage {
image, image,
@ -97,6 +101,40 @@ impl OwnedTexture {
}) })
} }
pub fn new(
vulkan: &Vulkan,
size: Size<u32>,
format: ImageFormat,
max_miplevels: u32,
) -> error::Result<OwnedTexture> {
Self::new_internal(vulkan.device.clone(), vulkan.memory_properties, size, format, max_miplevels)
}
pub(crate) fn scale(
&mut self,
scaling: Scale2D,
format: ImageFormat,
viewport_size: &Size<u32>,
_original: &Texture,
source: &Texture,
) -> error::Result<Size<u32>> {
let size = source.image.size.scale_viewport(scaling, *viewport_size);
if self.image.size != size {
let mut new = OwnedTexture::new_internal(self.device.clone(), self.mem_props, size, if format == ImageFormat::Unknown {
ImageFormat::R8G8B8A8Unorm
} else {
format
}, self.max_miplevels)?;
std::mem::swap(self, &mut new)
}
Ok(size)
}
pub fn create_texture_view(&self) -> error::Result<vk::ImageView> { pub fn create_texture_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)
@ -139,12 +177,14 @@ impl Drop for OwnedTexture {
} }
} }
#[derive(Clone)]
pub struct VulkanImage { pub struct VulkanImage {
pub size: Size<u32>, pub size: Size<u32>,
pub image: vk::Image, pub image: vk::Image,
pub format: vk::Format, pub format: vk::Format,
} }
#[derive(Clone)]
pub struct Texture { pub struct Texture {
pub image: VulkanImage, pub image: VulkanImage,
pub image_view: vk::ImageView, pub image_view: vk::ImageView,