From 32148cdff44c6393ee2953aca35f2942130771ba Mon Sep 17 00:00:00 2001 From: chyyran Date: Thu, 25 Jan 2024 20:05:31 -0500 Subject: [PATCH] rt(wgpu): filter pass logic --- librashader-common/src/wgpu.rs | 37 +-- librashader-runtime-wgpu/src/filter_pass.rs | 217 +++++++++++++++++- .../src/graphics_pipeline.rs | 23 +- librashader-runtime-wgpu/src/texture.rs | 14 +- 4 files changed, 262 insertions(+), 29 deletions(-) diff --git a/librashader-common/src/wgpu.rs b/librashader-common/src/wgpu.rs index e5a8272..30443a6 100644 --- a/librashader-common/src/wgpu.rs +++ b/librashader-common/src/wgpu.rs @@ -86,15 +86,25 @@ impl From> for ImageFormat { } // -// impl From> for vk::Extent3D { -// fn from(value: Size) -> Self { -// vk::Extent3D { -// width: value.width, -// height: value.height, -// depth: 1, -// } -// } -// } +impl From> for wgpu_types::Extent3d { + fn from(value: Size) -> Self { + wgpu_types::Extent3d { + width: value.width, + height: value.height, + depth: 1, + } + } +} + +impl From for Size { + fn from(value: wgpu_types::Extent3d) -> Self { + Size { + width: value.width, + height: value.height, + } + } +} + // // impl From> for vk::Extent2D { // fn from(value: Size) -> Self { @@ -105,14 +115,7 @@ impl From> for ImageFormat { // } // } // -// impl From for Size { -// fn from(value: vk::Extent3D) -> Self { -// Size { -// width: value.width, -// height: value.height, -// } -// } -// } + // // impl From for Size { // fn from(value: vk::Extent2D) -> Self { diff --git a/librashader-runtime-wgpu/src/filter_pass.rs b/librashader-runtime-wgpu/src/filter_pass.rs index 99a5f55..f60ff16 100644 --- a/librashader-runtime-wgpu/src/filter_pass.rs +++ b/librashader-runtime-wgpu/src/filter_pass.rs @@ -3,13 +3,25 @@ use librashader_preprocess::ShaderSource; use librashader_presets::ShaderPassConfig; use librashader_reflect::back::wgsl::NagaWgslContext; use librashader_reflect::back::ShaderCompilerOutput; -use librashader_reflect::reflect::semantics::{MemberOffset, UniformBinding}; +use librashader_reflect::reflect::semantics::{BindingStage, MemberOffset, TextureBinding, UniformBinding}; use librashader_reflect::reflect::ShaderReflection; -use librashader_runtime::uniforms::{NoUniformBinder, UniformStorage}; +use librashader_runtime::uniforms::{NoUniformBinder, UniformStorage, UniformStorageAccess}; use rustc_hash::FxHashMap; use std::sync::Arc; +use wgpu::{BindGroupDescriptor, BindGroupEntry, BindingResource, Buffer, BufferBinding, BufferUsages, RenderPass, ShaderStages, TextureView}; +use wgpu::util::{BufferInitDescriptor, DeviceExt}; +use librashader_common::{Size, Viewport}; +use librashader_runtime::binding::{BindSemantics, TextureInput}; +use librashader_runtime::quad::QuadType; +use librashader_runtime::render_target::RenderTarget; +use crate::error; +use crate::filter_chain::FilterCommon; +use crate::framebuffer::OutputImage; +use crate::samplers::SamplerSet; +use crate::texture::{InputImage, OwnedImage}; pub struct FilterPass { + pub device: Arc, pub reflection: ShaderReflection, pub(crate) compiled: ShaderCompilerOutput, pub(crate) uniform_storage: UniformStorage, @@ -20,3 +32,204 @@ pub struct FilterPass { // pub ubo_ring: VkUboRing, // pub frames_in_flight: u32, } + +impl TextureInput for InputImage { + fn size(&self) -> Size { + self.image.size().into() + } +} + +impl BindSemantics> for FilterPass { + type InputTexture = InputImage; + type SamplerSet = SamplerSet; + type DescriptorSet<'a> = ( + &'a mut FxHashMap>, + &'a mut FxHashMap>, + ); + type DeviceContext = Arc; + type UniformOffset = MemberOffset; + + #[inline(always)] + fn bind_texture<'a>( + descriptors: &mut Self::DescriptorSet<'a>, + samplers: &Self::SamplerSet, + binding: &TextureBinding, + texture: &Self::InputTexture, + _device: &Self::DeviceContext, + ) { + let sampler = samplers.get(texture.wrap_mode, texture.filter_mode, texture.mip_filter); + + let (texture_binding, sampler_binding) = descriptors; + texture_binding.insert(binding.binding, BindGroupEntry { + binding: binding.binding, + resource:BindingResource::TextureView(&texture.view)} + ); + sampler_binding.insert(binding.binding, BindGroupEntry { + binding: binding.binding, + resource: BindingResource::Sampler(&sampler), + }); + } +} + +impl FilterPass { + pub(crate) fn draw( + &mut self, + cmd: &mut wgpu::CommandEncoder, + pass_index: usize, + parent: &FilterCommon, + frame_count: u32, + frame_direction: i32, + viewport: &Viewport, + original: &InputImage, + source: &InputImage, + output: &RenderTarget, + vbo_type: QuadType, + ) -> error::Result { + + let mut main_heap = FxHashMap::default(); + let mut sampler_heap = FxHashMap::default(); + + self.build_semantics( + pass_index, + parent, + output.mvp, + frame_count, + frame_direction, + output.output.size, + viewport.output.size, + original, + source, + &mut main_heap, + &mut sampler_heap, + ); + + + let main_buffer: Buffer; + let pcb_buffer: Buffer; + if let Some(ubo) = &self.reflection.ubo { + main_buffer = self.device + .create_buffer_init(&BufferInitDescriptor { + label: Some("ubo buffer"), + contents: self.uniform_storage.ubo_slice(), + usage: BufferUsages::UNIFORM, + }); + + main_heap.insert(ubo.binding, BindGroupEntry { + binding: ubo.binding, + resource: BindingResource::Buffer(BufferBinding { + buffer: &main_buffer, + offset: 0, + size: None, + }), + }); + } + + let mut has_pcb_buffer = false; + if let Some(pcb) = &self.reflection.push_constant { + if let Some(binding) = pcb.binding { + pcb_buffer = self.device + .create_buffer_init(&BufferInitDescriptor { + label: Some("ubo buffer"), + contents: self.uniform_storage.push_slice(), + usage: BufferUsages::UNIFORM, + }); + + main_heap.insert(binding, BindGroupEntry { + binding, + resource: BindingResource::Buffer(BufferBinding { + buffer: &pcb_buffer, + offset: 0, + size: None, + }), + }); + has_pcb_buffer = true; + } + } + + + let mut render_pass = self.graphics_pipeline + .begin_rendering(output, cmd); + + let main_bind_group = self.device.create_bind_group(&BindGroupDescriptor { + label: Some("main bind group"), + layout: &self.graphics_pipeline.layout.main_bind_group_layout, + entries: &main_heap.into_values().collect::>() + }); + + let sampler_bind_group = self.device.create_bind_group(&BindGroupDescriptor { + label: Some("sampler bind group"), + layout: &self.graphics_pipeline.layout.sampler_bind_group_layout, + entries: &sampler_heap.into_values().collect::>() + }); + + render_pass.set_bind_group( + 0, + &main_bind_group, + &[] + ); + + render_pass.set_bind_group( + 1, + &sampler_bind_group, + &[] + ); + + if let Some(push) = &self.reflection.push_constant && !has_pcb_buffer { + let mut stage_mask = ShaderStages::empty(); + if push.stage_mask.contains(BindingStage::FRAGMENT) { + stage_mask |= ShaderStages::FRAGMENT; + } + if push.stage_mask.contains(BindingStage::VERTEX) { + stage_mask |= ShaderStages::VERTEX; + } + render_pass.set_push_constants( + stage_mask, + 0, + self.uniform_storage.push_slice() + ) + } + + parent.draw_quad.draw_quad(&mut render_pass, vbo_type); + + Ok(render_pass) + } + + 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, + original: &InputImage, + source: &InputImage, + main_heap: &mut FxHashMap + sampler_heap: &mut FxHashMap + ) { + Self::bind_semantics( + &self.device, + &parent.samplers, + &mut self.uniform_storage, + &mut (main_heap, sampler_heap), + mvp, + frame_count, + frame_direction, + fb_size, + viewport_size, + original, + source, + &self.uniform_bindings, + &self.reflection.meta.texture_meta, + parent.output_textures[0..pass_index] + .iter() + .map(|o| o.as_ref()), + parent.feedback_textures.iter().map(|o| o.as_ref()), + parent.history_textures.iter().map(|o| o.as_ref()), + parent.luts.iter().map(|(u, i)| (*u, i.as_ref())), + &self.source.parameters, + &parent.config.parameters, + ); + } +} diff --git a/librashader-runtime-wgpu/src/graphics_pipeline.rs b/librashader-runtime-wgpu/src/graphics_pipeline.rs index 2de96d3..5d37b0f 100644 --- a/librashader-runtime-wgpu/src/graphics_pipeline.rs +++ b/librashader-runtime-wgpu/src/graphics_pipeline.rs @@ -9,13 +9,14 @@ use librashader_runtime::render_target::RenderTarget; use crate::framebuffer::OutputImage; pub struct WgpuGraphicsPipeline { - layout: PipelineLayoutObjects, + pub layout: PipelineLayoutObjects, render_pipeline: wgpu::RenderPipeline, } pub struct PipelineLayoutObjects { layout: PipelineLayout, - bind_group_layouts: Vec, + pub main_bind_group_layout: BindGroupLayout, + pub sampler_bind_group_layout: BindGroupLayout, fragment_entry_name: String, vertex_entry_name: String, vertex: ShaderModule, @@ -39,8 +40,6 @@ impl PipelineLayoutObjects { source: ShaderSource::Wgsl(Cow::from(&shader_assembly.fragment)), }); - let mut bind_group_layouts = Vec::new(); - let mut main_bindings = Vec::new(); let mut sampler_bindings = Vec::new(); @@ -115,10 +114,7 @@ impl PipelineLayoutObjects { entries: &sampler_bindings, }); - bind_group_layouts.push(main_bind_group); - bind_group_layouts.push(sampler_bind_group); - - let bind_group_layout_refs = bind_group_layouts.iter().collect::>(); + let bind_group_layout_refs = [&main_bind_group, &sampler_bind_group]; let layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { label: Some("shader pipeline layout"), @@ -128,7 +124,8 @@ impl PipelineLayoutObjects { Self { layout, - bind_group_layouts, + main_bind_group_layout, + sampler_bind_group_layout, fragment_entry_name: shader_assembly.context.fragment.entry_points[0] .name .clone(), @@ -237,6 +234,13 @@ impl WgpuGraphicsPipeline { occlusion_query_set: None, }); + render_pass.set_scissor_rect( + output.x as u32, + output.y as u32, + output.output.size.width, + output.output.size.height + ); + render_pass.set_viewport( output.x, output.y, @@ -248,4 +252,5 @@ impl WgpuGraphicsPipeline { render_pass } + } diff --git a/librashader-runtime-wgpu/src/texture.rs b/librashader-runtime-wgpu/src/texture.rs index d48db73..f155170 100644 --- a/librashader-runtime-wgpu/src/texture.rs +++ b/librashader-runtime-wgpu/src/texture.rs @@ -17,7 +17,7 @@ pub struct OwnedImage { pub struct InputImage { /// A handle to the `VkImage`. pub image: wgpu::Texture, - pub image_view: wgpu::TextureView, + pub view: wgpu::TextureView, pub wrap_mode: WrapMode, pub filter_mode: FilterMode, pub mip_filter: FilterMode, @@ -92,4 +92,16 @@ impl OwnedImage { } size } + + pub(crate) fn as_input(&self, filter: FilterMode, wrap_mode: WrapMode) -> InputImage { + let image = self.clone(); + InputImage { + image: self.image.clone(), + view: self.clone()., + wrap_mode, + filter_mode: filter, + mip_filter: filter, + } + } + } \ No newline at end of file