diff --git a/librashader-runtime-vk/src/filter_chain.rs b/librashader-runtime-vk/src/filter_chain.rs index 8aac9e4..db685ae 100644 --- a/librashader-runtime-vk/src/filter_chain.rs +++ b/librashader-runtime-vk/src/filter_chain.rs @@ -126,13 +126,18 @@ pub struct FilterChainVulkan { // pub(crate) draw_quad: DrawQuad, } +pub struct FilterMutable { + pub(crate) passes_enabled: usize, + pub(crate) parameters: FxHashMap, +} + pub(crate) struct FilterCommon { pub(crate) luts: FxHashMap, pub samplers: SamplerSet, // pub output_textures: Box<[Option]>, // pub feedback_textures: Box<[Option]>, // pub history_textures: Box<[Option]>, - // pub config: FilterMutable, + pub config: FilterMutable, } pub type FilterChainOptionsVulkan = (); @@ -164,7 +169,17 @@ impl FilterChainVulkan { let samplers = SamplerSet::new(&device.device)?; eprintln!("filters initialized ok."); Ok(FilterChainVulkan { - common: FilterCommon { luts, samplers }, + common: FilterCommon { luts, + samplers, + config: FilterMutable { + passes_enabled: preset.shader_count as usize, + parameters: preset + .parameters + .into_iter() + .map(|param| (param.name, param.value)) + .collect(), + }, + }, passes: filters, }) } @@ -278,6 +293,8 @@ impl FilterChainVulkan { // shader_vulkan: 2026 filters.push(FilterPass { + device: vulkan.device.clone(), + reflection, compiled: spirv_words, uniform_storage, uniform_bindings, diff --git a/librashader-runtime-vk/src/filter_pass.rs b/librashader-runtime-vk/src/filter_pass.rs index 82842b9..af964b7 100644 --- a/librashader-runtime-vk/src/filter_pass.rs +++ b/librashader-runtime-vk/src/filter_pass.rs @@ -1,12 +1,20 @@ +use ash::vk; use crate::vulkan_state::VulkanGraphicsPipeline; use librashader_preprocess::ShaderSource; use librashader_presets::ShaderPassConfig; use librashader_reflect::back::ShaderCompilerOutput; -use librashader_reflect::reflect::semantics::{MemberOffset, UniformBinding}; +use librashader_reflect::reflect::semantics::{MemberOffset, TextureBinding, TextureSemantics, UniformBinding, UniqueSemantics}; use librashader_runtime::uniforms::UniformStorage; use rustc_hash::FxHashMap; +use librashader_common::Size; +use librashader_reflect::reflect::ShaderReflection; +use crate::filter_chain::FilterCommon; +use crate::texture::Texture; +use crate::samplers::{SamplerSet, VulkanSampler}; pub struct FilterPass { + pub device: ash::Device, + pub reflection: ShaderReflection, pub(crate) compiled: ShaderCompilerOutput>, pub(crate) uniform_storage: UniformStorage, pub uniform_bindings: FxHashMap, @@ -14,3 +22,298 @@ pub struct FilterPass { pub config: ShaderPassConfig, pub graphics_pipeline: VulkanGraphicsPipeline, } + + +impl FilterPass { + + #[inline(always)] + fn bind_texture(device: &ash::Device, + samplers: &SamplerSet, + descriptor_set: vk::DescriptorSet, + binding: &TextureBinding, + texture: &Texture) { + let sampler = samplers.get(texture.wrap_mode, texture.filter_mode, texture.mip_filter); + let image_info = [vk::DescriptorImageInfo::builder() + .sampler(sampler.handle) + .image_view(texture.image_view) + .image_layout(vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL) + .build()]; + + let write_desc = [vk::WriteDescriptorSet::builder() + .dst_set(descriptor_set) + .dst_binding(binding.binding) + .dst_array_element(0) + .descriptor_type(vk::DescriptorType::COMBINED_IMAGE_SAMPLER) + .image_info(&image_info) + .build()]; + unsafe { + device.update_descriptor_sets(&write_desc, &[]); + } + + } + + fn build_semantics( + &mut self, + pass_index: usize, + parent: &FilterCommon, + mvp: &[f32; 16], + frame_count: u32, + frame_direction: i32, + fb_size: Size, + viewport_size: Size, + descriptor_set: vk::DescriptorSet, + original: &Texture, + source: &Texture, + ) { + if let Some(offset) = self.uniform_bindings.get(&UniqueSemantics::MVP.into()) { + self.uniform_storage.bind_mat4(*offset, mvp, None); + } + + // bind OutputSize + if let Some(offset) = self.uniform_bindings.get(&UniqueSemantics::Output.into()) { + self.uniform_storage.bind_vec4(*offset, fb_size, None); + } + + // bind FinalViewportSize + if let Some(offset) = self + .uniform_bindings + .get(&UniqueSemantics::FinalViewport.into()) + { + self.uniform_storage.bind_vec4(*offset, viewport_size, None); + } + + // bind FrameCount + if let Some(offset) = self + .uniform_bindings + .get(&UniqueSemantics::FrameCount.into()) + { + self.uniform_storage.bind_scalar(*offset, frame_count, None); + } + + // bind FrameDirection + if let Some(offset) = self + .uniform_bindings + .get(&UniqueSemantics::FrameDirection.into()) + { + self.uniform_storage + .bind_scalar(*offset, frame_direction, None); + } + + // bind Original sampler + if let Some(binding) = self + .reflection + .meta + .texture_meta + .get(&TextureSemantics::Original.semantics(0)) + { + FilterPass::bind_texture( + &self.device, + &parent.samplers, + descriptor_set, + binding, + original, + ); + } + + // bind OriginalSize + if let Some(offset) = self + .uniform_bindings + .get(&TextureSemantics::Original.semantics(0).into()) + { + self.uniform_storage + .bind_vec4(*offset, original.size, None); + } + + // bind Source sampler + if let Some(binding) = self + .reflection + .meta + .texture_meta + .get(&TextureSemantics::Source.semantics(0)) + { + // eprintln!("setting source binding to {}", binding.binding); + FilterPass::bind_texture( + &self.device, + &parent.samplers, + descriptor_set, + binding, + source + ); + } + + // bind SourceSize + if let Some(offset) = self + .uniform_bindings + .get(&TextureSemantics::Source.semantics(0).into()) + { + self.uniform_storage + .bind_vec4(*offset, source.size, None); + } + + if let Some(binding) = self + .reflection + .meta + .texture_meta + .get(&TextureSemantics::OriginalHistory.semantics(0)) + { + FilterPass::bind_texture( + &self.device, + &parent.samplers, + descriptor_set, + binding, + original, + ); + } + + if let Some(offset) = self + .uniform_bindings + .get(&TextureSemantics::OriginalHistory.semantics(0).into()) + { + self.uniform_storage + .bind_vec4(*offset, original.size, None); + } + + // for (index, output) in parent.history_textures.iter().enumerate() { + // let Some(output) = output else { + // eprintln!("no history"); + // continue; + // }; + // if let Some(binding) = self + // .reflection + // .meta + // .texture_meta + // .get(&TextureSemantics::OriginalHistory.semantics(index + 1)) + // { + // FilterPass::bind_texture( + // &self.device, + // &parent.samplers, + // descriptor_set, + // binding, + // output, + // ); + // } + // + // if let Some(offset) = self.uniform_bindings.get( + // &TextureSemantics::OriginalHistory + // .semantics(index + 1) + // .into(), + // ) { + // self.uniform_storage + // .bind_vec4(*offset, output.size, None); + // } + // } + + // 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); + // } + // } + + // // PassFeedback + // for (index, feedback) in parent.feedback_textures.iter().enumerate() { + // let Some(feedback) = feedback else { + // eprintln!("no passfeedback {index}"); + // continue; + // }; + // if let Some(binding) = self + // .reflection + // .meta + // .texture_meta + // .get(&TextureSemantics::PassFeedback.semantics(index)) + // { + // FilterPass::bind_texture( + // &parent.samplers, + // &mut textures, + // &mut samplers, + // binding, + // feedback, + // ); + // } + // + // if let Some(offset) = self + // .uniform_bindings + // .get(&TextureSemantics::PassFeedback.semantics(index).into()) + // { + // self.uniform_storage + // .bind_vec4(*offset, feedback.view.size, None); + // } + // } + + // bind float parameters + for (id, offset) in + self.uniform_bindings + .iter() + .filter_map(|(binding, value)| match binding { + UniformBinding::Parameter(id) => Some((id, value)), + _ => None, + }) + { + let id = id.as_str(); + + let default = self + .source + .parameters + .iter() + .find(|&p| p.id == id) + .map(|f| f.initial) + .unwrap_or(0f32); + + let value = *parent.config.parameters.get(id).unwrap_or(&default); + + self.uniform_storage.bind_scalar(*offset, value, None); + } + + // bind luts + for (index, lut) in &parent.luts { + if let Some(binding) = self + .reflection + .meta + .texture_meta + .get(&TextureSemantics::User.semantics(*index)) + { + FilterPass::bind_texture( + &self.device, + &parent.samplers, + descriptor_set, + binding, + &lut.image, + ); + } + + if let Some(offset) = self + .uniform_bindings + .get(&TextureSemantics::User.semantics(*index).into()) + { + self.uniform_storage + .bind_vec4(*offset, lut.image.size, None); + } + } + + // (textures, samplers) + } +} \ No newline at end of file diff --git a/librashader-runtime-vk/src/framebuffer.rs b/librashader-runtime-vk/src/framebuffer.rs index 8e4177a..4ef5f8d 100644 --- a/librashader-runtime-vk/src/framebuffer.rs +++ b/librashader-runtime-vk/src/framebuffer.rs @@ -1,31 +1,17 @@ use crate::error; use crate::renderpass::VulkanRenderPass; -use crate::util::find_vulkan_memory_type; -use crate::vulkan_primitives::VulkanImageMemory; use ash::vk; use ash::vk::{ - Extent3D, ImageAspectFlags, ImageLayout, ImageTiling, ImageType, ImageUsageFlags, - ImageViewType, SampleCountFlags, SharingMode, + ImageAspectFlags, + ImageViewType, }; use librashader_common::Size; -use librashader_runtime::scaling::MipmapSize; - -pub struct Framebuffer { - device: ash::Device, - size: Size, - max_levels: u32, - mem_props: vk::PhysicalDeviceMemoryProperties, - render_pass: VulkanRenderPass, - framebuffer: Option, -} +use crate::filter_chain::Vulkan; +use crate::texture::OwnedTexture; pub struct VulkanFramebuffer { pub device: ash::Device, pub framebuffer: vk::Framebuffer, - pub image_view: vk::ImageView, - pub fb_view: vk::ImageView, - pub image: vk::Image, - pub memory: VulkanImageMemory, } impl Drop for VulkanFramebuffer { @@ -34,87 +20,72 @@ impl Drop for VulkanFramebuffer { 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.fb_view != vk::ImageView::null() { - self.device.destroy_image_view(self.fb_view, None); - } - if self.image != vk::Image::null() { - self.device.destroy_image(self.image, None); - } } } } -impl Framebuffer { +pub struct OwnedFramebuffer { + pub size: Size, + pub image: OwnedTexture, + pub render_pass: VulkanRenderPass, + pub framebuffer: VulkanFramebuffer, + pub view: vk::ImageView, +} + +impl OwnedFramebuffer { pub fn new( - device: &ash::Device, + vulkan: &Vulkan, size: Size, render_pass: VulkanRenderPass, - mip_levels: u32, - mem_props: vk::PhysicalDeviceMemoryProperties, + max_miplevels: u32, ) -> error::Result { - let mut framebuffer = Framebuffer { - device: device.clone(), - size, - max_levels: mip_levels, - mem_props, - render_pass, - framebuffer: None, + 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.size.width) + .height(image.size.height) + .layers(1) + .build(), + None, + )? }; - let vulkan_image = framebuffer.create_vulkan_image()?; - framebuffer.framebuffer = Some(vulkan_image); - - Ok(framebuffer) + Ok(OwnedFramebuffer { + size, + image, + view: fb_view, + render_pass, + framebuffer: VulkanFramebuffer { + device: vulkan.device.clone(), + framebuffer, + }, + }) } +} - pub fn create_vulkan_image(&mut self) -> error::Result { - let image_create_info = vk::ImageCreateInfo::builder() - .image_type(ImageType::TYPE_2D) - .format(self.render_pass.format.into()) - .extent(self.size.into()) - .mip_levels(std::cmp::min( - self.max_levels, - self.size.calculate_miplevels(), - )) - .array_layers(1) - .samples(SampleCountFlags::TYPE_1) - .tiling(ImageTiling::OPTIMAL) - .usage( - ImageUsageFlags::SAMPLED - | ImageUsageFlags::COLOR_ATTACHMENT - | ImageUsageFlags::TRANSFER_DST - | ImageUsageFlags::TRANSFER_SRC, - ) - .sharing_mode(SharingMode::EXCLUSIVE) - .initial_layout(ImageLayout::UNDEFINED) - .build(); - - let image = unsafe { self.device.create_image(&image_create_info, None)? }; - let mem_reqs = unsafe { self.device.get_image_memory_requirements(image.clone()) }; - - let alloc_info = vk::MemoryAllocateInfo::builder() - .allocation_size(mem_reqs.size) - .memory_type_index(find_vulkan_memory_type( - &self.mem_props, - mem_reqs.memory_type_bits, - vk::MemoryPropertyFlags::DEVICE_LOCAL, - )) - .build(); - - // todo: optimize by reusing existing memory. - let memory = VulkanImageMemory::new(&self.device, &alloc_info)?; - memory.bind(&image)?; +pub struct OutputFramebuffer<'a> { + device: ash::Device, + render_pass: &'a VulkanRenderPass, + pub handle: vk::Framebuffer, + pub size: Size, + pub image: vk::Image, + pub image_view: vk::ImageView, +} +impl<'a> OutputFramebuffer<'a> { + pub fn new(vulkan: &Vulkan, render_pass: &'a VulkanRenderPass, image: vk::Image, size: Size) -> error::Result> { let image_subresource = vk::ImageSubresourceRange::builder() .base_mip_level(0) .base_array_layer(0) - .level_count(image_create_info.mip_levels) + .level_count(1) .layer_count(1) .aspect_mask(ImageAspectFlags::COLOR) .build(); + let swizzle_components = vk::ComponentMapping::builder() .r(vk::ComponentSwizzle::R) .g(vk::ComponentSwizzle::G) @@ -124,37 +95,47 @@ impl Framebuffer { let mut view_info = vk::ImageViewCreateInfo::builder() .view_type(ImageViewType::TYPE_2D) - .format(self.render_pass.format.into()) + .format(render_pass.format.into()) .image(image.clone()) .subresource_range(image_subresource) .components(swizzle_components) .build(); - let image_view = unsafe { self.device.create_image_view(&view_info, None)? }; - - view_info.subresource_range.level_count = 1; - let fb_view = unsafe { self.device.create_image_view(&view_info, None)? }; + let image_view = unsafe { vulkan.device.create_image_view(&view_info, None)? }; let framebuffer = unsafe { - self.device.create_framebuffer( + vulkan.device.create_framebuffer( &vk::FramebufferCreateInfo::builder() - .render_pass(self.render_pass.render_pass) + .render_pass(render_pass.handle) .attachments(&[image_view]) - .width(self.size.width) - .height(self.size.height) + .width(size.width) + .height(size.height) .layers(1) .build(), None, )? }; - - Ok(VulkanFramebuffer { - device: self.device.clone(), - framebuffer, - memory, - image_view, - fb_view, + + Ok(OutputFramebuffer { + device: vulkan.device.clone(), image, + image_view, + render_pass, + 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() + .render_pass(self.render_pass.handle) + .framebuffer(self.handle) + .render_area(area); + + if let Some(clear) = clear { + builder = builder.clear_values(clear) + } + + builder.build() + } +} \ No newline at end of file diff --git a/librashader-runtime-vk/src/lib.rs b/librashader-runtime-vk/src/lib.rs index 3ddea92..42f0638 100644 --- a/librashader-runtime-vk/src/lib.rs +++ b/librashader-runtime-vk/src/lib.rs @@ -13,6 +13,7 @@ mod util; mod vulkan_primitives; mod vulkan_state; mod samplers; +mod texture; #[cfg(test)] mod tests { diff --git a/librashader-runtime-vk/src/luts.rs b/librashader-runtime-vk/src/luts.rs index 4512f3b..8f90321 100644 --- a/librashader-runtime-vk/src/luts.rs +++ b/librashader-runtime-vk/src/luts.rs @@ -8,15 +8,12 @@ use librashader_common::{FilterMode, WrapMode}; use librashader_presets::TextureConfig; use librashader_runtime::image::{Image, BGRA8}; use librashader_runtime::scaling::MipmapSize; +use crate::texture::Texture; pub struct LutTexture { - pub texture: vk::Image, - pub texture_view: vk::ImageView, pub memory: VulkanImageMemory, pub staging: VulkanBuffer, - pub filter_mode: FilterMode, - pub wrap_mode: WrapMode, - pub mipmap: bool, + pub image: Texture } impl LutTexture { @@ -237,13 +234,17 @@ impl LutTexture { } Ok(LutTexture { - texture, - texture_view, memory, staging, - filter_mode: config.filter_mode, - wrap_mode: config.wrap_mode, - mipmap: config.mipmap, + image: Texture { + size: image.size, + image_view: texture_view, + image: texture, + filter_mode: config.filter_mode, + wrap_mode: config.wrap_mode, + mip_filter: config.filter_mode, + format: vk::Format::B8G8R8A8_UNORM + } }) } } diff --git a/librashader-runtime-vk/src/renderpass.rs b/librashader-runtime-vk/src/renderpass.rs index e5b451d..271ba10 100644 --- a/librashader-runtime-vk/src/renderpass.rs +++ b/librashader-runtime-vk/src/renderpass.rs @@ -6,7 +6,7 @@ use ash::vk::{ use librashader_common::ImageFormat; pub struct VulkanRenderPass { - pub render_pass: vk::RenderPass, + pub handle: vk::RenderPass, pub format: ImageFormat, } @@ -51,7 +51,7 @@ impl VulkanRenderPass { unsafe { let rp = device.create_render_pass(&renderpass_info, None)?; Ok(Self { - render_pass: rp, + handle: rp, format, }) } diff --git a/librashader-runtime-vk/src/texture.rs b/librashader-runtime-vk/src/texture.rs new file mode 100644 index 0000000..89d5dc1 --- /dev/null +++ b/librashader-runtime-vk/src/texture.rs @@ -0,0 +1,147 @@ +use ash::vk; +use ash::vk::{ImageAspectFlags, ImageLayout, ImageTiling, ImageType, ImageUsageFlags, ImageViewType, SampleCountFlags, SharingMode}; +use librashader_common::{FilterMode, ImageFormat, Size, WrapMode}; +use librashader_runtime::scaling::MipmapSize; +use crate::error; +use crate::filter_chain::Vulkan; +use crate::util::find_vulkan_memory_type; +use crate::vulkan_primitives::VulkanImageMemory; + +pub struct OwnedTexture { + pub device: ash::Device, + pub image_view: vk::ImageView, + pub image: vk::Image, + pub format: vk::Format, + pub memory: VulkanImageMemory, + pub size: Size, + pub max_miplevels: u32, +} + +impl OwnedTexture { + pub fn new(vulkan: &Vulkan, size: Size, format: ImageFormat, max_miplevels: u32) + -> error::Result { + let image_create_info = vk::ImageCreateInfo::builder() + .image_type(ImageType::TYPE_2D) + .format(format.into()) + .extent(size.into()) + .mip_levels(std::cmp::min( + max_miplevels, + size.calculate_miplevels(), + )) + .array_layers(1) + .samples(SampleCountFlags::TYPE_1) + .tiling(ImageTiling::OPTIMAL) + .usage( + ImageUsageFlags::SAMPLED + | ImageUsageFlags::COLOR_ATTACHMENT + | ImageUsageFlags::TRANSFER_DST + | ImageUsageFlags::TRANSFER_SRC, + ) + .sharing_mode(SharingMode::EXCLUSIVE) + .initial_layout(ImageLayout::UNDEFINED) + .build(); + + let image = unsafe { vulkan.device.create_image(&image_create_info, None)? }; + let mem_reqs = unsafe { vulkan.device.get_image_memory_requirements(image.clone()) }; + + let alloc_info = vk::MemoryAllocateInfo::builder() + .allocation_size(mem_reqs.size) + .memory_type_index(find_vulkan_memory_type( + &vulkan.memory_properties, + mem_reqs.memory_type_bits, + vk::MemoryPropertyFlags::DEVICE_LOCAL, + )) + .build(); + + // todo: optimize by reusing existing memory. + let memory = VulkanImageMemory::new(&vulkan.device, &alloc_info)?; + memory.bind(&image)?; + + let image_subresource = vk::ImageSubresourceRange::builder() + .base_mip_level(0) + .base_array_layer(0) + .level_count(image_create_info.mip_levels) + .layer_count(1) + .aspect_mask(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(ImageViewType::TYPE_2D) + .format(format.into()) + .image(image.clone()) + .subresource_range(image_subresource) + .components(swizzle_components) + .build(); + + let image_view = unsafe { vulkan.device.create_image_view(&view_info, None)? }; + + Ok(OwnedTexture { + device: vulkan.device.clone(), + image_view, + image, + size, + format: format.into(), + memory, + max_miplevels, + }) + } + + pub fn create_texture_view(&self) -> error::Result { + let image_subresource = vk::ImageSubresourceRange::builder() + .base_mip_level(0) + .base_array_layer(0) + .level_count(1) + .layer_count(1) + .aspect_mask(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(ImageViewType::TYPE_2D) + .format(self.format) + .image(self.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) + } +} + +impl Drop for OwnedTexture { + fn drop(&mut self) { + unsafe { + if self.image_view != vk::ImageView::null() { + self.device.destroy_image_view(self.image_view, None); + } + if self.image != vk::Image::null() { + self.device.destroy_image(self.image, None); + } + } + } +} + +pub struct Texture { + pub size: Size, + pub image_view: vk::ImageView, + pub image: vk::Image, + pub format: vk::Format, + pub wrap_mode: WrapMode, + pub filter_mode: FilterMode, + pub mip_filter: FilterMode, +} diff --git a/librashader-runtime-vk/src/vulkan_state.rs b/librashader-runtime-vk/src/vulkan_state.rs index ff92dd3..f591565 100644 --- a/librashader-runtime-vk/src/vulkan_state.rs +++ b/librashader-runtime-vk/src/vulkan_state.rs @@ -302,7 +302,7 @@ impl VulkanGraphicsPipeline { .viewport_state(&viewport_state) .depth_stencil_state(&depth_stencil_state) .dynamic_state(&dynamic_state) - .render_pass(render_pass.render_pass.clone()) + .render_pass(render_pass.handle.clone()) .layout(pipeline_layout.layout) .build();