From a0c2ed028236277e800cec2f95e012daa77f0c2d Mon Sep 17 00:00:00 2001 From: galister <22305755+galister@users.noreply.github.com> Date: Wed, 31 Jan 2024 22:14:16 +0100 Subject: [PATCH] dynamic rendering pipelines --- src/backend/openxr/swapchain.rs | 8 +- src/graphics.rs | 285 +++++++++++++++++++++++++++----- src/gui/mod.rs | 12 +- src/overlays/screen.rs | 8 +- 4 files changed, 258 insertions(+), 55 deletions(-) diff --git a/src/backend/openxr/swapchain.rs b/src/backend/openxr/swapchain.rs index 6dae33c..1d98e52 100644 --- a/src/backend/openxr/swapchain.rs +++ b/src/backend/openxr/swapchain.rs @@ -9,7 +9,7 @@ use vulkano::{ Handle, }; -use crate::graphics::{WlxCommandBuffer, WlxGraphics, WlxPipeline}; +use crate::graphics::{WlxCommandBuffer, WlxGraphics, WlxPipeline, WlxPipelineLegacy}; use super::XrState; @@ -70,7 +70,7 @@ pub(super) fn create_swapchain_render_data( ); let buffer = Framebuffer::new( - pipeline.render_pass.clone(), + pipeline.data.render_pass.clone(), FramebufferCreateInfo { attachments: vec![view.clone()], extent: [view.image().extent()[0] as _, view.image().extent()[1] as _], @@ -104,7 +104,7 @@ pub(super) struct SwapchainRenderData { pub(super) struct SwapchainImagePipeline { pub(super) view: Arc, pub(super) buffer: Arc, - pub(super) pipeline: Arc, + pub(super) pipeline: Arc>, } impl SwapchainRenderData { @@ -120,7 +120,7 @@ impl SwapchainRenderData { let pipeline = image.pipeline.clone(); command_buffer.begin_render_pass(&pipeline); - let target_extent = image.pipeline.view.image().extent(); + let target_extent = image.pipeline.data.view.image().extent(); let set = image .pipeline .uniform_sampler(0, view.clone(), Filter::Linear); diff --git a/src/graphics.rs b/src/graphics.rs index 227b4bc..1e80542 100644 --- a/src/graphics.rs +++ b/src/graphics.rs @@ -9,7 +9,6 @@ use std::{ use ash::vk::{self, SubmitInfo}; use smallvec::smallvec; -use vulkano::instance::InstanceCreateFlags; use vulkano::{ buffer::{ allocator::{SubbufferAllocator, SubbufferAllocatorCreateInfo}, @@ -21,7 +20,8 @@ use vulkano::{ CommandBuffer, CommandBufferExecFuture, CommandBufferInheritanceInfo, CommandBufferInheritanceRenderPassInfo, CommandBufferInheritanceRenderPassType, CommandBufferLevel, CommandBufferUsage, CopyBufferToImageInfo, RecordingCommandBuffer, - RenderPassBeginInfo, SubpassBeginInfo, SubpassContents, SubpassEndInfo, + RenderPassBeginInfo, RenderingAttachmentInfo, RenderingInfo, SubpassBeginInfo, + SubpassContents, SubpassEndInfo, }, descriptor_set::{ allocator::StandardDescriptorSetAllocator, DescriptorSet, WriteDescriptorSet, @@ -56,13 +56,13 @@ use vulkano::{ input_assembly::InputAssemblyState, multisample::MultisampleState, rasterization::RasterizationState, + subpass::PipelineRenderingCreateInfo, vertex_input::{Vertex, VertexDefinition}, viewport::{Viewport, ViewportState}, GraphicsPipelineCreateInfo, }, layout::PipelineDescriptorSetLayoutCreateInfo, DynamicState, GraphicsPipeline, Pipeline, PipelineBindPoint, PipelineLayout, - PipelineShaderStageCreateInfo, }, render_pass::{ AttachmentDescription, AttachmentLoadOp, AttachmentReference, AttachmentStoreOp, @@ -76,6 +76,9 @@ use vulkano::{ }, DeviceSize, VulkanLibrary, VulkanObject, }; +use vulkano::{ + command_buffer::CommandBufferInheritanceRenderingInfo, instance::InstanceCreateFlags, +}; use wlx_capture::frame::{ DmabufFrame, FourCC, DRM_FORMAT_ABGR8888, DRM_FORMAT_ARGB8888, DRM_FORMAT_XBGR8888, @@ -630,8 +633,8 @@ impl WlxGraphics { vert: Arc, frag: Arc, format: Format, - ) -> Arc { - Arc::new(WlxPipeline::new( + ) -> Arc> { + Arc::new(WlxPipeline::::new( render_target, self.clone(), vert, @@ -648,8 +651,8 @@ impl WlxGraphics { format: Format, initial_layout: ImageLayout, final_layout: ImageLayout, - ) -> Arc { - Arc::new(WlxPipeline::new_with_layout( + ) -> Arc> { + Arc::new(WlxPipeline::::new_with_layout( render_target, self.clone(), vert, @@ -660,6 +663,21 @@ impl WlxGraphics { )) } + #[allow(dead_code)] + pub fn create_pipeline_dynamic( + self: &Arc, + vert: Arc, + frag: Arc, + format: Format, + ) -> Arc> { + Arc::new(WlxPipeline::::new( + self.clone(), + vert, + frag, + format, + )) + } + pub fn create_command_buffer(self: &Arc, usage: CommandBufferUsage) -> WlxCommandBuffer { let command_buffer = RecordingCommandBuffer::new( self.command_buffer_allocator.clone(), @@ -748,12 +766,12 @@ pub struct WlxCommandBuffer { } impl WlxCommandBuffer { - pub fn begin_render_pass(&mut self, pipeline: &WlxPipeline) { + pub fn begin_render_pass(&mut self, pipeline: &WlxPipeline) { self.command_buffer .begin_render_pass( RenderPassBeginInfo { clear_values: vec![Some([0.0, 0.0, 0.0, 1.0].into())], - ..RenderPassBeginInfo::framebuffer(pipeline.framebuffer.clone()) + ..RenderPassBeginInfo::framebuffer(pipeline.data.framebuffer.clone()) }, SubpassBeginInfo { contents: SubpassContents::SecondaryCommandBuffers, @@ -763,7 +781,23 @@ impl WlxCommandBuffer { .unwrap(); } - pub fn run_ref(&mut self, pass: &WlxPass) -> &mut Self { + #[allow(dead_code)] + pub fn begin_rendering(&mut self, render_target: Arc) { + self.command_buffer + .begin_rendering(RenderingInfo { + contents: SubpassContents::SecondaryCommandBuffers, + color_attachments: vec![Some(RenderingAttachmentInfo { + load_op: AttachmentLoadOp::Clear, + store_op: AttachmentStoreOp::Store, + clear_value: Some([0.0, 0.0, 0.0, 1.0].into()), + ..RenderingAttachmentInfo::image_view(render_target.clone()) + })], + ..Default::default() + }) + .unwrap(); + } + + pub fn run_ref(&mut self, pass: &WlxPass) -> &mut Self { let _ = self .command_buffer .execute_commands(pass.command_buffer.clone()) @@ -843,6 +877,11 @@ impl WlxCommandBuffer { .unwrap(); } + #[allow(dead_code)] + pub fn end_rendering(&mut self) { + self.command_buffer.end_rendering().unwrap(); + } + pub fn build(self) -> Arc { self.command_buffer.end().unwrap() } @@ -859,16 +898,105 @@ impl WlxCommandBuffer { } } -pub struct WlxPipeline { - pub graphics: Arc, - pub pipeline: Arc, +#[allow(dead_code)] +pub struct WlxPipelineDynamic {} + +pub struct WlxPipelineLegacy { pub render_pass: Arc, pub framebuffer: Arc, pub view: Arc, - pub format: Format, } -impl WlxPipeline { +pub struct WlxPipeline { + pub graphics: Arc, + pub pipeline: Arc, + pub format: Format, + pub data: D, +} + +impl WlxPipeline { + #[allow(dead_code)] + fn new( + graphics: Arc, + vert: Arc, + frag: Arc, + format: Format, + ) -> Self { + let vep = vert.entry_point("main").unwrap(); + let fep = frag.entry_point("main").unwrap(); + + let vertex_input_state = Vert2Uv::per_vertex() + .definition(&vep.info().input_interface) + .unwrap(); + + let stages = smallvec![ + vulkano::pipeline::PipelineShaderStageCreateInfo::new(vep), + vulkano::pipeline::PipelineShaderStageCreateInfo::new(fep), + ]; + + let layout = PipelineLayout::new( + graphics.device.clone(), + PipelineDescriptorSetLayoutCreateInfo::from_stages(&stages) + .into_pipeline_layout_create_info(graphics.device.clone()) + .unwrap(), + ) + .unwrap(); + + let subpass = PipelineRenderingCreateInfo { + color_attachment_formats: vec![Some(format)], + ..Default::default() + }; + + let pipeline = GraphicsPipeline::new( + graphics.device.clone(), + None, + GraphicsPipelineCreateInfo { + stages, + vertex_input_state: Some(vertex_input_state), + input_assembly_state: Some(InputAssemblyState::default()), + viewport_state: Some(ViewportState::default()), + rasterization_state: Some(RasterizationState::default()), + multisample_state: Some(MultisampleState::default()), + color_blend_state: Some(ColorBlendState { + attachments: vec![ColorBlendAttachmentState { + blend: Some(AttachmentBlend::alpha()), + ..Default::default() + }], + ..Default::default() + }), + dynamic_state: [DynamicState::Viewport].into_iter().collect(), + subpass: Some(subpass.into()), + ..GraphicsPipelineCreateInfo::layout(layout) + }, + ) + .unwrap(); + + Self { + graphics, + pipeline, + format, + data: WlxPipelineDynamic {}, + } + } + #[allow(dead_code)] + pub fn create_pass( + self: &Arc, + dimensions: [f32; 2], + vertex_buffer: Subbuffer<[Vert2Uv]>, + index_buffer: Subbuffer<[u16]>, + descriptor_sets: Vec>, + ) -> WlxPass { + WlxPass::::new( + self.clone(), + dimensions, + vertex_buffer, + index_buffer, + descriptor_sets, + ) + } +} + +impl WlxPipeline { fn new( render_target: Arc, graphics: Arc, @@ -948,8 +1076,8 @@ impl WlxPipeline { .unwrap(); let stages = smallvec![ - PipelineShaderStageCreateInfo::new(vep), - PipelineShaderStageCreateInfo::new(fep), + vulkano::pipeline::PipelineShaderStageCreateInfo::new(vep), + vulkano::pipeline::PipelineShaderStageCreateInfo::new(fep), ]; let layout = PipelineLayout::new( @@ -997,12 +1125,32 @@ impl WlxPipeline { graphics, pipeline, format, - render_pass, - framebuffer, - view: render_target, + data: WlxPipelineLegacy { + render_pass, + framebuffer, + view: render_target, + }, } } + pub fn create_pass( + self: &Arc, + dimensions: [f32; 2], + vertex_buffer: Subbuffer<[Vert2Uv]>, + index_buffer: Subbuffer<[u16]>, + descriptor_sets: Vec>, + ) -> WlxPass { + WlxPass::::new( + self.clone(), + dimensions, + vertex_buffer, + index_buffer, + descriptor_sets, + ) + } +} + +impl WlxPipeline { pub fn inner(&self) -> Arc { self.pipeline.clone() } @@ -1064,36 +1212,20 @@ impl WlxPipeline { ) .unwrap() } - - pub fn create_pass( - self: &Arc, - dimensions: [f32; 2], - vertex_buffer: Subbuffer<[Vert2Uv]>, - index_buffer: Subbuffer<[u16]>, - descriptor_sets: Vec>, - ) -> WlxPass { - WlxPass::new( - self.clone(), - dimensions, - vertex_buffer, - index_buffer, - descriptor_sets, - ) - } } #[allow(dead_code)] -pub struct WlxPass { - pipeline: Arc, +pub struct WlxPass { + pipeline: Arc>, vertex_buffer: Subbuffer<[Vert2Uv]>, index_buffer: Subbuffer<[u16]>, descriptor_sets: Vec>, pub command_buffer: Arc, } -impl WlxPass { +impl WlxPass { fn new( - pipeline: Arc, + pipeline: Arc>, dimensions: [f32; 2], vertex_buffer: Subbuffer<[Vert2Uv]>, index_buffer: Subbuffer<[u16]>, @@ -1115,7 +1247,7 @@ impl WlxPass { inheritance_info: Some(CommandBufferInheritanceInfo { render_pass: Some(CommandBufferInheritanceRenderPassType::BeginRenderPass( CommandBufferInheritanceRenderPassInfo { - subpass: Subpass::from(pipeline.render_pass.clone(), 0).unwrap(), + subpass: Subpass::from(pipeline.data.render_pass.clone(), 0).unwrap(), framebuffer: None, }, )), @@ -1163,6 +1295,77 @@ impl WlxPass { } } +impl WlxPass { + fn new( + pipeline: Arc>, + dimensions: [f32; 2], + vertex_buffer: Subbuffer<[Vert2Uv]>, + index_buffer: Subbuffer<[u16]>, + descriptor_sets: Vec>, + ) -> Self { + let viewport = Viewport { + offset: [0.0, 0.0], + extent: dimensions, + depth_range: 0.0..=1.0, + }; + let pipeline_inner = pipeline.inner().clone(); + let mut command_buffer = RecordingCommandBuffer::new( + pipeline.graphics.command_buffer_allocator.clone(), + pipeline.graphics.queue.queue_family_index(), + CommandBufferLevel::Secondary, + CommandBufferBeginInfo { + usage: CommandBufferUsage::MultipleSubmit, + inheritance_info: Some(CommandBufferInheritanceInfo { + render_pass: Some(CommandBufferInheritanceRenderPassType::BeginRendering( + CommandBufferInheritanceRenderingInfo { + color_attachment_formats: vec![Some(pipeline.format)], + ..Default::default() + }, + )), + ..Default::default() + }), + ..Default::default() + }, + ) + .unwrap(); + + unsafe { + command_buffer + .set_viewport(0, smallvec![viewport]) + .unwrap() + .bind_pipeline_graphics(pipeline_inner) + .unwrap() + .bind_descriptor_sets( + PipelineBindPoint::Graphics, + pipeline.inner().layout().clone(), + 0, + descriptor_sets.clone(), + ) + .unwrap() + .bind_vertex_buffers(0, vertex_buffer.clone()) + .unwrap() + .bind_index_buffer(index_buffer.clone()) + .unwrap() + .draw_indexed(index_buffer.len() as u32, 1, 0, 0, 0) + .or_else(|err| { + if let Some(source) = err.source() { + log::error!("Failed to draw: {}", source); + } + Err(err) + }) + .unwrap() + }; + + Self { + pipeline, + vertex_buffer, + index_buffer, + descriptor_sets, + command_buffer: command_buffer.end().unwrap(), + } + } +} + pub fn fourcc_to_vk(fourcc: FourCC) -> Format { match fourcc.value { DRM_FORMAT_ABGR8888 => Format::R8G8B8A8_UNORM, diff --git a/src/gui/mod.rs b/src/gui/mod.rs index 5759c1e..ef2bd92 100644 --- a/src/gui/mod.rs +++ b/src/gui/mod.rs @@ -12,7 +12,7 @@ use crate::{ input::{InteractionHandler, PointerHit}, overlay::{OverlayBackend, OverlayRenderer}, }, - graphics::{WlxCommandBuffer, WlxGraphics, WlxPass, WlxPipeline}, + graphics::{WlxCommandBuffer, WlxGraphics, WlxPass, WlxPipeline, WlxPipelineLegacy}, state::AppState, }; @@ -187,9 +187,9 @@ pub struct CanvasData { graphics: Arc, - pipeline_bg_color: Arc, - pipeline_fg_glyph: Arc, - pipeline_final: Arc, + pipeline_bg_color: Arc>, + pipeline_fg_glyph: Arc>, + pipeline_final: Arc>, } pub struct Canvas { @@ -205,8 +205,8 @@ pub struct Canvas { view_final: Arc, - pass_fg: WlxPass, - pass_bg: WlxPass, + pass_fg: WlxPass, + pass_bg: WlxPass, } impl Canvas { diff --git a/src/overlays/screen.rs b/src/overlays/screen.rs index 3a788c1..ea46016 100644 --- a/src/overlays/screen.rs +++ b/src/overlays/screen.rs @@ -32,7 +32,7 @@ use crate::{ }, config::def_pw_tokens, config_io, - graphics::{fourcc_to_vk, WlxGraphics, WlxPipeline}, + graphics::{fourcc_to_vk, WlxGraphics, WlxPipeline, WlxPipelineLegacy}, hid::{MOUSE_LEFT, MOUSE_MIDDLE, MOUSE_RIGHT}, state::{AppSession, AppState}, }; @@ -109,7 +109,7 @@ impl InteractionHandler for ScreenInteractionHandler { struct ScreenPipeline { graphics: Arc, - pipeline: Arc, + pipeline: Arc>, } impl ScreenPipeline { @@ -157,7 +157,7 @@ impl ScreenPipeline { Filter::Linear, ); - let dim = self.pipeline.view.image().extent(); + let dim = self.pipeline.data.view.image().extent(); let pass = self.pipeline.create_pass( [dim[0] as _, dim[1] as _], @@ -182,7 +182,7 @@ impl ScreenPipeline { } pub(super) fn view(&self) -> Arc { - self.pipeline.view.clone() + self.pipeline.data.view.clone() } }