Live toggle msaa

This commit is contained in:
2020-12-05 22:12:29 +01:00
parent 33768a6730
commit dd4eaa13f7
5 changed files with 168 additions and 125 deletions

View File

@@ -1,5 +1,5 @@
vulkan_validation_layers = true vulkan_validation_layers = true
mesh_load_info = true mesh_load_info = false
[input] [input]
mouse_motion = false mouse_motion = false

View File

@@ -64,6 +64,15 @@ impl Game for TestGame {
println!("{:.0} ms / {:.0} FPS", frame_time * 1000.0, 1.0 / frame_time); 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 // Custom game object stuff
let light_pos = self.player.camera.position * -1.0; let light_pos = self.player.camera.position * -1.0;
self.player.update(frame_time, &self.input, renderer); self.player.update(frame_time, &self.input, renderer);

View File

@@ -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<Device>,
swapchain: &Arc<Swapchain<Window>>,
images: &[Arc<SwapchainImage<Window>>],
msaa_sample_count: u32,
render_pass: Arc<dyn RenderPassAbstract + Send + Sync>,
dynamic_state: &mut DynamicState)
-> Vec<Arc<dyn FramebufferAbstract + Send + Sync>> {
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<dyn FramebufferAbstract + Send + Sync>);
} else {
framebuffers.push(Arc::new(Framebuffer::start(render_pass.clone())
.add(image_buffer.clone()).unwrap()
.add(depth_image.clone()).unwrap()
.build().unwrap()
) as Arc<dyn FramebufferAbstract + Send + Sync>);
}
}
framebuffers
}
fn create_msaa_buffers(device: Arc<Device>, dimensions: [u32; 2], swapchain: &Arc<Swapchain<Window>>, sample_count: u32) -> Vec<Arc<AttachmentImage>> {
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
}

View File

@@ -9,11 +9,10 @@ use vulkano::command_buffer::{AutoCommandBuffer, AutoCommandBufferBuilder, Dynam
use vulkano::descriptor::DescriptorSet; use vulkano::descriptor::DescriptorSet;
use vulkano::device::{Device, DeviceExtensions, Queue}; use vulkano::device::{Device, DeviceExtensions, Queue};
use vulkano::format::{ClearValue, Format}; use vulkano::format::{ClearValue, Format};
use vulkano::framebuffer::{Framebuffer, FramebufferAbstract, RenderPassAbstract}; use vulkano::framebuffer::{RenderPassAbstract, FramebufferAbstract};
use vulkano::image::{AttachmentImage, Dimensions, ImageUsage, ImageViewAccess, ImmutableImage, SwapchainImage}; use vulkano::image::{Dimensions, ImageUsage, ImmutableImage};
use vulkano::instance::{ApplicationInfo, Instance, InstanceExtensions, PhysicalDevice, Version}; use vulkano::instance::{ApplicationInfo, Instance, InstanceExtensions, PhysicalDevice, Version};
use vulkano::instance::debug::{DebugCallback, MessageSeverity, MessageType}; use vulkano::instance::debug::{DebugCallback, MessageSeverity, MessageType};
use vulkano::pipeline::viewport::Viewport;
use vulkano::sampler::{Filter, MipmapMode, Sampler, SamplerAddressMode}; use vulkano::sampler::{Filter, MipmapMode, Sampler, SamplerAddressMode};
use vulkano::swapchain::{AcquireError, FullscreenExclusive, PresentMode, Surface, SurfaceTransform, Swapchain, SwapchainCreationError}; use vulkano::swapchain::{AcquireError, FullscreenExclusive, PresentMode, Surface, SurfaceTransform, Swapchain, SwapchainCreationError};
use vulkano::swapchain; use vulkano::swapchain;
@@ -37,6 +36,8 @@ use crate::vulkan::{gameobject::{GameObject, GameObjectHandle}};
pub mod pipelines; pub mod pipelines;
pub mod gameobject; pub mod gameobject;
pub mod mesh; pub mod mesh;
mod renderpass;
mod framebuffers;
const VALIDATION_LAYERS: &[&str] = &[ const VALIDATION_LAYERS: &[&str] = &[
"VK_LAYER_KHRONOS_validation" "VK_LAYER_KHRONOS_validation"
@@ -113,7 +114,8 @@ pub struct VulkanRenderer {
pub debug_callback: Option<DebugCallback>, pub debug_callback: Option<DebugCallback>,
pub previous_frame_end: Option<Box<dyn GpuFuture>>, pub previous_frame_end: Option<Box<dyn GpuFuture>>,
pub uniform_buffers: Vec<Arc<CpuAccessibleBuffer<vs::ty::ObjectUniformData>>>, pub uniform_buffers: Vec<Arc<CpuAccessibleBuffer<vs::ty::ObjectUniformData>>>,
pub msaa_sample_count: u32, pub line_vertex_buffer: Arc<CpuAccessibleBuffer<[LinePoint]>>,
pub render_config: RenderConfig
} }
impl VulkanRenderer { impl VulkanRenderer {
@@ -238,62 +240,7 @@ impl VulkanRenderer {
}; };
// Render pass // Render pass
let render_pass: Arc<dyn RenderPassAbstract + Send + Sync> = if render_config.msaa_samples > 0 { let render_pass = renderpass::create_render_pass(device.clone(), &render_config, swapchain.format());
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 sampler = Sampler::new(device.clone(), Filter::Linear, Filter::Linear, let sampler = Sampler::new(device.clone(), Filter::Linear, Filter::Linear,
MipmapMode::Nearest, SamplerAddressMode::Repeat, SamplerAddressMode::Repeat, MipmapMode::Nearest, SamplerAddressMode::Repeat, SamplerAddressMode::Repeat,
@@ -303,22 +250,18 @@ impl VulkanRenderer {
let pipelines: Vec<Box<dyn Drawcall>> = vec![ let pipelines: Vec<Box<dyn Drawcall>> = vec![
Box::new(DefaultShader::new(device.clone(), render_pass.clone())), 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 // Dynamic viewports allow us to recreate just the viewport when the window is resized
// Otherwise we would have to recreate the whole pipeline. // 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 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 // 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. // 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 mut uniform_buffers = Vec::new();
let uniform_buffer = vs::ty::ObjectUniformData { let uniform_buffer = vs::ty::ObjectUniformData {
@@ -352,7 +295,8 @@ impl VulkanRenderer {
dynamic_state, pipelines, uniform_buffers, dynamic_state, pipelines, uniform_buffers,
surface, swapchain, render_pass, queue, surface, swapchain, render_pass, queue,
recreate_swapchain: false, debug_callback, previous_frame_end, recreate_swapchain: false, debug_callback, previous_frame_end,
msaa_sample_count: render_config.msaa_samples render_config,
line_vertex_buffer,
}, events_loop) }, events_loop)
} }
@@ -360,7 +304,7 @@ impl VulkanRenderer {
// General setup // General setup
let mut builder = AutoCommandBufferBuilder::primary_simultaneous_use(self.device.clone(), self.queue.family()).unwrap(); 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(); 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(); 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 { } 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(); 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()) Arc::new(builder.build().unwrap())
} }
fn create_msaa_buffers(device: Arc<Device>, dimensions: [u32; 2], swapchain: &Arc<Swapchain<Window>>, sample_count: u32) -> Vec<Arc<AttachmentImage>> {
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) { pub fn render_loop(self: &mut Self, new_ubo: vs::ty::ObjectUniformData) {
// cleanup previous frame // cleanup previous frame
@@ -405,16 +343,17 @@ impl VulkanRenderer {
Err(err) => panic!("{:?}", err), Err(err) => panic!("{:?}", err),
}; };
let msaa_buffers = if self.msaa_sample_count > 0 { self.render_pass = renderpass::create_render_pass(self.device.clone(), &self.render_config, new_swapchain.format());
Some(Self::create_msaa_buffers(self.device.clone(), self.game_data.dimensions, &new_swapchain, self.msaa_sample_count))
} else { self.pipelines = vec![
None 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; self.swapchain = new_swapchain;
// Because framebuffers contains an Arc on the old swapchain, we need to // Because framebuffers contains an Arc on the old swapchain, we need to
// recreate framebuffers as well. // 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; self.recreate_swapchain = false;
} }
@@ -586,45 +525,3 @@ pub fn start_event_loop(mut renderer: VulkanRenderer, mut game: Box<dyn Game>, e
}); });
} }
/// This method is called once during initialization, then again whenever the window is resized
fn window_size_dependent_setup(device: Arc<Device>, images: &[Arc<SwapchainImage<Window>>], msaa_buffers: Option<Vec<Arc<AttachmentImage>>>, msaa_sample_count: u32, render_pass: Arc<dyn RenderPassAbstract + Send + Sync>, dynamic_state: &mut DynamicState) -> Vec<Arc<dyn FramebufferAbstract + Send + Sync>> {
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<dyn FramebufferAbstract + Send + Sync>);
} else {
framebuffers.push(Arc::new(Framebuffer::start(render_pass.clone())
.add(image_buffer.clone()).unwrap()
.add(depth_image.clone()).unwrap()
.build().unwrap()
) as Arc<dyn FramebufferAbstract + Send + Sync>);
}
}
framebuffers
}

64
src/vulkan/renderpass.rs Normal file
View File

@@ -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<Device>, render_config: &RenderConfig, swapchain_format: Format) -> Arc<dyn RenderPassAbstract + Send + Sync> {
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())
}
}