iv/src/hal.rs
Steins7 ebc9299f33 Implemented dirty input system
+ added render thread
+ added control thread
* tweaked event_loop
2020-07-11 22:18:38 +02:00

499 lines
17 KiB
Rust

#[allow(unused_imports)]
use log::{debug, error, info, trace, warn};
use std::{
mem::ManuallyDrop,
iter,
};
use core::ptr::read;
use gfx_hal::{
Instance,
device::Device,
queue::QueueGroup,
Backend,
pool::CommandPool,
pso::Rect,
};
use gfx_backend_vulkan as vk_back;
use winit::window::Window;
pub mod render;
#[derive(Debug)]
pub struct HalState {
//items need to communicate with the GPU
instance: ManuallyDrop<<vk_back::Backend as Backend>::Instance>,
surface: ManuallyDrop<<vk_back::Backend as Backend>::Surface>,
adapter: ManuallyDrop<gfx_hal::adapter::Adapter<vk_back::Backend>>,
device: vk_back::Device,
queue_group: ManuallyDrop<QueueGroup<vk_back::Backend>>,
render_pass: ManuallyDrop<<vk_back::Backend as Backend>::RenderPass>,
swapchain: ManuallyDrop<<vk_back::Backend as Backend>::Swapchain>,
extent: gfx_hal::window::Extent2D,
format: gfx_hal::format::Format,
render_area: Rect,
//items needed to render the images
sems_image_available: Vec<<vk_back::Backend as Backend>::Semaphore>,
sems_render_finished: Vec<<vk_back::Backend as Backend>::Semaphore>,
fences: Vec<<vk_back::Backend as Backend>::Fence>,
image_views: Vec<<vk_back::Backend as Backend>::ImageView>,
framebuffers: Vec<<vk_back::Backend as Backend>::Framebuffer>,
command_pool: ManuallyDrop<<vk_back::Backend as Backend>::CommandPool>,
command_buffers: Vec<<vk_back::Backend as Backend>::CommandBuffer>,
//items needed to keep track of the images
image_count: usize,
current_image: usize,
}
impl core::ops::Drop for HalState {
//----------------------------------------------------------------------------------------------
fn drop(&mut self) {
let _ = self.device.wait_idle();
//destroy all underlying ressources
debug!("Destroying HAL ressources");
unsafe {
self.command_pool.free(self.command_buffers.drain(..));
self.device.destroy_command_pool(
ManuallyDrop::into_inner(read(&mut self.command_pool)));
for buffer in self.framebuffers.drain(..) {
self.device.destroy_framebuffer(buffer);
}
for view in self.image_views.drain(..) {
self.device.destroy_image_view(view);
}
for fence in self.fences.drain(..) {
self.device.destroy_fence(fence);
}
for sem in self.sems_image_available.drain(..) {
self.device.destroy_semaphore(sem);
}
for sem in self.sems_render_finished.drain(..) {
self.device.destroy_semaphore(sem);
}
self.device.destroy_swapchain(ManuallyDrop::into_inner(read(&mut self.swapchain)));
self.device.destroy_render_pass(ManuallyDrop::into_inner(read(&mut self.render_pass)));
ManuallyDrop::drop(&mut self.queue_group);
ManuallyDrop::drop(&mut self.adapter);
self.instance.destroy_surface(ManuallyDrop::into_inner(read(&mut self.surface)));
ManuallyDrop::drop(&mut self.instance);
}
info!("HAL ressources destroyed");
}
}
impl HalState {
//----------------------------------------------------------------------------------------------
pub fn recreate_swapchain(&mut self) -> Result<(), &'static str> {
use gfx_hal::window::{
SwapchainConfig,
Surface,
};
debug!("Recreating swapchain");
//destroying previous swapchain
unsafe {
for buffer in self.framebuffers.drain(..) {
self.device.destroy_framebuffer(buffer);
}
for view in self.image_views.drain(..) {
self.device.destroy_image_view(view);
}
self.device.destroy_swapchain(ManuallyDrop::into_inner(read(&mut self.swapchain)));
}
let capabilities = self.surface.capabilities(&self.adapter.physical_device);
info!("{:#?}", capabilities);
//creating new swapchain
let swapchain_config = SwapchainConfig::from_caps(&capabilities, self.format, self.extent);
info!("{:?}", swapchain_config);
let (swapchain, backbuffer) = unsafe {
self.device
.create_swapchain(&mut self.surface, swapchain_config, None)
.map_err(|_| "Failed to create swapchain and backbuffer")?
};
let image_views : Vec<_> = {
use gfx_hal::{
image::{ViewKind, SubresourceRange},
format::{Swizzle, Aspects},
};
backbuffer
.iter()
.map(|img| unsafe {
self.device
.create_image_view(
&img,
ViewKind::D2,
self.format,
Swizzle::NO,
SubresourceRange {
aspects : Aspects::COLOR,
levels : 0..1,
layers : 0..1,
},
)
.map_err(|_| "Could not create ImageViews")
})
.collect::<Result<Vec<_>, &str>>()?
};
let framebuffers: Vec<_> = {
image_views
.iter()
.map(|image_view|
unsafe {
self.device
.create_framebuffer(&self.render_pass,
iter::once(image_view),
self.extent.to_extent())
.map_err(|_| "Could not create FrameBuffer")
},
)
.collect::<Result<Vec<_>, &str>>()?
};
self.swapchain = ManuallyDrop::new(swapchain);
self.image_views = image_views;
self.framebuffers = framebuffers;
Ok(())
}
//----------------------------------------------------------------------------------------------
pub fn new(window: &Window) -> Result<HalState, &'static str> {
use gfx_hal::adapter::Gpu;
// create top level
let instance = vk_back::Instance::create("IV", 1)
.map_err(|_| "Could not create instance")?;
let mut surface = unsafe {
instance
.create_surface(window)
.map_err(|_| "Could not create Surface")?
};
let (adapter, device, queue_group) = {
use gfx_hal::{
window::Surface,
queue::family::QueueFamily,
};
// find a adapter with a suitable queue family
// TODO add weight for adapters
let adapter =
Instance::enumerate_adapters(&instance)
.into_iter();
// .find(|a| {
// a.queue_families
// .iter()
// .any(|qf|
// QueueFamily::queue_type(qf).supports_graphics()
// && Surface::supports_queue_family(&surface, &qf)
// )})
// .ok_or("Could not find a graphical adapter")?;
debug!("Adapters : {:#?}", adapter);
let adapter =
Instance::enumerate_adapters(&instance)
.into_iter()
.find(|a| {
a.queue_families
.iter()
.any(|qf|
QueueFamily::queue_type(qf).supports_graphics()
&& Surface::supports_queue_family(&surface, &qf)
)})
.ok_or("Could not find a graphical adapter")?;
info!("Selected adapter : {}", adapter.info.name);
// get the suitable queue family index
let queue_family = adapter
.queue_families
.iter()
.find(|qf|
QueueFamily::queue_type(*qf).supports_graphics()
&& Surface::supports_queue_family(&surface, &qf))
.ok_or("Could not find suitable queue_family")?;
// get the related physical device and queue family list
let Gpu {device, queue_groups} = unsafe {
use gfx_hal::{
adapter::PhysicalDevice,
Features,
};
adapter
.physical_device
.open(&[(&queue_family, &[1.0; 1])], Features::empty())
.map_err(|_| "Could not open physical device")?
};
// retrieve the selected queue family
let queue_group = queue_groups
.into_iter()
.find(|qg| qg.family == queue_family.id())
.ok_or("Could not take ownership of the queue")?;
// check our harvest
if queue_group.queues.len() <= 0 {
return Err("The QueueGroup does not have any CommandQueues available");
};
(adapter, device, queue_group)
};
let (swapchain, extent, backbuffer, format, image_count) = {
use gfx_hal::window::{
SwapchainConfig,
Surface,
};
let capabilities = surface.capabilities(&adapter.physical_device);
debug!("{:#?}", capabilities);
// select optimal presentation mode (vsync, triple buffuring, ...)
let present_mode = {
use gfx_hal::window::PresentMode;
[PresentMode::MAILBOX, PresentMode::FIFO,
PresentMode::RELAXED, PresentMode::IMMEDIATE]
.iter()
.cloned()
.find(|pm| capabilities.present_modes.contains(*pm))
.ok_or("No PresentMode found")?
};
// select optimal alpha composition
// let composite_alpha_mode = {
// use gfx_hal::window::CompositeAlphaMode;
//
// [CompositeAlphaMode::OPAQUE, CompositeAlphaMode::INHERIT,
// CompositeAlphaMode::PREMULTIPLIED, CompositeAlphaMode::POSTMULTIPLIED]
// .iter()
// .cloned()
// .find(|cam| capabilities.composite_alpha_modes.contains(*cam))
// .ok_or("No CompositeAlphaMode found")?
// };
// select optimal format (sRGB)
let format = {
use gfx_hal::format::{Format, ChannelType};
match surface.supported_formats(&adapter.physical_device) {
None => Format::Rgba8Srgb,
Some(formats) => formats
.iter()
.find(|f| f.base_format().1 == ChannelType::Srgb)
.cloned()
.ok_or("Could no find suitabe format")?
}};
let extent = capabilities.extents.end().clone();
// verify swapchain size
let image_count = {
use gfx_hal::window::PresentMode;
capabilities.image_count.end()
.min(capabilities.image_count.start()
.max(match present_mode {
PresentMode::MAILBOX => &3,
PresentMode::FIFO => &2,
_ => &1,
})).clone()
};
debug!("image count : {}", image_count);
// // a surface support at least one layer
// let image_layers = 1;
//
// // verify surface compatibility
// let image_usage = {
// use gfx_hal::image::Usage;
//
// if capabilities.usage.contains(Usage::COLOR_ATTACHMENT) {
// Ok(Usage::COLOR_ATTACHMENT)
// } else {
// Err("This surface does not support color")
// }
// }?;
let swapchain_config = SwapchainConfig::from_caps(&capabilities, format, extent);
debug!("{:?}", swapchain_config);
let (swapchain, backbuffer) = unsafe {
device
.create_swapchain(&mut surface, swapchain_config, None)
.map_err(|_| "Failed to create swapchain and backbuffer")?
};
(swapchain, extent, backbuffer, format, image_count as usize)
};
// creating semaphores and fences
let (sems_image_available, sems_render_finished, fences) = {
let mut sems_image_available : Vec<<vk_back::Backend as Backend>::Semaphore> = vec![];
let mut sems_render_finished : Vec<<vk_back::Backend as Backend>::Semaphore> = vec![];
let mut fences :Vec<<vk_back::Backend as Backend>::Fence> = vec![];
for _ in 0..image_count {
sems_image_available
.push(device
.create_semaphore()
.map_err(|_| "Could not create sempahore")?
);
sems_render_finished
.push(device
.create_semaphore()
.map_err(|_| "Could not create sempahore")?
);
fences
.push(device
.create_fence(true)
.map_err(|_| "Could not create fence")?
);
}
(sems_image_available, sems_render_finished, fences)
};
// creating RenderPass
let render_pass = {
use gfx_hal::{
pass::{Attachment, AttachmentOps, AttachmentLoadOp, AttachmentStoreOp, SubpassDesc},
image::Layout,
};
let color_attachment = Attachment {
format : Some(format),
samples : 1,
ops : AttachmentOps {
load : AttachmentLoadOp::Clear,
store : AttachmentStoreOp::Store,
},
stencil_ops : AttachmentOps::DONT_CARE,
layouts : (Layout::Undefined..Layout::Present),
};
let subpass = SubpassDesc {
colors : &[(0, Layout::ColorAttachmentOptimal)],
depth_stencil : None,
inputs : &[],
resolves : &[],
preserves : &[],
};
unsafe {
device.create_render_pass(&[color_attachment], &[subpass], &[])
.map_err(|_| "Could not create render pass")?
}
};
// add ImageView "headers" to images in BackBuffer
let image_views : Vec<_> = {
use gfx_hal::{
image::{ViewKind, SubresourceRange},
format::{Swizzle, Aspects},
};
backbuffer
.iter()
.map(|img| unsafe {
device
.create_image_view(
&img,
ViewKind::D2,
format,
Swizzle::NO,
SubresourceRange {
aspects : Aspects::COLOR,
levels : 0..1,
layers : 0..1,
},
)
.map_err(|_| "Could not create ImageViews")
})
.collect::<Result<Vec<_>, &str>>()?
};
let framebuffers: Vec<_> = {
image_views
.iter()
.map(|image_view|
unsafe {
device
.create_framebuffer(&render_pass, vec![image_view], extent.to_extent())
.map_err(|_| "Could not create FrameBuffer")
},
)
.collect::<Result<Vec<_>, &str>>()?
};
let mut command_pool = unsafe {
use gfx_hal::pool::CommandPoolCreateFlags;
device
.create_command_pool(queue_group.family, CommandPoolCreateFlags::RESET_INDIVIDUAL)
.map_err(|_| "Could not create CommandPool")?
};
let command_buffers: Vec<_> = unsafe {
use gfx_hal::command::Level;
framebuffers
.iter()
.map(|_| command_pool.allocate_one(Level::Primary))
.collect()
};
info!("HAL successfully initialized");
Ok(
HalState {
instance: ManuallyDrop::new(instance),
surface: ManuallyDrop::new(surface),
adapter: ManuallyDrop::new(adapter),
device: device,
queue_group: ManuallyDrop::new(queue_group),
render_pass: ManuallyDrop::new(render_pass),
swapchain: ManuallyDrop::new(swapchain),
extent: extent,
format: format,
render_area: Rect{x: 0, y: 0, w: 1280, h: 720},
sems_image_available,
sems_render_finished,
fences,
image_views,
framebuffers,
command_pool: ManuallyDrop::new(command_pool),
command_buffers,
image_count,
current_image: 0,
}
)
}
}