diff --git a/engine/BUILD b/engine/BUILD index cae8873..77cb81c 100644 --- a/engine/BUILD +++ b/engine/BUILD @@ -16,6 +16,7 @@ rust_binary( "src/render/vulkan/data.rs", "src/render/vulkan/mod.rs", "src/render/vulkan/pipeline.rs", + "src/render/vulkan/pipeline_forward.rs", "src/render/vulkan/qfi.rs", "src/render/vulkan/shaders.rs", "src/render/vulkan/surface_binding.rs", diff --git a/engine/src/render/vulkan/mod.rs b/engine/src/render/vulkan/mod.rs index c755a09..44d908d 100644 --- a/engine/src/render/vulkan/mod.rs +++ b/engine/src/render/vulkan/mod.rs @@ -13,6 +13,7 @@ use vulkano::sync::{FenceSignalFuture, GpuFuture}; pub mod data; mod surface_binding; mod pipeline; +mod pipeline_forward; mod qfi; mod shaders; mod swapchain_binding; @@ -136,7 +137,7 @@ impl Instance { let render_pass = self.swapchain_binding().render_pass.clone(); - self.pipeline = Some(Box::new(pipeline::Forward::new(device.clone(), chain.dimensions(), render_pass))); + self.pipeline = Some(Box::new(pipeline_forward::Forward::new(device.clone(), chain.dimensions(), render_pass))); self.uniform_pool = Some( vb::CpuBufferPool::new(device.clone(), vb::BufferUsage::uniform_buffer_transfer_destination()) ); diff --git a/engine/src/render/vulkan/pipeline.rs b/engine/src/render/vulkan/pipeline.rs index 789245e..d957d6c 100644 --- a/engine/src/render/vulkan/pipeline.rs +++ b/engine/src/render/vulkan/pipeline.rs @@ -1,177 +1,15 @@ -use std::borrow::Cow; use std::sync::Arc; -use vulkano::descriptor::descriptor as vdD; -use vulkano::descriptor::descriptor_set as vdd; -use vulkano::descriptor::pipeline_layout as vdp; -use vulkano::device as vd; use vulkano::format::Format; -use vulkano::framebuffer as vf; use vulkano::pipeline as vp; -use vulkano::pipeline::shader as vps; -use vulkano::pipeline::vertex as vpv; -use vulkano::sampler as vs; +use vulkano::descriptor::descriptor_set as vdd; use vulkano::image as vm; -use crate::render::vulkan::data; -use crate::render::vulkan::shaders; - pub type VulkanoPipeline = dyn vp::GraphicsPipelineAbstract + Send + Sync; -type VulkanoDescriptorSet = dyn vdd::DescriptorSet + Send + Sync; +pub type VulkanoDescriptorSet = dyn vdd::DescriptorSet + Send + Sync; pub trait Pipeline { fn get_pipeline(&self) -> Arc; fn make_descriptor_set(&mut self, texture_image: Arc>) -> Arc; } -pub struct Forward { - pipeline: Arc, - descriptor_set_pool: vdd::FixedSizeDescriptorSetsPool, - device: Arc, -} - -impl Forward { - pub fn new( - device: Arc, - viewport_dimensions: [u32; 2], - render_pass: Arc, - ) -> Forward { - let vertex_shader = shaders::ShaderDefinition { - name: "engine/shaders/forward_vert.spv".to_string(), - ty: vps::GraphicsShaderType::Vertex, - inputs: vec![ - vps::ShaderInterfaceDefEntry { - location: 0..1, format: Format::R32G32B32Sfloat, - name: Some(Cow::Borrowed("pos")), - }, - vps::ShaderInterfaceDefEntry { - location: 1..2, format: Format::R32G32B32Sfloat, - name: Some(Cow::Borrowed("color")), - }, - vps::ShaderInterfaceDefEntry { - location: 2..6, format: Format::R32G32B32A32Sfloat, - name: Some(Cow::Borrowed("model")), - }, - vps::ShaderInterfaceDefEntry { - location: 6..7, format: Format::R32G32Sfloat, - name: Some(Cow::Borrowed("tex")), - }, - ], - outputs: vec![ - vps::ShaderInterfaceDefEntry { - location: 0..1, format: Format::R32G32B32Sfloat, - name: Some(Cow::Borrowed("fragColor")), - }, - vps::ShaderInterfaceDefEntry { - location: 1..2, format: Format::R32G32Sfloat, - name: Some(Cow::Borrowed("fragTexCoord")), - }, - ], - uniforms: vec![], - push_constants: vec![ - vdp::PipelineLayoutDescPcRange { - offset: 0, - size: 64usize, - stages: vdD::ShaderStages { - vertex: true, - ..vdD::ShaderStages::none() - }, - }, - ], - }.load_into(device.clone()).expect("could not load vertex shader"); - - let fragment_shader = shaders::ShaderDefinition { - name: "engine/shaders/forward_frag.spv".to_string(), - ty: vps::GraphicsShaderType::Fragment, - inputs: vec![ - vps::ShaderInterfaceDefEntry { - location: 0..1, format: Format::R32G32B32Sfloat, - name: Some(Cow::Borrowed("fragColor")), - }, - vps::ShaderInterfaceDefEntry { - location: 1..2, format: Format::R32G32Sfloat, - name: Some(Cow::Borrowed("fragTexCoord")), - }, - ], - outputs: vec![ - vps::ShaderInterfaceDefEntry { - location: 0..1, format: Format::R32G32B32A32Sfloat, - name: Some(Cow::Borrowed("outColor")), - } - ], - uniforms: vec![ - vdD::DescriptorDesc { - ty: vdD::DescriptorDescTy::CombinedImageSampler(vdD::DescriptorImageDesc { - sampled: true, - dimensions: vdD::DescriptorImageDescDimensions::TwoDimensional, - format: None, - multisampled: false, - array_layers: vdD::DescriptorImageDescArray::NonArrayed, - }), - array_count: 1, - readonly: true, - stages: vdD::ShaderStages { - fragment: true, - ..vdD::ShaderStages::none() - }, - }, - ], - push_constants: vec![], - }.load_into(device.clone()).expect("could not load fragment shader"); - - let dimensions = [viewport_dimensions[0] as f32, viewport_dimensions[1] as f32]; - let viewport = vp::viewport::Viewport { - origin: [0.0, 0.0], - dimensions, - depth_range: 0.0 .. 1.0, - }; - - // Counter-clockwise facing triangles - this is because geometry data is left-handed, and - // the vertex shader performs a handedness flip by doing .y *= -1 on emitted vertices. To - // keep geomtry-space triangles clockwise after this transformation, the pipeline must be - // set to treat counter-clockwise triangles as front-facing. An alternative would be to - // fully embrace the vulkan coordinate system, including geometry - however this goes - // against most existing software and practices. This might bite us in the ass at some - // point in the future. - let pipeline = Arc::new(vp::GraphicsPipeline::start() - .vertex_input(vpv::OneVertexOneInstanceDefinition::::new()) - .vertex_shader(vertex_shader.entry_point(), ()) - .triangle_list() - .primitive_restart(false) - .viewports(vec![viewport]) - .fragment_shader(fragment_shader.entry_point(), ()) - .depth_clamp(false) - .polygon_mode_fill() - .line_width(1.0) - .cull_mode_back() - .front_face_counter_clockwise() - .blend_pass_through() - .depth_stencil(vulkano::pipeline::depth_stencil::DepthStencil::simple_depth_test()) - .render_pass(vf::Subpass::from(render_pass.clone(), 0).unwrap()) - .build(device.clone()) - .unwrap()) - as Arc; - - let layout = pipeline.descriptor_set_layout(0).unwrap(); - let descriptor_set_pool = vdd::FixedSizeDescriptorSetsPool::new(layout.clone()); - - Forward { - pipeline, - descriptor_set_pool, - device - } - } -} - -impl Pipeline for Forward { - fn get_pipeline(&self) -> Arc { - self.pipeline.clone() - } - - fn make_descriptor_set(&mut self, texture_image: Arc>) -> Arc { - let image_sampler = vs::Sampler::simple_repeat_linear(self.device.clone()); - Arc::new(self.descriptor_set_pool.next() - .add_sampled_image(texture_image.clone(), image_sampler).unwrap() - .build().unwrap()) - } -} diff --git a/engine/src/render/vulkan/pipeline_forward.rs b/engine/src/render/vulkan/pipeline_forward.rs new file mode 100644 index 0000000..dafdc9a --- /dev/null +++ b/engine/src/render/vulkan/pipeline_forward.rs @@ -0,0 +1,170 @@ +use std::borrow::Cow; +use std::sync::Arc; + +use vulkano::descriptor::descriptor as vdD; +use vulkano::descriptor::descriptor_set as vdd; +use vulkano::descriptor::pipeline_layout as vdp; +use vulkano::device as vd; +use vulkano::format::Format; +use vulkano::framebuffer as vf; +use vulkano::image as vm; +use vulkano::pipeline as vp; +use vulkano::pipeline::shader as vps; +use vulkano::pipeline::vertex as vpv; +use vulkano::sampler as vs; + +use crate::render::vulkan::data; +use crate::render::vulkan::shaders; +use crate::render::vulkan::pipeline; + +pub struct Forward { + pipeline: Arc, + descriptor_set_pool: vdd::FixedSizeDescriptorSetsPool, + device: Arc, +} + +impl Forward { + pub fn new( + device: Arc, + viewport_dimensions: [u32; 2], + render_pass: Arc, + ) -> Forward { + let vertex_shader = shaders::ShaderDefinition { + name: "engine/shaders/forward_vert.spv".to_string(), + ty: vps::GraphicsShaderType::Vertex, + inputs: vec![ + vps::ShaderInterfaceDefEntry { + location: 0..1, format: Format::R32G32B32Sfloat, + name: Some(Cow::Borrowed("pos")), + }, + vps::ShaderInterfaceDefEntry { + location: 1..2, format: Format::R32G32B32Sfloat, + name: Some(Cow::Borrowed("color")), + }, + vps::ShaderInterfaceDefEntry { + location: 2..6, format: Format::R32G32B32A32Sfloat, + name: Some(Cow::Borrowed("model")), + }, + vps::ShaderInterfaceDefEntry { + location: 6..7, format: Format::R32G32Sfloat, + name: Some(Cow::Borrowed("tex")), + }, + ], + outputs: vec![ + vps::ShaderInterfaceDefEntry { + location: 0..1, format: Format::R32G32B32Sfloat, + name: Some(Cow::Borrowed("fragColor")), + }, + vps::ShaderInterfaceDefEntry { + location: 1..2, format: Format::R32G32Sfloat, + name: Some(Cow::Borrowed("fragTexCoord")), + }, + ], + uniforms: vec![], + push_constants: vec![ + vdp::PipelineLayoutDescPcRange { + offset: 0, + size: 64usize, + stages: vdD::ShaderStages { + vertex: true, + ..vdD::ShaderStages::none() + }, + }, + ], + }.load_into(device.clone()).expect("could not load vertex shader"); + + let fragment_shader = shaders::ShaderDefinition { + name: "engine/shaders/forward_frag.spv".to_string(), + ty: vps::GraphicsShaderType::Fragment, + inputs: vec![ + vps::ShaderInterfaceDefEntry { + location: 0..1, format: Format::R32G32B32Sfloat, + name: Some(Cow::Borrowed("fragColor")), + }, + vps::ShaderInterfaceDefEntry { + location: 1..2, format: Format::R32G32Sfloat, + name: Some(Cow::Borrowed("fragTexCoord")), + }, + ], + outputs: vec![ + vps::ShaderInterfaceDefEntry { + location: 0..1, format: Format::R32G32B32A32Sfloat, + name: Some(Cow::Borrowed("outColor")), + } + ], + uniforms: vec![ + vdD::DescriptorDesc { + ty: vdD::DescriptorDescTy::CombinedImageSampler(vdD::DescriptorImageDesc { + sampled: true, + dimensions: vdD::DescriptorImageDescDimensions::TwoDimensional, + format: None, + multisampled: false, + array_layers: vdD::DescriptorImageDescArray::NonArrayed, + }), + array_count: 1, + readonly: true, + stages: vdD::ShaderStages { + fragment: true, + ..vdD::ShaderStages::none() + }, + }, + ], + push_constants: vec![], + }.load_into(device.clone()).expect("could not load fragment shader"); + + let dimensions = [viewport_dimensions[0] as f32, viewport_dimensions[1] as f32]; + let viewport = vp::viewport::Viewport { + origin: [0.0, 0.0], + dimensions, + depth_range: 0.0 .. 1.0, + }; + + // Counter-clockwise facing triangles - this is because geometry data is left-handed, and + // the vertex shader performs a handedness flip by doing .y *= -1 on emitted vertices. To + // keep geomtry-space triangles clockwise after this transformation, the pipeline must be + // set to treat counter-clockwise triangles as front-facing. An alternative would be to + // fully embrace the vulkan coordinate system, including geometry - however this goes + // against most existing software and practices. This might bite us in the ass at some + // point in the future. + let pipeline = Arc::new(vp::GraphicsPipeline::start() + .vertex_input(vpv::OneVertexOneInstanceDefinition::::new()) + .vertex_shader(vertex_shader.entry_point(), ()) + .triangle_list() + .primitive_restart(false) + .viewports(vec![viewport]) + .fragment_shader(fragment_shader.entry_point(), ()) + .depth_clamp(false) + .polygon_mode_fill() + .line_width(1.0) + .cull_mode_back() + .front_face_counter_clockwise() + .blend_pass_through() + .depth_stencil(vulkano::pipeline::depth_stencil::DepthStencil::simple_depth_test()) + .render_pass(vf::Subpass::from(render_pass.clone(), 0).unwrap()) + .build(device.clone()) + .unwrap()) + as Arc; + + let layout = pipeline.descriptor_set_layout(0).unwrap(); + let descriptor_set_pool = vdd::FixedSizeDescriptorSetsPool::new(layout.clone()); + + Forward { + pipeline, + descriptor_set_pool, + device + } + } +} + +impl pipeline::Pipeline for Forward { + fn get_pipeline(&self) -> Arc { + self.pipeline.clone() + } + + fn make_descriptor_set(&mut self, texture_image: Arc>) -> Arc { + let image_sampler = vs::Sampler::simple_repeat_linear(self.device.clone()); + Arc::new(self.descriptor_set_pool.next() + .add_sampled_image(texture_image.clone(), image_sampler).unwrap() + .build().unwrap()) + } +} diff --git a/engine/src/util/resourcemap.rs b/engine/src/util/resourcemap.rs index 4d64b6f..27a6775 100644 --- a/engine/src/util/resourcemap.rs +++ b/engine/src/util/resourcemap.rs @@ -1,7 +1,5 @@ use std::cmp::PartialEq; -use crate::render::renderable::ResourceID; - /// A map from ResourceID to Vec, useful for building up information about /// a scene. This implementation is currently naive, but is pretty fast /// compared to a HashMap as it performs no hashing - just uses ResourceIDs.