From 483645dcc51ff037cb7195386d4a3db639f7bf57 Mon Sep 17 00:00:00 2001 From: Asuro Date: Fri, 27 Nov 2020 08:35:27 +0100 Subject: [PATCH] Allow for more pipelines --- src/main.rs | 5 +- src/pipelines.rs | 182 +++++++++++++++++++++++++++++++++++++++++++ src/vulkan.rs | 196 ++++++++++++----------------------------------- 3 files changed, 232 insertions(+), 151 deletions(-) create mode 100644 src/pipelines.rs diff --git a/src/main.rs b/src/main.rs index 34015b4..af1b0ef 100644 --- a/src/main.rs +++ b/src/main.rs @@ -6,7 +6,7 @@ use crate::gameobject::{GameObject, GameObjectHandle, Updatable}; use crate::input::InputState; use crate::player::Player; use crate::vulkan::{Game, LinePoint, MeshHandle, VulkanRenderer}; -use crate::vulkan::vs::ty::ObjectUniformData; +use crate::pipelines::vs::ty::ObjectUniformData; mod vulkan; mod input; @@ -14,6 +14,7 @@ mod config; mod mesh; mod gameobject; mod player; +mod pipelines; struct TestGame { input: InputState, @@ -159,7 +160,7 @@ impl TestGame { fn add_game_object(&mut self, renderer: &mut VulkanRenderer, mesh: MeshHandle) -> &mut GameObjectHandle { let obj = GameObject::new(mesh); - let obj_handle = renderer.add_game_object(obj); + let obj_handle = renderer.add_game_object(obj, 0); self.game_objects.push(obj_handle); self.game_objects.last_mut().unwrap() } diff --git a/src/pipelines.rs b/src/pipelines.rs new file mode 100644 index 0000000..eec2eb3 --- /dev/null +++ b/src/pipelines.rs @@ -0,0 +1,182 @@ +use vulkano::command_buffer::DynamicState; +use crate::vulkan::GameData; +use crate::vulkan::{LinePoint, Vertex}; +use crate::GameObject; +use vulkano::{command_buffer::AutoCommandBufferBuilder, descriptor::descriptor_set::PersistentDescriptorSet}; +use crate::VulkanRenderer; +use vulkano::pipeline::{GraphicsPipeline}; +use vulkano::framebuffer::Subpass; +use vulkano::pipeline::GraphicsPipelineAbstract; +use vulkano::framebuffer::RenderPassAbstract; +use std::sync::Arc; +use vulkano::device::Device; + +type RP = Arc; +type GP = Arc; + +pub trait Drawcall { + fn draw(self: &Self, builder: &mut AutoCommandBufferBuilder, fb_index: usize, game_data: &GameData, dynamic_state: &DynamicState); + fn create_descriptor_set(self: &Self, game_object: &mut GameObject, renderer: &VulkanRenderer); + fn recreate_pipeline(self: &mut Self, device: Arc, render_pass: RP); + fn get_pipeline(self: &Self) -> &GP; +} + +pub mod vs { + vulkano_shaders::shader!{ + ty: "vertex", + path: "shaders/triangle.vert" + } +} + +pub mod fs { + vulkano_shaders::shader! { + ty: "fragment", + path: "shaders/triangle.frag" + } +} + +#[derive(Clone)] +pub struct DefaultShader { + pipeline: GP, +} + +impl DefaultShader { + pub fn new(device: Arc, render_pass: RP) -> Self { + DefaultShader { + pipeline: Self::create_pipeline(device, render_pass) + } + } + + fn create_pipeline(device: Arc, render_pass: RP) -> GP { + let sub_pass = Subpass::from(render_pass.clone(), 0).unwrap(); + let vertex_shader = vs::Shader::load(device.clone()).unwrap(); + let fragment_shader = fs::Shader::load(device.clone()).unwrap(); + + Arc::new(GraphicsPipeline::start() + .vertex_input_single_buffer::() + .vertex_shader(vertex_shader.main_entry_point(), ()) + .triangle_list() + .viewports_dynamic_scissors_irrelevant(1) + .depth_stencil_simple_depth() + .fragment_shader(fragment_shader.main_entry_point(), ()) + .blend_alpha_blending() + .cull_mode_back() + .render_pass(sub_pass.clone()) + .build(device.clone()) + .unwrap()) + } +} + +impl Drawcall for DefaultShader { + fn recreate_pipeline(self: &mut Self, device: Arc, render_pass: RP) { + self.pipeline = Self::create_pipeline(device, render_pass); + } + + fn create_descriptor_set(self: &Self, game_object: &mut GameObject, renderer: &VulkanRenderer) { + let descriptor_set_layout = self.get_pipeline().descriptor_set_layout(0).unwrap().clone(); + + println!("Diff: {:?}, Norm: {:?}", game_object.texture_index, game_object.normal_map_index); + + game_object.descriptor_sets = renderer.uniform_buffers.iter().map(|uniform_buffer| { + let descriptor_set: Arc<(dyn vulkano::descriptor::DescriptorSet + std::marker::Send + std::marker::Sync + 'static)>; + let builder = PersistentDescriptorSet::start(descriptor_set_layout.clone()); + + descriptor_set = Arc::new(builder + .add_buffer(uniform_buffer.clone()).unwrap() + .add_sampled_image(renderer.game_data.textures[game_object.texture_index].clone(), renderer.sampler.clone()).unwrap() + .add_sampled_image(renderer.game_data.textures[game_object.normal_map_index].clone(), renderer.sampler.clone()).unwrap() + .build().unwrap()); + + descriptor_set + }).collect(); + } + + fn draw(self: &Self, builder: &mut AutoCommandBufferBuilder, fb_index: usize, game_data: &GameData, dynamic_state: &DynamicState) { + for i in 0..game_data.game_objects.len() { + let game_object = &game_data.game_objects[i]; + let mesh = &game_data.meshes[game_object.mesh_index]; + let mut push_constants = game_data.push_constants.clone(); + push_constants.model = game_object.get_model_matrix().into(); + + builder.draw_indexed( + self.pipeline.clone(), + dynamic_state, + vec![mesh.vertex_buffer.clone()], + mesh.index_buffer.clone(), + game_object.descriptor_sets[fb_index].clone(), + push_constants).unwrap(); + } + } + + fn get_pipeline(self: &Self) -> &GP { + &self.pipeline + } +} + +pub mod line_vs { + vulkano_shaders::shader!{ + ty: "vertex", + path: "shaders/line.vert" + } +} + +pub mod line_fs { + vulkano_shaders::shader! { + ty: "fragment", + path: "shaders/line.frag" + } +} + +#[derive(Clone)] +pub struct LineShader { + pipeline: GP, + vertex_buffer: Arc> +} + +impl LineShader { + pub fn new(device: Arc, render_pass: RP, vertex_buffer: Arc>) -> Self { + LineShader { + pipeline: Self::create_pipeline(device, render_pass), + vertex_buffer + } + } + + fn create_pipeline(device: Arc, render_pass: RP) -> GP { + let sub_pass = Subpass::from(render_pass.clone(), 0).unwrap(); + let vertex_shader = line_vs::Shader::load(device.clone()).unwrap(); + let fragment_shader = line_fs::Shader::load(device.clone()).unwrap(); + + Arc::new(GraphicsPipeline::start() + .vertex_input_single_buffer::() + .vertex_shader(vertex_shader.main_entry_point(), ()) + .line_list() + .viewports_dynamic_scissors_irrelevant(1) + .depth_stencil_simple_depth() + .fragment_shader(fragment_shader.main_entry_point(), ()) + .render_pass(sub_pass.clone()) + .build(device.clone()) + .unwrap()) + } +} + +impl Drawcall for LineShader { + fn draw(self: &Self, builder: &mut AutoCommandBufferBuilder, _fb_index: usize, game_data: &GameData, dynamic_state: &DynamicState) { + builder.draw(self.pipeline.clone(), + &dynamic_state, + vec![self.vertex_buffer.clone()], + (), + game_data.line_push_constants.clone()).unwrap(); + } + + fn create_descriptor_set(self: &Self, game_object: &mut GameObject, renderer: &VulkanRenderer) { + + } + + fn recreate_pipeline(self: &mut Self, device: Arc, render_pass: RP) { + self.pipeline = Self::create_pipeline(device, render_pass); + } + + fn get_pipeline(self: &Self) -> &GP { + &self.pipeline + } +} \ No newline at end of file diff --git a/src/vulkan.rs b/src/vulkan.rs index 8176199..d1a7401 100644 --- a/src/vulkan.rs +++ b/src/vulkan.rs @@ -1,3 +1,5 @@ +use crate::pipelines::{Drawcall, LineShader}; +use crate::pipelines::DefaultShader; use std::sync::Arc; use std::time::SystemTime; @@ -6,16 +8,13 @@ use image::{ImageBuffer, ImageFormat, Rgb, Rgba}; use image::buffer::ConvertBuffer; use vulkano::{command_buffer::CommandBuffer, buffer::{BufferUsage, CpuAccessibleBuffer}, image::{ImageLayout, MipmapsCount}}; use vulkano::command_buffer::{AutoCommandBuffer, AutoCommandBufferBuilder, DynamicState}; -use vulkano::descriptor::descriptor_set::PersistentDescriptorSet; use vulkano::descriptor::DescriptorSet; use vulkano::device::{Device, DeviceExtensions, Queue}; use vulkano::format::{ClearValue, Format}; -use vulkano::framebuffer::{Framebuffer, FramebufferAbstract, RenderPassAbstract, Subpass}; +use vulkano::framebuffer::{Framebuffer, FramebufferAbstract, RenderPassAbstract}; use vulkano::image::{AttachmentImage, Dimensions, ImageUsage, ImmutableImage, SwapchainImage, ImageViewAccess}; use vulkano::instance::{ApplicationInfo, Instance, InstanceExtensions, PhysicalDevice, Version}; use vulkano::instance::debug::{DebugCallback, MessageSeverity, MessageType}; -use vulkano::memory::pool::{PotentialDedicatedAllocation, StdMemoryPoolAlloc}; -use vulkano::pipeline::{GraphicsPipeline, GraphicsPipelineAbstract}; use vulkano::pipeline::viewport::Viewport; use vulkano::sampler::{Filter, MipmapMode, Sampler, SamplerAddressMode}; use vulkano::swapchain::{AcquireError, ColorSpace, FullscreenExclusive, PresentMode, Surface, SurfaceTransform, Swapchain, SwapchainCreationError}; @@ -27,10 +26,11 @@ use winit::event::{Event, WindowEvent}; use winit::event_loop::{ControlFlow, EventLoop}; use winit::window::{Window, WindowBuilder}; -use line_vs::ty::LinePushConstants; -use vs::ty::PushConstants; +use crate::pipelines::{line_vs::ty::LinePushConstants}; +use crate::pipelines::vs::ty::PushConstants; -use crate::gameobject::{GameObject, GameObjectHandle}; +use crate::pipelines::vs; +use crate::{gameobject::{GameObject, GameObjectHandle}}; use crate::mesh::CPUMesh; use crate::config::RenderConfig; @@ -63,8 +63,8 @@ pub trait Game { } pub struct Mesh { - vertex_buffer: Arc>, - index_buffer: Arc>, + pub vertex_buffer: Arc>, + pub index_buffer: Arc>, } #[derive(Debug, Copy, Clone)] @@ -98,9 +98,7 @@ pub struct VulkanRenderer { pub framebuffers: Vec>, pub sampler: Arc, pub dynamic_state: DynamicState, - pub pipeline: Arc, - pub line_pipeline: Arc, - pub line_vertex_buffer: Arc>>, + pub pipelines: Vec>, pub surface: Arc>, pub swapchain: Arc>, pub render_pass: Arc, @@ -233,9 +231,6 @@ impl VulkanRenderer { PresentMode::Fifo, FullscreenExclusive::Default, true, ColorSpace::SrgbNonLinear).unwrap() }; - // what is host_cached - let line_vertex_buffer = CpuAccessibleBuffer::from_iter(device.clone(), BufferUsage::vertex_buffer(), false, data.line_vertices.iter().cloned()).unwrap(); - // Render pass let render_pass = Arc::new(vulkano::single_pass_renderpass!( device.clone(), @@ -272,10 +267,12 @@ impl VulkanRenderer { MipmapMode::Nearest, SamplerAddressMode::Repeat, SamplerAddressMode::Repeat, SamplerAddressMode::Repeat, 0.0, 1.0, 0.0, 0.0).unwrap(); - let pipeline: Arc = - create_pipeline::(device.clone(), render_pass.clone(), false).unwrap(); - let line_pipeline: Arc = - create_pipeline::(device.clone(), render_pass.clone(), true).unwrap(); + let line_vertex_buffer = CpuAccessibleBuffer::from_iter(device.clone(), BufferUsage::vertex_buffer(), false, data.line_vertices.iter().cloned()).unwrap(); + + let pipelines: Vec> = vec![ + Box::new(DefaultShader::new(device.clone(), render_pass.clone())), + Box::new(LineShader::new(device.clone(), render_pass.clone(), line_vertex_buffer)), + ]; let default_tex = { let image = image::load_from_memory_with_format(include_bytes!("../models/missing-texture.jpg"), @@ -337,8 +334,8 @@ impl VulkanRenderer { let previous_frame_end = Some(Box::new(sync::now(device.clone())) as Box); (VulkanRenderer { game_data: data, device, framebuffers, sampler, - dynamic_state, pipeline, line_pipeline, uniform_buffers, - surface, swapchain, render_pass, queue, line_vertex_buffer, + dynamic_state, pipelines, uniform_buffers, + surface, swapchain, render_pass, queue, recreate_swapchain: false, debug_callback, previous_frame_end, msaa_sample_count: render_config.msaa_samples }, events_loop) @@ -350,26 +347,11 @@ impl VulkanRenderer { builder.update_buffer(self.uniform_buffers[fb_index].clone(), uniform_buffer_data).unwrap(); builder.begin_render_pass(self.framebuffers[fb_index].clone(), false, vec![ClearValue::None, ClearValue::Float([0.0, 0.0, 0.0, 1.0]), ClearValue::Depth(1.0)]).unwrap(); - // Load and draw meshes etc. - for i in 0..self.game_data.game_objects.len() { - let game_object = &self.game_data.game_objects[i]; - let mesh = &self.game_data.meshes[game_object.mesh_index]; - self.game_data.push_constants.model = game_object.get_model_matrix().into(); - - builder.draw_indexed( - self.pipeline.clone(), - &self.dynamic_state, - vec![mesh.vertex_buffer.clone()], - mesh.index_buffer.clone(), - game_object.descriptor_sets[fb_index].clone(), - self.game_data.push_constants.clone()).unwrap(); + // Draw meshes etc. + for pipeline in &self.pipelines { + pipeline.draw(&mut builder, fb_index, &self.game_data, &self.dynamic_state); } - - // Draw line grid - if self.game_data.use_line_pipeline { - builder.draw(self.line_pipeline.clone(), &self.dynamic_state, vec![self.line_vertex_buffer.clone()], (), self.game_data.line_push_constants.clone()).unwrap(); - } - + // General cleanup builder.end_render_pass().unwrap(); Arc::new(builder.build().unwrap()) @@ -416,12 +398,9 @@ impl VulkanRenderer { // recreate pipeline if requested if self.game_data.recreate_pipeline { - if let Some(pipeline_ok) = create_pipeline::(self.device.clone(), self.render_pass.clone(), false) { - self.pipeline = pipeline_ok; - println!("Updated pipeline."); - } else { - println!("Failed to update pipeline."); - } + let device = self.device.clone(); + let render_pass = self.render_pass.clone(); + self.pipelines.iter_mut().for_each(|pipeline| pipeline.recreate_pipeline(device.clone(), render_pass.clone())); self.game_data.recreate_pipeline = false; } @@ -523,27 +502,27 @@ impl VulkanRenderer { ).unwrap(); // Generate mipmaps - let mut mip_width = image_view.dimensions().width() as i32; - let mut mip_height = image_view.dimensions().height() as i32; + // let mut mip_width = image_view.dimensions().width() as i32; + // let mut mip_height = image_view.dimensions().height() as i32; - for i in 0..image_view.mipmap_levels() { - command_buffer_builder.blit_image( - image_view.clone(), - [0; 3], - [mip_width, mip_height, 1], - 0, - i, - image_view.clone(), - [0; 3], - [mip_width / 2, mip_height / 2, 1], - 0, - i + 1, - dimensions.array_layers_with_cube(), - Filter::Linear).unwrap(); + // for i in 0..image_view.mipmap_levels() { + // command_buffer_builder.blit_image( + // image_view.clone(), + // [0; 3], + // [mip_width, mip_height, 1], + // 0, + // i, + // image_view.clone(), + // [0; 3], + // [mip_width / 2, mip_height / 2, 1], + // 0, + // i + 1, + // dimensions.array_layers_with_cube(), + // Filter::Linear).unwrap(); - if mip_width > 1 { mip_width = mip_width / 2; } - if mip_height > 1 { mip_height = mip_height / 2; } - } + // if mip_width > 1 { mip_width = mip_width / 2; } + // if mip_height > 1 { mip_height = mip_height / 2; } + // } let command_buffer = command_buffer_builder.build().unwrap(); let command_buffer_future = command_buffer.execute(self.queue.clone()).unwrap(); @@ -552,22 +531,8 @@ impl VulkanRenderer { self.game_data.textures.push(image_view); } - pub fn add_game_object(self: &mut Self, mut game_object: GameObject) -> GameObjectHandle { - let descriptor_set_layout = self.pipeline.descriptor_set_layout(0).unwrap().clone(); - - println!("Diff: {:?}, Norm: {:?}", game_object.texture_index, game_object.normal_map_index); - - let descriptor_sets = self.uniform_buffers.iter().map(|uniform_buffer| { - let builder = PersistentDescriptorSet::start(descriptor_set_layout.clone()); - let result: Arc = Arc::new(builder - .add_buffer(uniform_buffer.clone()).unwrap() - .add_sampled_image(self.game_data.textures[game_object.texture_index].clone(), self.sampler.clone()).unwrap() - .add_sampled_image(self.game_data.textures[game_object.normal_map_index].clone(), self.sampler.clone()).unwrap() - .build().unwrap()); - result - }).collect(); - - game_object.descriptor_sets = descriptor_sets; + pub fn add_game_object(self: &mut Self, mut game_object: GameObject, pipeline_index: usize) -> GameObjectHandle { + self.pipelines[pipeline_index].create_descriptor_set(&mut game_object, self); self.game_data.game_objects.push(game_object); GameObjectHandle { @@ -621,71 +586,4 @@ fn window_size_dependent_setup(device: Arc, images: &[Arc(device: Arc, render_pass: Arc, is_line: bool) -> Option> { - let sub_pass = Subpass::from(render_pass.clone(), 0).unwrap(); - let pipeline; - - if is_line { - let vertex_shader = line_vs::Shader::load(device.clone()).unwrap(); - let fragment_shader = line_fs::Shader::load(device.clone()).unwrap(); - - pipeline = Arc::new(GraphicsPipeline::start() - .vertex_input_single_buffer::() - .vertex_shader(vertex_shader.main_entry_point(), ()) - .line_list() - .viewports_dynamic_scissors_irrelevant(1) - .depth_stencil_simple_depth() - .fragment_shader(fragment_shader.main_entry_point(), ()) - .render_pass(sub_pass.clone()) - .build(device.clone()) - .unwrap()); - } else { - let vertex_shader = vs::Shader::load(device.clone()).unwrap(); - let fragment_shader = fs::Shader::load(device.clone()).unwrap(); - - pipeline = Arc::new(GraphicsPipeline::start() - .vertex_input_single_buffer::() - .vertex_shader(vertex_shader.main_entry_point(), ()) - .triangle_list() - .viewports_dynamic_scissors_irrelevant(1) - .depth_stencil_simple_depth() - .fragment_shader(fragment_shader.main_entry_point(), ()) - .blend_alpha_blending() - .cull_mode_back() - .render_pass(sub_pass.clone()) - .build(device.clone()) - .unwrap()); - } - - return Some(pipeline); -} +} \ No newline at end of file