From dd4eaa13f70322d29722b3d20903566e214d9316 Mon Sep 17 00:00:00 2001 From: Asuro Date: Sat, 5 Dec 2020 22:12:29 +0100 Subject: [PATCH] Live toggle msaa --- config/log.toml | 2 +- src/game/mod.rs | 9 +++ src/vulkan/framebuffers.rs | 73 +++++++++++++++++++ src/vulkan/mod.rs | 145 ++++++------------------------------- src/vulkan/renderpass.rs | 64 ++++++++++++++++ 5 files changed, 168 insertions(+), 125 deletions(-) create mode 100644 src/vulkan/framebuffers.rs create mode 100644 src/vulkan/renderpass.rs diff --git a/config/log.toml b/config/log.toml index 73d0727..233e82f 100644 --- a/config/log.toml +++ b/config/log.toml @@ -1,5 +1,5 @@ vulkan_validation_layers = true -mesh_load_info = true +mesh_load_info = false [input] mouse_motion = false diff --git a/src/game/mod.rs b/src/game/mod.rs index 3dd931c..93627ae 100644 --- a/src/game/mod.rs +++ b/src/game/mod.rs @@ -64,6 +64,15 @@ impl Game for TestGame { println!("{:.0} ms / {:.0} FPS", frame_time * 1000.0, 1.0 / frame_time); } + if self.input.button_just_pressed("test") { + if renderer.render_config.msaa_samples > 0 { + renderer.render_config.msaa_samples = 0; + } else { + renderer.render_config.msaa_samples = 8; + } + renderer.recreate_swapchain = true; + } + // Custom game object stuff let light_pos = self.player.camera.position * -1.0; self.player.update(frame_time, &self.input, renderer); diff --git a/src/vulkan/framebuffers.rs b/src/vulkan/framebuffers.rs new file mode 100644 index 0000000..768b428 --- /dev/null +++ b/src/vulkan/framebuffers.rs @@ -0,0 +1,73 @@ +use std::sync::Arc; + +use vulkano::command_buffer::DynamicState; +use vulkano::device::Device; +use vulkano::format::Format; +use vulkano::framebuffer::{Framebuffer, FramebufferAbstract, RenderPassAbstract}; +use vulkano::image::{AttachmentImage, ImageUsage, SwapchainImage}; +use vulkano::pipeline::viewport::Viewport; +use winit::window::Window; +use vulkano::swapchain::Swapchain; + +/// This method is called once during initialization, then again whenever the window is resized +pub fn create_framebuffers(device: Arc, + swapchain: &Arc>, + images: &[Arc>], + msaa_sample_count: u32, + render_pass: Arc, + dynamic_state: &mut DynamicState) + -> Vec> { + + let dim_array = images[0].dimensions(); + let dim_array_f32 = [dim_array[0] as f32, dim_array[1] as f32]; + + let viewport = Viewport { + origin: [0.0, 0.0], + dimensions: dim_array_f32, + depth_range: 0.0..1.0, + }; + dynamic_state.viewports = Some(vec!(viewport)); + + let depth_image = if msaa_sample_count > 0 { + AttachmentImage::multisampled_with_usage(device.clone(), dim_array, msaa_sample_count, Format::D16Unorm, ImageUsage { depth_stencil_attachment: true, ..ImageUsage::none() }).unwrap() + } else { + AttachmentImage::with_usage(device.clone(), dim_array, Format::D16Unorm, ImageUsage { depth_stencil_attachment: true, ..ImageUsage::none() }).unwrap() + }; + + let msaa_buffers = if msaa_sample_count > 0 { + Some(create_msaa_buffers(device.clone(), dim_array, swapchain, msaa_sample_count)) + } else { + None + }; + + let mut framebuffers = vec![]; + + for i in 0..images.len() { + let image_buffer = &images[i]; + + if let Some(msaa_buffers_exist) = &msaa_buffers { + framebuffers.push(Arc::new(Framebuffer::start(render_pass.clone()) + .add(image_buffer.clone()).unwrap() + .add((&msaa_buffers_exist[i]).clone()).unwrap() + .add(depth_image.clone()).unwrap() + .build().unwrap() + ) as Arc); + } else { + framebuffers.push(Arc::new(Framebuffer::start(render_pass.clone()) + .add(image_buffer.clone()).unwrap() + .add(depth_image.clone()).unwrap() + .build().unwrap() + ) as Arc); + } + } + + framebuffers +} + +fn create_msaa_buffers(device: Arc, dimensions: [u32; 2], swapchain: &Arc>, sample_count: u32) -> Vec> { + let mut msaa_attachments = vec![]; + for _ in 0..swapchain.num_images() { + msaa_attachments.push(AttachmentImage::transient_multisampled(device.clone(), dimensions, sample_count, swapchain.format()).unwrap()); + } + msaa_attachments +} \ No newline at end of file diff --git a/src/vulkan/mod.rs b/src/vulkan/mod.rs index 9633103..8474df1 100644 --- a/src/vulkan/mod.rs +++ b/src/vulkan/mod.rs @@ -9,11 +9,10 @@ use vulkano::command_buffer::{AutoCommandBuffer, AutoCommandBufferBuilder, Dynam use vulkano::descriptor::DescriptorSet; use vulkano::device::{Device, DeviceExtensions, Queue}; use vulkano::format::{ClearValue, Format}; -use vulkano::framebuffer::{Framebuffer, FramebufferAbstract, RenderPassAbstract}; -use vulkano::image::{AttachmentImage, Dimensions, ImageUsage, ImageViewAccess, ImmutableImage, SwapchainImage}; +use vulkano::framebuffer::{RenderPassAbstract, FramebufferAbstract}; +use vulkano::image::{Dimensions, ImageUsage, ImmutableImage}; use vulkano::instance::{ApplicationInfo, Instance, InstanceExtensions, PhysicalDevice, Version}; use vulkano::instance::debug::{DebugCallback, MessageSeverity, MessageType}; -use vulkano::pipeline::viewport::Viewport; use vulkano::sampler::{Filter, MipmapMode, Sampler, SamplerAddressMode}; use vulkano::swapchain::{AcquireError, FullscreenExclusive, PresentMode, Surface, SurfaceTransform, Swapchain, SwapchainCreationError}; use vulkano::swapchain; @@ -37,6 +36,8 @@ use crate::vulkan::{gameobject::{GameObject, GameObjectHandle}}; pub mod pipelines; pub mod gameobject; pub mod mesh; +mod renderpass; +mod framebuffers; const VALIDATION_LAYERS: &[&str] = &[ "VK_LAYER_KHRONOS_validation" @@ -113,7 +114,8 @@ pub struct VulkanRenderer { pub debug_callback: Option, pub previous_frame_end: Option>, pub uniform_buffers: Vec>>, - pub msaa_sample_count: u32, + pub line_vertex_buffer: Arc>, + pub render_config: RenderConfig } impl VulkanRenderer { @@ -238,62 +240,7 @@ impl VulkanRenderer { }; // Render pass - let render_pass: Arc = if render_config.msaa_samples > 0 { - Arc::new(vulkano::single_pass_renderpass!( - device.clone(), - attachments: { - color: { - load: DontCare, - store: Store, - format: swapchain.format(), - samples: 1, - }, - intermediary: { - load: Clear, - store: DontCare, - format: swapchain.format(), - samples: render_config.msaa_samples, - }, - depth: { - load: Clear, - store: Store, - format: Format::D16Unorm, - samples: render_config.msaa_samples, - initial_layout: ImageLayout::Undefined, - final_layout: ImageLayout::DepthStencilAttachmentOptimal, - } - }, - pass: { - color: [intermediary], - depth_stencil: {depth}, - resolve: [color] - } - ).unwrap()) - } else { - Arc::new(vulkano::single_pass_renderpass!( - device.clone(), - attachments: { - color: { - load: Clear, - store: Store, - format: swapchain.format(), - samples: 1, - }, - depth: { - load: Clear, - store: Store, - format: Format::D16Unorm, - samples: 1, - initial_layout: ImageLayout::Undefined, - final_layout: ImageLayout::DepthStencilAttachmentOptimal, - } - }, - pass: { - color: [color], - depth_stencil: {depth} - } - ).unwrap()) - }; + let render_pass = renderpass::create_render_pass(device.clone(), &render_config, swapchain.format()); let sampler = Sampler::new(device.clone(), Filter::Linear, Filter::Linear, MipmapMode::Nearest, SamplerAddressMode::Repeat, SamplerAddressMode::Repeat, @@ -303,22 +250,18 @@ impl VulkanRenderer { 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)), + Box::new(LineShader::new(device.clone(), render_pass.clone(), line_vertex_buffer.clone())), ]; // Dynamic viewports allow us to recreate just the viewport when the window is resized // Otherwise we would have to recreate the whole pipeline. let mut dynamic_state = DynamicState { line_width: None, viewports: None, scissors: None, compare_mask: None, write_mask: None, reference: None }; - let msaa_attachments = if render_config.msaa_samples > 0 { - Some(Self::create_msaa_buffers(device.clone(), data.dimensions, &swapchain, render_config.msaa_samples)) - } else { - None - }; + // The render pass we created above only describes the layout of our framebuffers. Before we // can draw we also need to create the actual framebuffers. - let framebuffers = window_size_dependent_setup(device.clone(), &images, msaa_attachments, render_config.msaa_samples, render_pass.clone(), &mut dynamic_state); + let framebuffers = framebuffers::create_framebuffers(device.clone(), &swapchain, &images, render_config.msaa_samples, render_pass.clone(), &mut dynamic_state); let mut uniform_buffers = Vec::new(); let uniform_buffer = vs::ty::ObjectUniformData { @@ -352,7 +295,8 @@ impl VulkanRenderer { 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 + render_config, + line_vertex_buffer, }, events_loop) } @@ -360,7 +304,7 @@ impl VulkanRenderer { // General setup let mut builder = AutoCommandBufferBuilder::primary_simultaneous_use(self.device.clone(), self.queue.family()).unwrap(); builder.update_buffer(self.uniform_buffers[fb_index].clone(), uniform_buffer_data).unwrap(); - if self.msaa_sample_count > 0 { + if self.render_config.msaa_samples > 0 { 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(); } else { builder.begin_render_pass(self.framebuffers[fb_index].clone(), false, vec![ClearValue::Float([0.0, 0.0, 0.0, 1.0]), ClearValue::Depth(1.0)]).unwrap(); @@ -376,13 +320,7 @@ impl VulkanRenderer { Arc::new(builder.build().unwrap()) } - fn create_msaa_buffers(device: Arc, dimensions: [u32; 2], swapchain: &Arc>, sample_count: u32) -> Vec> { - let mut msaa_attachments = vec![]; - for _ in 0..swapchain.num_images() { - msaa_attachments.push(AttachmentImage::transient_multisampled(device.clone(), dimensions, sample_count, swapchain.format()).unwrap()); - } - msaa_attachments - } + pub fn render_loop(self: &mut Self, new_ubo: vs::ty::ObjectUniformData) { // cleanup previous frame @@ -405,16 +343,17 @@ impl VulkanRenderer { Err(err) => panic!("{:?}", err), }; - let msaa_buffers = if self.msaa_sample_count > 0 { - Some(Self::create_msaa_buffers(self.device.clone(), self.game_data.dimensions, &new_swapchain, self.msaa_sample_count)) - } else { - None - }; + self.render_pass = renderpass::create_render_pass(self.device.clone(), &self.render_config, new_swapchain.format()); + + self.pipelines = vec![ + Box::new(DefaultShader::new(self.device.clone(), self.render_pass.clone())), + Box::new(LineShader::new(self.device.clone(), self.render_pass.clone(), self.line_vertex_buffer.clone())), + ]; self.swapchain = new_swapchain; // Because framebuffers contains an Arc on the old swapchain, we need to // recreate framebuffers as well. - self.framebuffers = window_size_dependent_setup(self.device.clone(), &new_images, msaa_buffers, self.msaa_sample_count, self.render_pass.clone(), &mut self.dynamic_state); + self.framebuffers = framebuffers::create_framebuffers(self.device.clone(), &self.swapchain, &new_images, self.render_config.msaa_samples, self.render_pass.clone(), &mut self.dynamic_state); self.recreate_swapchain = false; } @@ -586,45 +525,3 @@ pub fn start_event_loop(mut renderer: VulkanRenderer, mut game: Box, e }); } -/// This method is called once during initialization, then again whenever the window is resized -fn window_size_dependent_setup(device: Arc, images: &[Arc>], msaa_buffers: Option>>, msaa_sample_count: u32, render_pass: Arc, dynamic_state: &mut DynamicState) -> Vec> { - let dimensions = images[0].dimensions(); - let dim_array = [dimensions.width() as f32, dimensions.height() as f32]; - let dim_array_u32 = [dimensions.width() as u32, dimensions.height() as u32]; - - let viewport = Viewport { - origin: [0.0, 0.0], - dimensions: dim_array, - depth_range: 0.0 .. 1.0, - }; - dynamic_state.viewports = Some(vec!(viewport)); - - let depth_image = if let Some(msaa_buffers_exist) = &msaa_buffers { - AttachmentImage::multisampled_with_usage(device.clone(), dim_array_u32, msaa_sample_count, Format::D16Unorm, ImageUsage { depth_stencil_attachment: true, ..ImageUsage::none() }).unwrap() - } else { - AttachmentImage::with_usage(device.clone(), dim_array_u32, Format::D16Unorm, ImageUsage { depth_stencil_attachment: true, ..ImageUsage::none() }).unwrap() - }; - - let mut framebuffers = vec![]; - - for i in 0..images.len() { - let image_buffer = &images[i]; - - if let Some(msaa_buffers_exist) = &msaa_buffers { - framebuffers.push(Arc::new(Framebuffer::start(render_pass.clone()) - .add(image_buffer.clone()).unwrap() - .add((&msaa_buffers_exist[i]).clone()).unwrap() - .add(depth_image.clone()).unwrap() - .build().unwrap() - ) as Arc); - } else { - framebuffers.push(Arc::new(Framebuffer::start(render_pass.clone()) - .add(image_buffer.clone()).unwrap() - .add(depth_image.clone()).unwrap() - .build().unwrap() - ) as Arc); - } - } - - framebuffers -} diff --git a/src/vulkan/renderpass.rs b/src/vulkan/renderpass.rs new file mode 100644 index 0000000..073d5c4 --- /dev/null +++ b/src/vulkan/renderpass.rs @@ -0,0 +1,64 @@ +use crate::RenderConfig; +use std::sync::Arc; +use vulkano::framebuffer::RenderPassAbstract; +use vulkano::format::Format; +use vulkano::device::Device; + +pub fn create_render_pass(device: Arc, render_config: &RenderConfig, swapchain_format: Format) -> Arc { + if render_config.msaa_samples > 0 { + Arc::new(vulkano::single_pass_renderpass!( + device.clone(), + attachments: { + color: { + load: DontCare, + store: Store, + format: swapchain_format, + samples: 1, + }, + intermediary: { + load: Clear, + store: DontCare, + format: swapchain_format, + samples: render_config.msaa_samples, + }, + depth: { + load: Clear, + store: Store, + format: Format::D16Unorm, + samples: render_config.msaa_samples, + initial_layout: ImageLayout::Undefined, + final_layout: ImageLayout::DepthStencilAttachmentOptimal, + } + }, + pass: { + color: [intermediary], + depth_stencil: {depth}, + resolve: [color] + } + ).unwrap()) + } else { + Arc::new(vulkano::single_pass_renderpass!( + device.clone(), + attachments: { + color: { + load: Clear, + store: Store, + format: swapchain_format, + samples: 1, + }, + depth: { + load: Clear, + store: Store, + format: Format::D16Unorm, + samples: 1, + initial_layout: ImageLayout::Undefined, + final_layout: ImageLayout::DepthStencilAttachmentOptimal, + } + }, + pass: { + color: [color], + depth_stencil: {depth} + } + ).unwrap()) + } +} \ No newline at end of file