abrasion/engine/render/vulkan/swapchain_binding.rs

221 lines
8.2 KiB
Rust
Raw Normal View History

2020-07-23 22:53:33 +00:00
// Copyright 2020 Sergiusz 'q3k' Bazanski <q3k@q3k.org>
//
// This file is part of Abrasion.
//
// Abrasion 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, version 3.
//
// Abrasion 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
// Abrasion. If not, see <https://www.gnu.org/licenses/>.
2020-01-18 20:03:31 +00:00
use std::sync::Arc;
use vulkano::swapchain as vs;
use vulkano::image as vm;
2020-07-23 21:27:27 +00:00
use vulkano::image::traits::ImageAccess;
2020-01-18 20:03:31 +00:00
use vulkano::format as vf;
2020-01-20 03:01:36 +00:00
use vulkano::framebuffer as vfb;
2020-01-18 20:03:31 +00:00
use vulkano::sync as vy;
2020-01-20 03:01:36 +00:00
pub struct SwapchainBinding<WT> {
2020-01-19 15:59:05 +00:00
pub chain: Arc<vs::Swapchain<WT>>,
pub images: Vec<Arc<vm::SwapchainImage<WT>>>,
2020-01-20 03:01:36 +00:00
pub render_pass: Arc<dyn vfb::RenderPassAbstract + Send + Sync>,
pub framebuffers: Vec<Arc<dyn vfb::FramebufferAbstract + Send + Sync>>,
2020-01-18 20:03:31 +00:00
}
2020-01-20 03:01:36 +00:00
impl<WT: 'static + Send + Sync> SwapchainBinding<WT> {
pub fn new(
2020-03-15 16:02:49 +00:00
surface_binding: &super::surface_binding::SurfaceBinding<WT>,
2020-01-20 03:01:36 +00:00
previous: Option<&SwapchainBinding<WT>>
) -> Self {
let physical_device = surface_binding.physical_device();
let capabilities = surface_binding.surface.capabilities(physical_device).expect("could not get capabilities");
2020-01-18 20:03:31 +00:00
let surface_format = Self::choose_swap_surface_format(&capabilities.supported_formats);
let present_mode = Self::choose_swap_present_mode(capabilities.present_modes);
let extent = Self::choose_swap_extent(&capabilities);
let mut image_count = capabilities.min_image_count + 1;
if let Some(max_image_count) = capabilities.max_image_count {
if image_count > max_image_count {
image_count = max_image_count;
}
}
let image_usage = vm::ImageUsage {
color_attachment: true,
2020-07-23 21:27:27 +00:00
transfer_destination: true,
2020-01-18 20:03:31 +00:00
.. vm::ImageUsage::none()
};
2020-01-20 03:01:36 +00:00
let indices = super::qfi::QueueFamilyIndices::find(&surface_binding.surface, &physical_device).unwrap();
2020-01-18 20:03:31 +00:00
let sharing: vy::SharingMode = if indices.graphics_family != indices.present_family {
2020-01-20 03:01:36 +00:00
vec![&surface_binding.graphics_queue, &surface_binding.present_queue].as_slice().into()
2020-01-18 20:03:31 +00:00
} else {
2020-01-20 03:01:36 +00:00
(&surface_binding.graphics_queue).into()
2020-01-18 20:03:31 +00:00
};
2020-01-19 22:21:27 +00:00
let prev = match previous {
None => None,
Some(p) => Some(p.chain.clone()),
};
2020-03-16 23:00:50 +00:00
let (chain, images) = match prev.as_ref() {
None => vs::Swapchain::new(
surface_binding.device.clone(),
surface_binding.surface.clone(),
image_count,
surface_format.0,
extent,
1,
image_usage,
sharing,
capabilities.current_transform,
vs::CompositeAlpha::Opaque,
present_mode,
vs::FullscreenExclusive::Default,
true,
vs::ColorSpace::SrgbNonLinear,
),
Some(p) => vs::Swapchain::with_old_swapchain(
surface_binding.device.clone(),
surface_binding.surface.clone(),
image_count,
surface_format.0,
extent,
1,
image_usage,
sharing,
capabilities.current_transform,
vs::CompositeAlpha::Opaque,
present_mode,
vs::FullscreenExclusive::Default,
true,
vs::ColorSpace::SrgbNonLinear,
p.clone(),
),
}.expect("could not create swap chain");
2020-01-18 20:03:31 +00:00
2020-01-20 20:29:28 +00:00
log::info!("Swap chain: present mode {:?}, {} images", present_mode, images.len());
2020-03-16 00:03:59 +00:00
let depth_format = Self::find_depth_format();
2020-07-23 21:27:27 +00:00
// TODO(q3k): make configurable and check with hardware
let sample_count = 8;
let depth_image = vm::AttachmentImage::multisampled_with_usage(
2020-03-16 00:03:59 +00:00
surface_binding.device.clone(),
chain.dimensions(),
2020-07-23 21:27:27 +00:00
sample_count,
2020-03-16 00:03:59 +00:00
depth_format,
vm::ImageUsage { depth_stencil_attachment: true, ..vm::ImageUsage::none() },
).unwrap();
2020-07-23 21:27:27 +00:00
let render_pass = Self::create_render_pass(surface_binding, chain.format(), depth_format, sample_count);
let framebuffers = Self::create_framebuffers(surface_binding, render_pass.clone(), images.clone(), depth_image, sample_count);
2020-01-20 03:01:36 +00:00
2020-01-18 20:03:31 +00:00
Self {
2020-01-20 03:01:36 +00:00
chain,
images,
render_pass,
framebuffers,
2020-01-18 20:03:31 +00:00
}
}
2020-01-20 03:01:36 +00:00
fn create_render_pass(
2020-03-15 16:02:49 +00:00
surface_binding: &super::surface_binding::SurfaceBinding<WT>,
2020-03-16 00:03:59 +00:00
color_format: vf::Format,
depth_format: vf::Format,
2020-07-23 21:27:27 +00:00
sample_count: u32,
2020-01-20 03:01:36 +00:00
) -> Arc<dyn vfb::RenderPassAbstract + Send + Sync> {
let device = surface_binding.device.clone();
Arc::new(vulkano::single_pass_renderpass!(device,
attachments: {
2020-07-23 21:27:27 +00:00
multisample_color: {
2020-01-20 03:01:36 +00:00
load: Clear,
store: Store,
format: color_format,
2020-07-23 21:27:27 +00:00
samples: sample_count,
2020-03-16 00:03:59 +00:00
},
2020-07-23 21:27:27 +00:00
multisample_depth: {
2020-03-16 00:03:59 +00:00
load: Clear,
store: DontCare,
format: depth_format,
2020-07-23 21:27:27 +00:00
samples: sample_count,
2020-03-16 00:03:59 +00:00
initial_layout: ImageLayout::Undefined,
final_layout: ImageLayout::DepthStencilAttachmentOptimal,
2020-07-23 21:27:27 +00:00
},
resolve_color: {
load: DontCare,
store: Store,
format: color_format,
samples: 1,
initial_layout: ImageLayout::Undefined,
2020-01-20 03:01:36 +00:00
}
},
pass: {
2020-07-23 21:27:27 +00:00
color: [multisample_color],
depth_stencil: {multisample_depth},
resolve: [resolve_color]
2020-01-20 03:01:36 +00:00
}
).unwrap())
}
fn create_framebuffers(
2020-07-23 21:27:27 +00:00
surface_binding: &super::surface_binding::SurfaceBinding<WT>,
2020-01-20 03:01:36 +00:00
render_pass: Arc<dyn vfb::RenderPassAbstract + Send + Sync>,
images: Vec<Arc<vm::SwapchainImage<WT>>>,
2020-03-16 00:03:59 +00:00
depth_image: Arc<vm::AttachmentImage<vf::Format>>,
2020-07-23 21:27:27 +00:00
sample_count: u32,
2020-01-20 03:01:36 +00:00
) -> Vec<Arc<dyn vfb::FramebufferAbstract + Send + Sync>> {
2020-07-23 21:27:27 +00:00
let device = surface_binding.device.clone();
2020-01-20 03:01:36 +00:00
images.iter()
.map(|image| {
2020-07-23 21:27:27 +00:00
let dim = image.dimensions().width_height();
let multisample_image = vm::AttachmentImage::transient_multisampled(device.clone(), dim, sample_count, image.format()).unwrap();
2020-01-20 03:01:36 +00:00
let fba: Arc<dyn vfb::FramebufferAbstract + Send + Sync> = Arc::new(vfb::Framebuffer::start(render_pass.clone())
2020-07-23 21:27:27 +00:00
.add(multisample_image.clone()).unwrap()
2020-03-16 00:03:59 +00:00
.add(depth_image.clone()).unwrap()
2020-07-23 21:27:27 +00:00
.add(image.clone()).unwrap()
2020-01-20 03:01:36 +00:00
.build().unwrap());
fba
})
.collect::<Vec<_>>()
}
2020-01-18 20:03:31 +00:00
fn choose_swap_surface_format(available_formats: &[(vf::Format, vs::ColorSpace)]) -> (vf::Format, vs::ColorSpace) {
*available_formats.iter()
.find(|(format, color_space)|
*format == vf::Format::B8G8R8A8Unorm && *color_space == vs::ColorSpace::SrgbNonLinear
)
.unwrap_or_else(|| &available_formats[0])
}
fn choose_swap_present_mode(available_present_modes: vs::SupportedPresentModes) -> vs::PresentMode {
if available_present_modes.mailbox {
vs::PresentMode::Mailbox
} else if available_present_modes.immediate {
vs::PresentMode::Immediate
} else {
vs::PresentMode::Fifo
}
//vs::PresentMode::Fifo
2020-01-18 20:03:31 +00:00
}
fn choose_swap_extent(capabilities: &vs::Capabilities) -> [u32; 2] {
capabilities.current_extent.expect("could not get current extent")
}
2020-03-16 00:03:59 +00:00
fn find_depth_format() -> vf::Format {
// TODO: actually do it
vf::Format::D16Unorm
}
2020-01-18 20:03:31 +00:00
}