aboutsummaryrefslogtreecommitdiff
path: root/stockton-render
diff options
context:
space:
mode:
authortcmal <me@aria.rip>2024-08-25 17:44:22 +0100
committertcmal <me@aria.rip>2024-08-25 17:44:22 +0100
commit82ba63bc9fb8873d3e5612d34770c957aaca51a7 (patch)
tree85ac63f99f04b8a2e252446357c6eea964c38b7a /stockton-render
parent38c66803774854cfa8c7f4539480e9e5039ab6de (diff)
refactor(draw): take pipeline out as its own struct
Diffstat (limited to 'stockton-render')
-rw-r--r--stockton-render/src/draw/context.rs356
-rw-r--r--stockton-render/src/draw/mod.rs1
-rw-r--r--stockton-render/src/draw/pipeline.rs336
-rw-r--r--stockton-render/src/draw/target.rs24
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,