diff options
author | tcmal <me@aria.rip> | 2024-08-25 17:44:22 +0100 |
---|---|---|
committer | tcmal <me@aria.rip> | 2024-08-25 17:44:22 +0100 |
commit | 82ba63bc9fb8873d3e5612d34770c957aaca51a7 (patch) | |
tree | 85ac63f99f04b8a2e252446357c6eea964c38b7a /stockton-render | |
parent | 38c66803774854cfa8c7f4539480e9e5039ab6de (diff) |
refactor(draw): take pipeline out as its own struct
Diffstat (limited to 'stockton-render')
-rw-r--r-- | stockton-render/src/draw/context.rs | 356 | ||||
-rw-r--r-- | stockton-render/src/draw/mod.rs | 1 | ||||
-rw-r--r-- | stockton-render/src/draw/pipeline.rs | 336 | ||||
-rw-r--r-- | stockton-render/src/draw/target.rs | 24 |
4 files changed, 366 insertions, 351 deletions
diff --git a/stockton-render/src/draw/context.rs b/stockton-render/src/draw/context.rs index b569ced..b17bbe9 100644 --- a/stockton-render/src/draw/context.rs +++ b/stockton-render/src/draw/context.rs @@ -19,12 +19,7 @@ //! In the end, this takes in a depth-sorted list of faces and a map file and renders them. //! You'll need something else to actually find/sort the faces though. -use std::{ - borrow::Borrow, - convert::TryInto, - mem::{size_of, ManuallyDrop}, - ops::Deref, -}; +use std::{convert::TryInto, mem::ManuallyDrop, ops::Deref}; use arrayvec::ArrayVec; use hal::{pool::CommandPoolCreateFlags, prelude::*}; @@ -39,20 +34,12 @@ use stockton_types::{Vector2, Vector3}; use super::{ buffer::ModifiableBuffer, draw_buffers::{DrawBuffers, INITIAL_INDEX_SIZE, INITIAL_VERT_SIZE}, + pipeline::CompletePipeline, target::{SwapchainProperties, TargetChain}, texture::TextureStore, }; use crate::{error, types::*}; -/// Entry point name for shaders -const ENTRY_NAME: &str = "main"; - -/// Source for vertex shader. TODO -const VERTEX_SOURCE: &str = include_str!("./data/stockton.vert"); - -/// Source for fragment shader. TODO -const FRAGMENT_SOURCE: &str = include_str!("./data/stockton.frag"); - /// Represents a point of a triangle, including UV and texture information. #[derive(Debug, Clone, Copy)] pub struct UVPoint(pub Vector3, pub i32, pub Vector2); @@ -78,15 +65,8 @@ pub struct RenderingContext<'a> { /// Swapchain and stuff pub(crate) target_chain: ManuallyDrop<TargetChain>, - // Pipeline - /// Our main render pass - renderpass: ManuallyDrop<RenderPass>, - - /// The layout of our main graphics pipeline - pipeline_layout: ManuallyDrop<PipelineLayout>, - - /// Our main graphics pipeline - pipeline: ManuallyDrop<GraphicsPipeline>, + /// Graphics pipeline and associated objects + pipeline: ManuallyDrop<CompletePipeline>, // Command pool and buffers /// The command pool used for our buffers @@ -103,12 +83,6 @@ pub struct RenderingContext<'a> { /// View projection matrix pub(crate) vp_matrix: Mat4, - - /// The vertex shader module - vs_module: ManuallyDrop<ShaderModule>, - - /// The fragment shader module - fs_module: ManuallyDrop<ShaderModule>, } impl<'a> RenderingContext<'a> { @@ -166,86 +140,6 @@ impl<'a> RenderingContext<'a> { } .map_err(|_| error::CreationError::OutOfMemoryError)?; - // Renderpass - let renderpass = { - use hal::{ - image::{Access, Layout}, - memory::Dependencies, - pass::*, - pso::PipelineStage, - }; - - let img_attachment = Attachment { - format: Some(swapchain_properties.format), - samples: 1, - ops: AttachmentOps::new(AttachmentLoadOp::Clear, AttachmentStoreOp::Store), - stencil_ops: AttachmentOps::new( - AttachmentLoadOp::Clear, - AttachmentStoreOp::DontCare, - ), - layouts: Layout::Undefined..Layout::Present, - }; - - let depth_attachment = Attachment { - format: Some(swapchain_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, - }; - - let subpass = SubpassDesc { - colors: &[(0, Layout::ColorAttachmentOptimal)], - depth_stencil: Some(&(1, Layout::DepthStencilAttachmentOptimal)), - inputs: &[], - resolves: &[], - preserves: &[], - }; - - let in_dependency = SubpassDependency { - flags: Dependencies::empty(), - passes: None..Some(0), - stages: PipelineStage::COLOR_ATTACHMENT_OUTPUT - ..(PipelineStage::COLOR_ATTACHMENT_OUTPUT - | PipelineStage::EARLY_FRAGMENT_TESTS), - accesses: Access::empty() - ..(Access::COLOR_ATTACHMENT_READ - | Access::COLOR_ATTACHMENT_WRITE - | Access::DEPTH_STENCIL_ATTACHMENT_READ - | Access::DEPTH_STENCIL_ATTACHMENT_WRITE), - }; - - let out_dependency = SubpassDependency { - flags: Dependencies::empty(), - passes: Some(0)..None, - stages: PipelineStage::COLOR_ATTACHMENT_OUTPUT | PipelineStage::EARLY_FRAGMENT_TESTS - ..PipelineStage::COLOR_ATTACHMENT_OUTPUT, - accesses: (Access::COLOR_ATTACHMENT_READ - | Access::COLOR_ATTACHMENT_WRITE - | Access::DEPTH_STENCIL_ATTACHMENT_READ - | Access::DEPTH_STENCIL_ATTACHMENT_WRITE) - ..Access::empty(), - }; - - unsafe { - device.create_render_pass( - &[img_attachment, depth_attachment], - &[subpass], - &[in_dependency, out_dependency], - ) - } - .map_err(|_| error::CreationError::OutOfMemoryError)? - }; - - // Subpass - let subpass = hal::pass::Subpass { - index: 0, - main_pass: &renderpass, - }; - // Vertex and index buffers let draw_buffers = DrawBuffers::new(&mut device, &adapter)?; @@ -262,10 +156,10 @@ impl<'a> RenderingContext<'a> { descriptor_set_layouts.push(texture_store.descriptor_set_layout.deref()); // Graphics pipeline - let (pipeline_layout, pipeline, vs_module, fs_module) = Self::create_pipeline( + let pipeline = CompletePipeline::new( &mut device, swapchain_properties.extent, - &subpass, + &swapchain_properties, descriptor_set_layouts, )?; @@ -274,7 +168,7 @@ impl<'a> RenderingContext<'a> { &mut device, &adapter, &mut surface, - &renderpass, + &pipeline, &mut cmd_pool, swapchain_properties, None, @@ -289,20 +183,15 @@ impl<'a> RenderingContext<'a> { adapter, queue_group, - renderpass: ManuallyDrop::new(renderpass), target_chain: ManuallyDrop::new(target_chain), cmd_pool: ManuallyDrop::new(cmd_pool), - pipeline_layout: ManuallyDrop::new(pipeline_layout), pipeline: ManuallyDrop::new(pipeline), texture_store: ManuallyDrop::new(texture_store), draw_buffers: ManuallyDrop::new(draw_buffers), - vs_module: ManuallyDrop::new(vs_module), - fs_module: ManuallyDrop::new(fs_module), - vp_matrix: Mat4::identity(), }) } @@ -319,39 +208,19 @@ impl<'a> RenderingContext<'a> { use core::ptr::read; // Graphics pipeline - self.device - .destroy_graphics_pipeline(ManuallyDrop::into_inner(read(&self.pipeline))); - - self.device - .destroy_pipeline_layout(ManuallyDrop::into_inner(read(&self.pipeline_layout))); - - self.device - .destroy_shader_module(ManuallyDrop::into_inner(read(&self.vs_module))); - self.device - .destroy_shader_module(ManuallyDrop::into_inner(read(&self.fs_module))); - - let (pipeline_layout, pipeline, vs_module, fs_module) = { + // TODO: Recycle + ManuallyDrop::into_inner(read(&self.pipeline)).deactivate(&mut self.device); + self.pipeline = ManuallyDrop::new({ let mut descriptor_set_layouts: ArrayVec<[_; 2]> = ArrayVec::new(); descriptor_set_layouts.push(self.texture_store.descriptor_set_layout.deref()); - let subpass = hal::pass::Subpass { - index: 0, - main_pass: &(*self.renderpass), - }; - - Self::create_pipeline( + CompletePipeline::new( &mut self.device, properties.extent, - &subpass, + &properties, descriptor_set_layouts, )? - }; - - self.pipeline_layout = ManuallyDrop::new(pipeline_layout); - self.pipeline = ManuallyDrop::new(pipeline); - - self.vs_module = ManuallyDrop::new(vs_module); - self.fs_module = ManuallyDrop::new(fs_module); + }); let old_swapchain = ManuallyDrop::into_inner(read(&self.target_chain)) .deactivate_with_recyling(&mut self.device, &mut self.cmd_pool); @@ -360,7 +229,7 @@ impl<'a> RenderingContext<'a> { &mut self.device, &self.adapter, &mut self.surface, - &self.renderpass, + &self.pipeline, &mut self.cmd_pool, properties, Some(old_swapchain), @@ -371,184 +240,6 @@ impl<'a> RenderingContext<'a> { Ok(()) } - #[allow(clippy::type_complexity)] - fn create_pipeline<T>( - device: &mut Device, - extent: hal::image::Extent, - subpass: &hal::pass::Subpass<back::Backend>, - set_layouts: T, - ) -> Result<(PipelineLayout, GraphicsPipeline, ShaderModule, ShaderModule), error::CreationError> - where - T: IntoIterator, - T::Item: Borrow<DescriptorSetLayout>, - { - use hal::format::Format; - use hal::pso::*; - - // Shader modules - let (vs_module, fs_module) = { - let mut compiler = shaderc::Compiler::new().ok_or(error::CreationError::NoShaderC)?; - - let vertex_compile_artifact = compiler - .compile_into_spirv( - VERTEX_SOURCE, - shaderc::ShaderKind::Vertex, - "vertex.vert", - ENTRY_NAME, - None, - ) - .map_err(error::CreationError::ShaderCError)?; - - let fragment_compile_artifact = compiler - .compile_into_spirv( - FRAGMENT_SOURCE, - shaderc::ShaderKind::Fragment, - "fragment.frag", - ENTRY_NAME, - None, - ) - .map_err(error::CreationError::ShaderCError)?; - - // Make into shader module - unsafe { - ( - device - .create_shader_module(vertex_compile_artifact.as_binary()) - .map_err(error::CreationError::ShaderModuleFailed)?, - device - .create_shader_module(fragment_compile_artifact.as_binary()) - .map_err(error::CreationError::ShaderModuleFailed)?, - ) - } - }; - - // Shader entry points (ShaderStage) - let (vs_entry, fs_entry) = ( - EntryPoint::<back::Backend> { - entry: ENTRY_NAME, - module: &vs_module, - specialization: Specialization::default(), - }, - EntryPoint::<back::Backend> { - entry: ENTRY_NAME, - module: &fs_module, - specialization: Specialization::default(), - }, - ); - - // Shader set - let shaders = GraphicsShaderSet { - vertex: vs_entry, - fragment: Some(fs_entry), - hull: None, - domain: None, - geometry: None, - }; - - // Vertex buffers - let vertex_buffers: Vec<VertexBufferDesc> = vec![VertexBufferDesc { - binding: 0, - stride: (size_of::<f32>() * 6) as u32, - rate: VertexInputRate::Vertex, - }]; - - let attributes: Vec<AttributeDesc> = pipeline_vb_attributes!(0, - size_of::<f32>() * 3; Rgb32Sfloat, - size_of::<u32>(); R32Sint, - size_of::<f32>() * 2; Rg32Sfloat - ); - - // Rasterizer - let rasterizer = Rasterizer { - polygon_mode: PolygonMode::Fill, - cull_face: Face::BACK, - front_face: FrontFace::CounterClockwise, - depth_clamping: false, - depth_bias: None, - conservative: true, - line_width: hal::pso::State::Static(1.0), - }; - - // Depth stencil - let depth_stencil = DepthStencilDesc { - depth: Some(DepthTest { - fun: Comparison::Less, - write: true, - }), - depth_bounds: false, - stencil: None, - }; - - // Pipeline layout - let layout = unsafe { - device.create_pipeline_layout( - set_layouts, - // vp matrix, 4x4 f32 - &[(ShaderStageFlags::VERTEX, 0..64)], - ) - } - .map_err(|_| error::CreationError::OutOfMemoryError)?; - - // Colour blending - let blender = { - let blend_state = BlendState { - color: BlendOp::Add { - src: Factor::One, - dst: Factor::Zero, - }, - alpha: BlendOp::Add { - src: Factor::One, - dst: Factor::Zero, - }, - }; - - BlendDesc { - logic_op: Some(LogicOp::Copy), - targets: vec![ColorBlendDesc { - mask: ColorMask::ALL, - blend: Some(blend_state), - }], - } - }; - - // Baked states - let baked_states = BakedStates { - viewport: Some(Viewport { - rect: extent.rect(), - depth: (0.0..1.0), - }), - scissor: Some(extent.rect()), - blend_color: None, - depth_bounds: None, - }; - - // Input assembler - let input_assembler = InputAssemblerDesc::new(Primitive::TriangleList); - - // Pipeline description - let pipeline_desc = GraphicsPipelineDesc { - shaders, - rasterizer, - vertex_buffers, - blender, - depth_stencil, - multisampling: None, - baked_states, - layout: &layout, - subpass: *subpass, - flags: PipelineCreationFlags::empty(), - parent: BasePipeline::None, - input_assembler, - attributes, - }; - - // Pipeline - let pipeline = unsafe { device.create_graphics_pipeline(&pipeline_desc, None) } - .map_err(error::CreationError::PipelineError)?; - - Ok((layout, pipeline, vs_module, fs_module)) - } - /// Draw all vertices in the buffer pub fn draw_vertices<M: MinBSPFeatures<VulkanSystem>>( &mut self, @@ -559,9 +250,7 @@ impl<'a> RenderingContext<'a> { let cmd_buffer = self.target_chain.prep_next_target( &mut self.device, &mut self.draw_buffers, - &self.renderpass, &self.pipeline, - &self.pipeline_layout, &self.vp_matrix, )?; @@ -579,7 +268,7 @@ impl<'a> RenderingContext<'a> { descriptor_sets.push(self.texture_store.get_chunk_descriptor_set(current_chunk)); unsafe { cmd_buffer.bind_graphics_descriptor_sets( - &self.pipeline_layout, + &self.pipeline.pipeline_layout, 0, descriptor_sets, &[], @@ -642,7 +331,7 @@ impl<'a> RenderingContext<'a> { descriptor_sets.push(self.texture_store.get_chunk_descriptor_set(current_chunk)); unsafe { cmd_buffer.bind_graphics_descriptor_sets( - &self.pipeline_layout, + &self.pipeline.pipeline_layout, 0, descriptor_sets, &[], @@ -690,19 +379,8 @@ impl<'a> core::ops::Drop for RenderingContext<'a> { self.device .destroy_command_pool(ManuallyDrop::into_inner(read(&self.cmd_pool))); - self.device - .destroy_render_pass(ManuallyDrop::into_inner(read(&self.renderpass))); - - self.device - .destroy_shader_module(ManuallyDrop::into_inner(read(&self.vs_module))); - self.device - .destroy_shader_module(ManuallyDrop::into_inner(read(&self.fs_module))); - - self.device - .destroy_graphics_pipeline(ManuallyDrop::into_inner(read(&self.pipeline))); - self.device - .destroy_pipeline_layout(ManuallyDrop::into_inner(read(&self.pipeline_layout))); + ManuallyDrop::into_inner(read(&self.pipeline)).deactivate(&mut self.device); self.instance .destroy_surface(ManuallyDrop::into_inner(read(&self.surface))); diff --git a/stockton-render/src/draw/mod.rs b/stockton-render/src/draw/mod.rs index 88381c5..482d62c 100644 --- a/stockton-render/src/draw/mod.rs +++ b/stockton-render/src/draw/mod.rs @@ -25,6 +25,7 @@ mod buffer; mod camera; mod context; mod draw_buffers; +mod pipeline; mod texture; pub use self::camera::calc_vp_matrix_system; diff --git a/stockton-render/src/draw/pipeline.rs b/stockton-render/src/draw/pipeline.rs new file mode 100644 index 0000000..8ad167d --- /dev/null +++ b/stockton-render/src/draw/pipeline.rs @@ -0,0 +1,336 @@ +/* + * Copyright (C) Oscar Shrimpton 2020 + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ +//! A complete graphics pipeline + +/// Entry point name for shaders +const ENTRY_NAME: &str = "main"; + +/// Source for vertex shader. TODO +const VERTEX_SOURCE: &str = include_str!("./data/stockton.vert"); + +/// Source for fragment shader. TODO +const FRAGMENT_SOURCE: &str = include_str!("./data/stockton.frag"); + +use std::{ + borrow::Borrow, + mem::{size_of, ManuallyDrop}, +}; + +use hal::prelude::*; + +use super::target::SwapchainProperties; +use crate::error; +use crate::types::*; + +// TODO: Generalise so we can use for UI also +/// A complete graphics pipeline and associated resources +pub struct CompletePipeline { + /// Our main render pass + pub(crate) renderpass: ManuallyDrop<RenderPass>, + + /// The layout of our main graphics pipeline + pub(crate) pipeline_layout: ManuallyDrop<PipelineLayout>, + + /// Our main graphics pipeline + pub(crate) pipeline: ManuallyDrop<GraphicsPipeline>, + + /// The vertex shader module + pub(crate) vs_module: ManuallyDrop<ShaderModule>, + + /// The fragment shader module + pub(crate) fs_module: ManuallyDrop<ShaderModule>, +} + +impl CompletePipeline { + pub fn new<T>( + device: &mut Device, + extent: hal::image::Extent, + swapchain_properties: &SwapchainProperties, + set_layouts: T, + ) -> Result<Self, error::CreationError> + where + T: IntoIterator, + T::Item: Borrow<DescriptorSetLayout>, + { + use hal::format::Format; + use hal::pso::*; + + // Renderpass + let renderpass = { + use hal::{ + image::{Access, Layout}, + memory::Dependencies, + pass::*, + }; + + let img_attachment = Attachment { + format: Some(swapchain_properties.format), + samples: 1, + ops: AttachmentOps::new(AttachmentLoadOp::Clear, AttachmentStoreOp::Store), + stencil_ops: AttachmentOps::new( + AttachmentLoadOp::Clear, + AttachmentStoreOp::DontCare, + ), + layouts: Layout::Undefined..Layout::Present, + }; + + let depth_attachment = Attachment { + format: Some(swapchain_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, + }; + + let subpass = SubpassDesc { + colors: &[(0, Layout::ColorAttachmentOptimal)], + depth_stencil: Some(&(1, Layout::DepthStencilAttachmentOptimal)), + inputs: &[], + resolves: &[], + preserves: &[], + }; + + let in_dependency = SubpassDependency { + flags: Dependencies::empty(), + passes: None..Some(0), + stages: PipelineStage::COLOR_ATTACHMENT_OUTPUT + ..(PipelineStage::COLOR_ATTACHMENT_OUTPUT + | PipelineStage::EARLY_FRAGMENT_TESTS), + accesses: Access::empty() + ..(Access::COLOR_ATTACHMENT_READ + | Access::COLOR_ATTACHMENT_WRITE + | Access::DEPTH_STENCIL_ATTACHMENT_READ + | Access::DEPTH_STENCIL_ATTACHMENT_WRITE), + }; + + let out_dependency = SubpassDependency { + flags: Dependencies::empty(), + passes: Some(0)..None, + stages: PipelineStage::COLOR_ATTACHMENT_OUTPUT | PipelineStage::EARLY_FRAGMENT_TESTS + ..PipelineStage::COLOR_ATTACHMENT_OUTPUT, + accesses: (Access::COLOR_ATTACHMENT_READ + | Access::COLOR_ATTACHMENT_WRITE + | Access::DEPTH_STENCIL_ATTACHMENT_READ + | Access::DEPTH_STENCIL_ATTACHMENT_WRITE) + ..Access::empty(), + }; + + unsafe { + device.create_render_pass( + &[img_attachment, depth_attachment], + &[subpass], + &[in_dependency, out_dependency], + ) + } + .map_err(|_| error::CreationError::OutOfMemoryError)? + }; + + // Subpass + let subpass = hal::pass::Subpass { + index: 0, + main_pass: &renderpass, + }; + + // Shader modules + let (vs_module, fs_module) = { + let mut compiler = shaderc::Compiler::new().ok_or(error::CreationError::NoShaderC)?; + + let vertex_compile_artifact = compiler + .compile_into_spirv( + VERTEX_SOURCE, + shaderc::ShaderKind::Vertex, + "vertex.vert", + ENTRY_NAME, + None, + ) + .map_err(error::CreationError::ShaderCError)?; + + let fragment_compile_artifact = compiler + .compile_into_spirv( + FRAGMENT_SOURCE, + shaderc::ShaderKind::Fragment, + "fragment.frag", + ENTRY_NAME, + None, + ) + .map_err(error::CreationError::ShaderCError)?; + + // Make into shader module + unsafe { + ( + device + .create_shader_module(vertex_compile_artifact.as_binary()) + .map_err(error::CreationError::ShaderModuleFailed)?, + device + .create_shader_module(fragment_compile_artifact.as_binary()) + .map_err(error::CreationError::ShaderModuleFailed)?, + ) + } + }; + + // Shader entry points (ShaderStage) + let (vs_entry, fs_entry) = ( + EntryPoint::<back::Backend> { + entry: ENTRY_NAME, + module: &vs_module, + specialization: Specialization::default(), + }, + EntryPoint::<back::Backend> { + entry: ENTRY_NAME, + module: &fs_module, + specialization: Specialization::default(), + }, + ); + + // Shader set + let shaders = GraphicsShaderSet { + vertex: vs_entry, + fragment: Some(fs_entry), + hull: None, + domain: None, + geometry: None, + }; + + // Vertex buffers + let vertex_buffers: Vec<VertexBufferDesc> = vec![VertexBufferDesc { + binding: 0, + stride: (size_of::<f32>() * 6) as u32, + rate: VertexInputRate::Vertex, + }]; + + let attributes: Vec<AttributeDesc> = pipeline_vb_attributes!(0, + size_of::<f32>() * 3; Rgb32Sfloat, + size_of::<u32>(); R32Sint, + size_of::<f32>() * 2; Rg32Sfloat + ); + + // Rasterizer + let rasterizer = Rasterizer { + polygon_mode: PolygonMode::Fill, + cull_face: Face::BACK, + front_face: FrontFace::CounterClockwise, + depth_clamping: false, + depth_bias: None, + conservative: true, + line_width: hal::pso::State::Static(1.0), + }; + + // Depth stencil + let depth_stencil = DepthStencilDesc { + depth: Some(DepthTest { + fun: Comparison::Less, + write: true, + }), + depth_bounds: false, + stencil: None, + }; + + // Pipeline layout + let layout = unsafe { + device.create_pipeline_layout( + set_layouts, + // vp matrix, 4x4 f32 + &[(ShaderStageFlags::VERTEX, 0..64)], + ) + } + .map_err(|_| error::CreationError::OutOfMemoryError)?; + + // Colour blending + let blender = { + let blend_state = BlendState { + color: BlendOp::Add { + src: Factor::One, + dst: Factor::Zero, + }, + alpha: BlendOp::Add { + src: Factor::One, + dst: Factor::Zero, + }, + }; + + BlendDesc { + logic_op: Some(LogicOp::Copy), + targets: vec![ColorBlendDesc { + mask: ColorMask::ALL, + blend: Some(blend_state), + }], + } + }; + + // Baked states + let baked_states = BakedStates { + viewport: Some(Viewport { + rect: extent.rect(), + depth: (0.0..1.0), + }), + scissor: Some(extent.rect()), + blend_color: None, + depth_bounds: None, + }; + + // Input assembler + let input_assembler = InputAssemblerDesc::new(Primitive::TriangleList); + + // Pipeline description + let pipeline_desc = GraphicsPipelineDesc { + shaders, + rasterizer, + vertex_buffers, + blender, + depth_stencil, + multisampling: None, + baked_states, + layout: &layout, + subpass, + flags: PipelineCreationFlags::empty(), + parent: BasePipeline::None, + input_assembler, + attributes, + }; + + // Pipeline + let pipeline = unsafe { device.create_graphics_pipeline(&pipeline_desc, None) } + .map_err(error::CreationError::PipelineError)?; + + Ok(CompletePipeline { + renderpass: ManuallyDrop::new(renderpass), + pipeline_layout: ManuallyDrop::new(layout), + pipeline: ManuallyDrop::new(pipeline), + vs_module: ManuallyDrop::new(vs_module), + fs_module: ManuallyDrop::new(fs_module), + }) + } + + /// Deactivate vulkan resources. Use before dropping + pub fn deactivate(self, device: &mut Device) { + unsafe { + use core::ptr::read; + + device.destroy_render_pass(ManuallyDrop::into_inner(read(&self.renderpass))); + + device.destroy_shader_module(ManuallyDrop::into_inner(read(&self.vs_module))); + device.destroy_shader_module(ManuallyDrop::into_inner(read(&self.fs_module))); + + device.destroy_graphics_pipeline(ManuallyDrop::into_inner(read(&self.pipeline))); + + device.destroy_pipeline_layout(ManuallyDrop::into_inner(read(&self.pipeline_layout))); + } + } +} diff --git a/stockton-render/src/draw/target.rs b/stockton-render/src/draw/target.rs index 19f41dc..05efc59 100644 --- a/stockton-render/src/draw/target.rs +++ b/stockton-render/src/draw/target.rs @@ -16,13 +16,9 @@ */ //! Resources needed for drawing on the screen, including sync objects -use super::texture::image::LoadedImage; -use crate::types::*; use core::{iter::once, mem::ManuallyDrop}; -use crate::draw::buffer::ModifiableBuffer; -use crate::draw::draw_buffers::DrawBuffers; use arrayvec::ArrayVec; use hal::{ format::{ChannelType, Format, Swizzle}, @@ -34,6 +30,12 @@ use hal::{ }; use na::Mat4; +use super::{ + buffer::ModifiableBuffer, draw_buffers::DrawBuffers, pipeline::CompletePipeline, + texture::image::LoadedImage, +}; +use crate::types::*; + /// Defines the colour range we use. const COLOR_RANGE: hal::image::SubresourceRange = hal::image::SubresourceRange { aspects: hal::format::Aspects::COLOR, @@ -149,7 +151,7 @@ impl TargetChain { device: &mut Device, adapter: &Adapter, surface: &mut Surface, - renderpass: &RenderPass, + pipeline: &CompletePipeline, cmd_pool: &mut CommandPool, properties: SwapchainProperties, old_swapchain: Option<Swapchain>, @@ -210,7 +212,7 @@ impl TargetChain { TargetResources::new( device, cmd_pool, - renderpass, + &pipeline.renderpass, image, &(*depth_buffer.image_view), properties.extent, @@ -264,9 +266,7 @@ impl TargetChain { &'a mut self, device: &mut Device, draw_buffers: &mut DrawBuffers, - renderpass: &RenderPass, - pipeline: &GraphicsPipeline, - pipeline_layout: &PipelineLayout, + pipeline: &CompletePipeline, vp: &Mat4, ) -> Result<&'a mut crate::types::CommandBuffer, &'static str> { self.last_drawn = (self.last_drawn + 1) % self.targets.len(); @@ -329,19 +329,19 @@ impl TargetChain { target.cmd_buffer.begin_primary(CommandBufferFlags::EMPTY); // Main render pass / pipeline target.cmd_buffer.begin_render_pass( - renderpass, + &pipeline.renderpass, &target.framebuffer, self.properties.viewport.rect, clear_values.iter(), SubpassContents::Inline, ); - target.cmd_buffer.bind_graphics_pipeline(&pipeline); + target.cmd_buffer.bind_graphics_pipeline(&pipeline.pipeline); // VP Matrix let vp = &*(vp.data.as_slice() as *const [f32] as *const [u32]); target.cmd_buffer.push_graphics_constants( - &pipeline_layout, + &pipeline.pipeline_layout, ShaderStageFlags::VERTEX, 0, vp, |