diff options
author | tcmal <me@aria.rip> | 2024-08-25 17:44:24 +0100 |
---|---|---|
committer | tcmal <me@aria.rip> | 2024-08-25 17:44:24 +0100 |
commit | 982c053f3946b53e1d763df71e4ffcb81362e8d3 (patch) | |
tree | cab91964c0e456db51c487d8ca2051b18ec70bcd /stockton-render | |
parent | 3b21e4c9d1d72a2ba71e4e4c1a2f60fb51f67205 (diff) |
fix(render): unsoundness in handle_surface_change
Diffstat (limited to 'stockton-render')
-rw-r--r-- | stockton-render/src/level.rs | 396 | ||||
-rw-r--r-- | stockton-render/src/ui.rs | 288 |
2 files changed, 335 insertions, 349 deletions
diff --git a/stockton-render/src/level.rs b/stockton-render/src/level.rs index b1f7b7c..f577569 100644 --- a/stockton-render/src/level.rs +++ b/stockton-render/src/level.rs @@ -10,8 +10,8 @@ use stockton_skeleton::{ image::{BoundImageView, ImageSpec, DEPTH_RESOURCES}, }, builders::{ - AttachmentSpec, CompletePipeline, PipelineSpec, PipelineSpecBuilder, RenderpassSpec, - ShaderDesc, VertexBufferSpec, VertexPrimitiveAssemblerSpec, + AttachmentSpec, CompletePipeline, PipelineSpecBuilder, RenderpassSpec, ShaderDesc, + VertexBufferSpec, VertexPrimitiveAssemblerSpec, }, context::RenderingContext, draw_passes::{util::TargetSpecificResources, DrawPass, IntoDrawPass, PassPosition}, @@ -57,14 +57,10 @@ struct UvPoint(pub Vector3, pub i32, pub Vector2); /// Draw a level pub struct LevelDrawPass<'a, M> { - pipeline: CompletePipeline, repo: TextureRepo<TexturesPool, StagingPool>, active_camera: Entity, draw_buffers: DrawBuffers<'a, UvPoint, DataPool, StagingPool>, - - framebuffers: TargetSpecificResources<FramebufferT>, - depth_buffers: TargetSpecificResources<BoundImageView<DepthBufferPool>>, - + surface_resources: SurfaceDependentResources, _d: PhantomData<M>, } @@ -96,8 +92,8 @@ where .context("Couldn't find camera components")?; let camera_vp = { - let aspect_ratio = - self.pipeline.render_area.w as f32 / self.pipeline.render_area.h as f32; + let aspect_ratio = self.surface_resources.pipeline.render_area.w as f32 + / self.surface_resources.pipeline.render_area.h as f32; // Get look direction from euler angles let direction = euler_to_direction(&camera_transform.rotation); @@ -131,14 +127,14 @@ where let map = map_lock.read().map_err(|_| LockPoisoned::Map)?; // Get framebuffer and depth buffer - let fb = self.framebuffers.get_next(); - let db = self.depth_buffers.get_next(); + let fb = self.surface_resources.framebuffers.get_next(); + let db = self.surface_resources.depth_buffers.get_next(); unsafe { cmd_buffer.begin_render_pass( - &self.pipeline.renderpass, + &self.surface_resources.pipeline.renderpass, fb, - self.pipeline.render_area, + self.surface_resources.pipeline.render_area, vec![ RenderAttachmentInfo { image_view: img_view, @@ -161,13 +157,13 @@ where .into_iter(), SubpassContents::Inline, ); - cmd_buffer.bind_graphics_pipeline(&self.pipeline.pipeline); + cmd_buffer.bind_graphics_pipeline(&self.surface_resources.pipeline.pipeline); // VP Matrix let vp = &*(camera_vp.data.as_slice() as *const [f32] as *const [u32]); cmd_buffer.push_graphics_constants( - &self.pipeline.pipeline_layout, + &self.surface_resources.pipeline.pipeline_layout, ShaderStageFlags::VERTEX, 0, vp, @@ -270,16 +266,7 @@ where fn deactivate(self, context: &mut RenderingContext) -> Result<()> { self.draw_buffers.deactivate(context); - unsafe { - let mut device = context.lock_device()?; - self.pipeline.deactivate(&mut device); - for fb in self.framebuffers.dissolve() { - device.destroy_framebuffer(fb); - } - } - for db in self.depth_buffers.dissolve() { - db.deactivate_with_context(context); - } + self.surface_resources.deactivate(context)?; self.repo.deactivate(context); Ok(()) @@ -290,39 +277,21 @@ where _session: &Session, context: &mut RenderingContext, ) -> Result<Self> { - // TODO: Handle deactivation if any of this fails. - - // Recreate depth buffers - for db in self.depth_buffers.dissolve() { - db.deactivate_with_context(context); - } - self.depth_buffers = create_depth_buffers(context)?; - - { - let mut device = context.lock_device()?; - - // Recreate pipeline - self.pipeline.deactivate(&mut device); - self.pipeline = create_pipeline_spec::<P>(context)? - .build( - &mut device, - context.properties().extent, - once(&*self.repo.get_ds_layout()?), - ) - .context("Error building pipeline")?; - - // Recreate framebuffers - for fb in self.framebuffers.dissolve() { - unsafe { - device.destroy_framebuffer(fb); - } + let new_resources = + SurfaceDependentResources::new::<P>(context, &*self.repo.get_ds_layout()?)?; + let old_resources = self.surface_resources; + self.surface_resources = new_resources; + + match old_resources.deactivate(context) { + Ok(_) => Ok(self), + Err(e) => { + <Self as DrawPass<P>>::deactivate(self, context)?; + Err(e) } - self.framebuffers = create_framebuffers(&mut device, &self.pipeline, context)?; } - - Ok(self) } } + impl<'a, M> LevelDrawPass<'a, M> { fn draw_or_queue( &mut self, @@ -334,7 +303,7 @@ impl<'a, M> LevelDrawPass<'a, M> { if let Some(ds) = self.repo.attempt_get_descriptor_set(current_chunk) { unsafe { cmd_buffer.bind_graphics_descriptor_sets( - &*self.pipeline.pipeline_layout, + &*self.surface_resources.pipeline.pipeline_layout, 0, once(ds), empty(), @@ -365,7 +334,6 @@ where _session: &mut Session, context: &mut RenderingContext, ) -> Result<LevelDrawPass<'a, M>> { - let spec = create_pipeline_spec::<P>(context)?; let repo = TextureRepo::new::<_, TexLoadQueue>( context, TextureLoadConfig { @@ -375,33 +343,18 @@ where }, ) .context("Error creating texture repo")?; - let draw_buffers = DrawBuffers::from_context(context).context("Error creating draw buffers")?; - let (pipeline, framebuffers) = { - let mut device = context.lock_device()?; - let pipeline = spec - .build( - &mut device, - context.properties().extent, - once(&*repo.get_ds_layout()?), - ) - .context("Error building pipeline")?; - let framebuffers = create_framebuffers(&mut device, &pipeline, context)?; - - (pipeline, framebuffers) - }; - let depth_buffers = create_depth_buffers(context)?; + let surface_resources = + SurfaceDependentResources::new::<P>(context, &*repo.get_ds_layout()?)?; Ok(LevelDrawPass { - pipeline, repo, draw_buffers, active_camera: self.active_camera, + surface_resources, _d: PhantomData, - framebuffers, - depth_buffers, }) } @@ -415,30 +368,6 @@ where } } -fn create_framebuffers( - device: &mut DeviceT, - pipeline: &CompletePipeline, - context: &RenderingContext, -) -> Result<TargetSpecificResources<FramebufferT>> { - let fat = context.properties().swapchain_framebuffer_attachment(); - let dat = FramebufferAttachment { - usage: Usage::DEPTH_STENCIL_ATTACHMENT, - format: context.properties().depth_format, - view_caps: ViewCapabilities::empty(), - }; - - TargetSpecificResources::new( - || unsafe { - Ok(device.create_framebuffer( - &pipeline.renderpass, - IntoIter::new([fat.clone(), dat.clone()]), - context.properties().extent, - )?) - }, - context.properties().image_count as usize, - ) -} - /// Indicates an issue with the level object being used #[derive(Debug, Error)] pub enum LevelError { @@ -446,6 +375,173 @@ pub enum LevelError { BadReference, } +/// Used to store resources which depend on the surface, for convenience in handle_surface_change +struct SurfaceDependentResources { + pub pipeline: CompletePipeline, + pub framebuffers: TargetSpecificResources<FramebufferT>, + pub depth_buffers: TargetSpecificResources<BoundImageView<DepthBufferPool>>, +} + +impl SurfaceDependentResources { + pub fn new<P: PassPosition>( + context: &mut RenderingContext, + ds_layout: &DescriptorSetLayoutT, + ) -> Result<Self> { + let db_spec = ImageSpec { + width: context.properties().extent.width, + height: context.properties().extent.height, + format: context.properties().depth_format, + usage: Usage::DEPTH_STENCIL_ATTACHMENT, + resources: DEPTH_RESOURCES, + }; + let img_count = context.properties().image_count; + + let depth_buffers = TargetSpecificResources::new( + || { + BoundImageView::from_context(context, &db_spec) + .context("Error creating depth buffer") + }, + img_count as usize, + )?; + + let (pipeline, framebuffers) = { + let pipeline_spec = PipelineSpecBuilder::default() + .rasterizer(Rasterizer { + polygon_mode: PolygonMode::Fill, + cull_face: Face::BACK, + front_face: FrontFace::CounterClockwise, + depth_clamping: false, + depth_bias: None, + conservative: true, + line_width: State::Static(1.0), + }) + .depth_stencil(DepthStencilDesc { + depth: Some(DepthTest { + fun: Comparison::Less, + write: true, + }), + depth_bounds: false, + stencil: None, + }) + .blender(BlendDesc { + logic_op: Some(LogicOp::Copy), + targets: vec![ColorBlendDesc { + mask: ColorMask::ALL, + blend: Some(BlendState { + color: BlendOp::Add { + src: Factor::SrcAlpha, + dst: Factor::OneMinusSrcAlpha, + }, + alpha: BlendOp::Add { + src: Factor::SrcAlpha, + dst: Factor::OneMinusSrcAlpha, + }, + }), + }], + }) + .primitive_assembler(VertexPrimitiveAssemblerSpec::with_buffers( + InputAssemblerDesc::new(Primitive::TriangleList), + vec![VertexBufferSpec { + attributes: vec![Format::Rgb32Sfloat, Format::R32Sint, Format::Rg32Sfloat], + rate: VertexInputRate::Vertex, + }], + )) + .shader_vertex(ShaderDesc { + source: include_str!("./data/3d.vert").to_string(), + entry: "main".to_string(), + kind: ShaderKind::Vertex, + }) + .shader_fragment(ShaderDesc { + source: include_str!("./data/3d.frag").to_string(), + entry: "main".to_string(), + kind: ShaderKind::Fragment, + }) + .push_constants(vec![(ShaderStageFlags::VERTEX, 0..64)]) + .renderpass(RenderpassSpec { + colors: vec![AttachmentSpec { + attachment: Attachment { + format: Some(context.properties().color_format), + samples: 1, + ops: P::attachment_ops(), + stencil_ops: P::attachment_ops(), + layouts: P::layout_as_range(), + }, + + used_layout: Layout::ColorAttachmentOptimal, + }], + depth: Some(AttachmentSpec { + attachment: Attachment { + format: Some(context.properties().depth_format), + samples: 1, + ops: AttachmentOps::new( + AttachmentLoadOp::Clear, + AttachmentStoreOp::DontCare, + ), + stencil_ops: AttachmentOps::new( + AttachmentLoadOp::DontCare, + AttachmentStoreOp::DontCare, + ), + layouts: Layout::Undefined..Layout::DepthStencilAttachmentOptimal, + }, + used_layout: Layout::DepthStencilAttachmentOptimal, + }), + inputs: vec![], + resolves: vec![], + preserves: vec![], + }) + .build() + .context("Error building pipeline")?; + let mut device = context.lock_device()?; + + let pipeline = pipeline_spec + .build(&mut device, context.properties().extent, once(ds_layout)) + .context("Error building pipeline")?; + + let fat = context.properties().swapchain_framebuffer_attachment(); + let dat = FramebufferAttachment { + usage: Usage::DEPTH_STENCIL_ATTACHMENT, + format: context.properties().depth_format, + view_caps: ViewCapabilities::empty(), + }; + + let framebuffers = TargetSpecificResources::new( + || unsafe { + Ok(device.create_framebuffer( + &pipeline.renderpass, + IntoIter::new([fat.clone(), dat.clone()]), + context.properties().extent, + )?) + }, + context.properties().image_count as usize, + )?; + + (pipeline, framebuffers) + }; + + Ok(Self { + pipeline, + framebuffers, + depth_buffers, + }) + } + + pub fn deactivate(self, context: &mut RenderingContext) -> Result<()> { + for db in self.depth_buffers.dissolve() { + db.deactivate_with_context(context); + } + unsafe { + let mut device = context.lock_device()?; + for fb in self.framebuffers.dissolve() { + device.destroy_framebuffer(fb); + } + + self.pipeline.deactivate(&mut device); + } + + Ok(()) + } +} + fn euler_to_direction(euler: &Vector3) -> Vector3 { let pitch = euler.x; let yaw = euler.y; @@ -457,107 +553,3 @@ fn euler_to_direction(euler: &Vector3) -> Vector3 { yaw.cos() * pitch.cos(), ) } - -fn create_pipeline_spec<P: PassPosition>(context: &RenderingContext) -> Result<PipelineSpec> { - Ok(PipelineSpecBuilder::default() - .rasterizer(Rasterizer { - polygon_mode: PolygonMode::Fill, - cull_face: Face::BACK, - front_face: FrontFace::CounterClockwise, - depth_clamping: false, - depth_bias: None, - conservative: true, - line_width: State::Static(1.0), - }) - .depth_stencil(DepthStencilDesc { - depth: Some(DepthTest { - fun: Comparison::Less, - write: true, - }), - depth_bounds: false, - stencil: None, - }) - .blender(BlendDesc { - logic_op: Some(LogicOp::Copy), - targets: vec![ColorBlendDesc { - mask: ColorMask::ALL, - blend: Some(BlendState { - color: BlendOp::Add { - src: Factor::SrcAlpha, - dst: Factor::OneMinusSrcAlpha, - }, - alpha: BlendOp::Add { - src: Factor::SrcAlpha, - dst: Factor::OneMinusSrcAlpha, - }, - }), - }], - }) - .primitive_assembler(VertexPrimitiveAssemblerSpec::with_buffers( - InputAssemblerDesc::new(Primitive::TriangleList), - vec![VertexBufferSpec { - attributes: vec![Format::Rgb32Sfloat, Format::R32Sint, Format::Rg32Sfloat], - rate: VertexInputRate::Vertex, - }], - )) - .shader_vertex(ShaderDesc { - source: include_str!("./data/3d.vert").to_string(), - entry: "main".to_string(), - kind: ShaderKind::Vertex, - }) - .shader_fragment(ShaderDesc { - source: include_str!("./data/3d.frag").to_string(), - entry: "main".to_string(), - kind: ShaderKind::Fragment, - }) - .push_constants(vec![(ShaderStageFlags::VERTEX, 0..64)]) - .renderpass(RenderpassSpec { - colors: vec![AttachmentSpec { - attachment: Attachment { - format: Some(context.properties().color_format), - samples: 1, - ops: P::attachment_ops(), - stencil_ops: P::attachment_ops(), - layouts: P::layout_as_range(), - }, - - used_layout: Layout::ColorAttachmentOptimal, - }], - depth: Some(AttachmentSpec { - attachment: Attachment { - format: Some(context.properties().depth_format), - samples: 1, - ops: AttachmentOps::new(AttachmentLoadOp::Clear, AttachmentStoreOp::DontCare), - stencil_ops: AttachmentOps::new( - AttachmentLoadOp::DontCare, - AttachmentStoreOp::DontCare, - ), - layouts: Layout::Undefined..Layout::DepthStencilAttachmentOptimal, - }, - used_layout: Layout::DepthStencilAttachmentOptimal, - }), - inputs: vec![], - resolves: vec![], - preserves: vec![], - }) - .build() - .context("Error building pipeline")?) -} - -fn create_depth_buffers( - context: &mut RenderingContext, -) -> Result<TargetSpecificResources<BoundImageView<DepthBufferPool>>> { - let db_spec = ImageSpec { - width: context.properties().extent.width, - height: context.properties().extent.height, - format: context.properties().depth_format, - usage: Usage::DEPTH_STENCIL_ATTACHMENT, - resources: DEPTH_RESOURCES, - }; - let img_count = context.properties().image_count; - - TargetSpecificResources::new( - || BoundImageView::from_context(context, &db_spec).context("Error creating depth buffer"), - img_count as usize, - ) -} diff --git a/stockton-render/src/ui.rs b/stockton-render/src/ui.rs index 4149d71..91e1b4b 100644 --- a/stockton-render/src/ui.rs +++ b/stockton-render/src/ui.rs @@ -4,8 +4,8 @@ use crate::window::UiState; use stockton_skeleton::{ buffers::draw::DrawBuffers, builders::{ - AttachmentSpec, CompletePipeline, PipelineSpec, PipelineSpecBuilder, RenderpassSpec, - ShaderDesc, VertexBufferSpec, VertexPrimitiveAssemblerSpec, + AttachmentSpec, CompletePipeline, PipelineSpecBuilder, RenderpassSpec, ShaderDesc, + VertexBufferSpec, VertexPrimitiveAssemblerSpec, }, context::RenderingContext, draw_passes::{util::TargetSpecificResources, DrawPass, IntoDrawPass, PassPosition}, @@ -47,11 +47,10 @@ pub struct UiPoint(pub Vector2, pub Vector2, pub [f32; 4]); /// Draw a Ui object pub struct UiDrawPass<'a> { - pipeline: CompletePipeline, repo: TextureRepo<TexturesPool, StagingPool>, draw_buffers: DrawBuffers<'a, UiPoint, DataPool, StagingPool>, - framebuffers: TargetSpecificResources<FramebufferT>, + surface_resources: SurfaceDependentResources, } impl<'a, P: PassPosition> DrawPass<P> for UiDrawPass<'a> { @@ -76,12 +75,12 @@ impl<'a, P: PassPosition> DrawPass<P> for UiDrawPass<'a> { let ui: &mut UiState = &mut session.resources.get_mut::<UiState>().unwrap(); // Get framebuffer and depth buffer - let fb = self.framebuffers.get_next(); + let fb = self.surface_resources.framebuffers.get_next(); unsafe { cmd_buffer.begin_render_pass( - &self.pipeline.renderpass, + &self.surface_resources.pipeline.renderpass, fb, - self.pipeline.render_area, + self.surface_resources.pipeline.render_area, vec![RenderAttachmentInfo { image_view: img_view, clear_value: ClearValue { @@ -93,7 +92,7 @@ impl<'a, P: PassPosition> DrawPass<P> for UiDrawPass<'a> { .into_iter(), SubpassContents::Inline, ); - cmd_buffer.bind_graphics_pipeline(&self.pipeline.pipeline); + cmd_buffer.bind_graphics_pipeline(&self.surface_resources.pipeline.pipeline); // Bind buffers cmd_buffer.bind_vertex_buffers( @@ -153,7 +152,7 @@ impl<'a, P: PassPosition> DrawPass<P> for UiDrawPass<'a> { if let Some(ds) = self.repo.attempt_get_descriptor_set(0) { unsafe { cmd_buffer.push_graphics_constants( - &self.pipeline.pipeline_layout, + &self.surface_resources.pipeline.pipeline_layout, ShaderStageFlags::VERTEX, 0, &[screen.x.to_bits(), screen.y.to_bits()], @@ -169,7 +168,7 @@ impl<'a, P: PassPosition> DrawPass<P> for UiDrawPass<'a> { }]), ); cmd_buffer.bind_graphics_descriptor_sets( - &self.pipeline.pipeline_layout, + &self.surface_resources.pipeline.pipeline_layout, 0, IntoIter::new([ds]), empty(), @@ -198,14 +197,7 @@ impl<'a, P: PassPosition> DrawPass<P> for UiDrawPass<'a> { fn deactivate(self, context: &mut RenderingContext) -> Result<()> { self.draw_buffers.deactivate(context); - - unsafe { - let mut device = context.lock_device()?; - self.pipeline.deactivate(&mut device); - for fb in self.framebuffers.dissolve() { - device.destroy_framebuffer(fb); - } - } + self.surface_resources.deactivate(context)?; self.repo.deactivate(context); Ok(()) @@ -216,36 +208,23 @@ impl<'a, P: PassPosition> DrawPass<P> for UiDrawPass<'a> { _session: &Session, context: &mut RenderingContext, ) -> Result<Self> { - { - let mut device = context.lock_device()?; - - // Recreate pipeline - self.pipeline.deactivate(&mut device); - self.pipeline = create_pipeline_spec::<P>(context)? - .build( - &mut device, - context.properties().extent, - once(&*self.repo.get_ds_layout()?), - ) - .context("Error building pipeline")?; - - // Recreate framebuffers - for fb in self.framebuffers.dissolve() { - unsafe { - device.destroy_framebuffer(fb); - } + let new_surface_resources = + SurfaceDependentResources::new::<P>(context, &*self.repo.get_ds_layout()?)?; + let old_surface_resources = self.surface_resources; + self.surface_resources = new_surface_resources; + + match old_surface_resources.deactivate(context) { + Ok(_) => Ok(self), + Err(e) => { + <Self as DrawPass<P>>::deactivate(self, context)?; + Err(e) } - self.framebuffers = create_framebuffers(&mut device, context, &self.pipeline)?; } - - Ok(self) } } impl<'a, P: PassPosition> IntoDrawPass<UiDrawPass<'a>, P> for () { fn init(self, session: &mut Session, context: &mut RenderingContext) -> Result<UiDrawPass<'a>> { - let spec = create_pipeline_spec::<P>(context)?; - let ui: &mut UiState = &mut session.resources.get_mut::<UiState>().unwrap(); let repo = TextureRepo::new::<_, TexLoadQueue>( context, @@ -260,26 +239,13 @@ impl<'a, P: PassPosition> IntoDrawPass<UiDrawPass<'a>, P> for () { let draw_buffers = DrawBuffers::from_context(context).context("Error creating draw buffers")?; - let (pipeline, framebuffers) = { - let mut device = context.lock_device()?; - - let pipeline = spec - .build( - &mut device, - context.properties().extent, - once(&*repo.get_ds_layout()?), - ) - .context("Error building pipeline")?; - - let framebuffers = create_framebuffers(&mut device, context, &pipeline)?; - (pipeline, framebuffers) - }; + let surface_resources = + SurfaceDependentResources::new::<P>(context, &*repo.get_ds_layout()?)?; Ok(UiDrawPass { - pipeline, repo, draw_buffers, - framebuffers, + surface_resources, }) } @@ -293,96 +259,6 @@ impl<'a, P: PassPosition> IntoDrawPass<UiDrawPass<'a>, P> for () { } } -fn create_framebuffers( - device: &mut DeviceT, - context: &RenderingContext, - pipeline: &CompletePipeline, -) -> Result<TargetSpecificResources<FramebufferT>> { - let fat = context.properties().swapchain_framebuffer_attachment(); - - TargetSpecificResources::new( - || unsafe { - Ok(device.create_framebuffer( - &pipeline.renderpass, - IntoIter::new([fat.clone()]), - context.properties().extent, - )?) - }, - context.properties().image_count as usize, - ) -} - -fn create_pipeline_spec<P: PassPosition>(context: &RenderingContext) -> Result<PipelineSpec> { - PipelineSpecBuilder::default() - .rasterizer(Rasterizer { - polygon_mode: PolygonMode::Fill, - cull_face: Face::NONE, - front_face: FrontFace::CounterClockwise, - depth_clamping: false, - depth_bias: None, - conservative: true, - line_width: State::Static(1.0), - }) - .depth_stencil(DepthStencilDesc { - depth: None, - depth_bounds: false, - stencil: None, - }) - .blender(BlendDesc { - logic_op: Some(LogicOp::Copy), - targets: vec![ColorBlendDesc { - mask: ColorMask::ALL, - blend: Some(BlendState { - color: BlendOp::Add { - src: Factor::SrcAlpha, - dst: Factor::OneMinusSrcAlpha, - }, - alpha: BlendOp::Add { - src: Factor::SrcAlpha, - dst: Factor::OneMinusSrcAlpha, - }, - }), - }], - }) - .primitive_assembler(VertexPrimitiveAssemblerSpec::with_buffers( - InputAssemblerDesc::new(Primitive::TriangleList), - vec![VertexBufferSpec { - attributes: vec![Format::Rg32Sfloat, Format::Rg32Sfloat, Format::Rgba32Sfloat], - rate: VertexInputRate::Vertex, - }], - )) - .shader_vertex(ShaderDesc { - source: include_str!("./data/ui.vert").to_string(), - entry: "main".to_string(), - kind: ShaderKind::Vertex, - }) - .shader_fragment(ShaderDesc { - source: include_str!("./data/ui.frag").to_string(), - entry: "main".to_string(), - kind: ShaderKind::Fragment, - }) - .push_constants(vec![(ShaderStageFlags::VERTEX, 0..8)]) - .renderpass(RenderpassSpec { - colors: vec![AttachmentSpec { - attachment: Attachment { - format: Some(context.properties().color_format), - samples: 1, - ops: P::attachment_ops(), - stencil_ops: P::attachment_ops(), - layouts: P::layout_as_range(), - }, - used_layout: Layout::ColorAttachmentOptimal, - }], - depth: None, - inputs: vec![], - resolves: vec![], - preserves: vec![], - }) - .dynamic_scissor(true) - .build() - .context("Error building pipeline") -} - pub struct UiTexture(Arc<Texture>); pub struct UiTextures { @@ -425,3 +301,121 @@ impl LoadableImage for UiTexture { } } } + +struct SurfaceDependentResources { + pipeline: CompletePipeline, + framebuffers: TargetSpecificResources<FramebufferT>, +} + +impl SurfaceDependentResources { + fn new<P: PassPosition>( + context: &mut RenderingContext, + ds_layout: &DescriptorSetLayoutT, + ) -> Result<Self> { + let mut device = context.lock_device()?; + + let spec = PipelineSpecBuilder::default() + .rasterizer(Rasterizer { + polygon_mode: PolygonMode::Fill, + cull_face: Face::NONE, + front_face: FrontFace::CounterClockwise, + depth_clamping: false, + depth_bias: None, + conservative: true, + line_width: State::Static(1.0), + }) + .depth_stencil(DepthStencilDesc { + depth: None, + depth_bounds: false, + stencil: None, + }) + .blender(BlendDesc { + logic_op: Some(LogicOp::Copy), + targets: vec![ColorBlendDesc { + mask: ColorMask::ALL, + blend: Some(BlendState { + color: BlendOp::Add { + src: Factor::SrcAlpha, + dst: Factor::OneMinusSrcAlpha, + }, + alpha: BlendOp::Add { + src: Factor::SrcAlpha, + dst: Factor::OneMinusSrcAlpha, + }, + }), + }], + }) + .primitive_assembler(VertexPrimitiveAssemblerSpec::with_buffers( + InputAssemblerDesc::new(Primitive::TriangleList), + vec![VertexBufferSpec { + attributes: vec![Format::Rg32Sfloat, Format::Rg32Sfloat, Format::Rgba32Sfloat], + rate: VertexInputRate::Vertex, + }], + )) + .shader_vertex(ShaderDesc { + source: include_str!("./data/ui.vert").to_string(), + entry: "main".to_string(), + kind: ShaderKind::Vertex, + }) + .shader_fragment(ShaderDesc { + source: include_str!("./data/ui.frag").to_string(), + entry: "main".to_string(), + kind: ShaderKind::Fragment, + }) + .push_constants(vec![(ShaderStageFlags::VERTEX, 0..8)]) + .renderpass(RenderpassSpec { + colors: vec![AttachmentSpec { + attachment: Attachment { + format: Some(context.properties().color_format), + samples: 1, + ops: P::attachment_ops(), + stencil_ops: P::attachment_ops(), + layouts: P::layout_as_range(), + }, + used_layout: Layout::ColorAttachmentOptimal, + }], + depth: None, + inputs: vec![], + resolves: vec![], + preserves: vec![], + }) + .dynamic_scissor(true) + .build() + .context("Error building pipeline")?; + + let pipeline = spec + .build(&mut device, context.properties().extent, once(ds_layout)) + .context("Error building pipeline")?; + + let fat = context.properties().swapchain_framebuffer_attachment(); + + let framebuffers = TargetSpecificResources::new( + || unsafe { + Ok(device.create_framebuffer( + &pipeline.renderpass, + IntoIter::new([fat.clone()]), + context.properties().extent, + )?) + }, + context.properties().image_count as usize, + )?; + + Ok(Self { + framebuffers, + pipeline, + }) + } + + fn deactivate(self, context: &mut RenderingContext) -> Result<()> { + unsafe { + let mut device = context.lock_device()?; + self.pipeline.deactivate(&mut device); + + for fb in self.framebuffers.dissolve() { + device.destroy_framebuffer(fb); + } + } + + Ok(()) + } +} |