refucktor

ecs
q3k 2020-01-18 21:03:31 +01:00
parent 14238117a1
commit 77c88aa27a
6 changed files with 294 additions and 248 deletions

View File

@ -26,7 +26,7 @@ impl Renderer {
pub fn initialize() -> Self {
let mut instance = vulkan::Instance::new("threepy".to_string());
let (events_loop, surface) = Self::init_window(instance.get_vulkan());
instance.bind_surface(&surface);
instance.use_surface(&surface);
Self {
instance,
events_loop,

View File

@ -1,247 +0,0 @@
use std::collections::HashSet;
use std::sync::Arc;
use log;
use vulkano::instance as vi;
use vulkano::device as vd;
use vulkano::swapchain as vs;
use vulkano::image as vm;
use vulkano::format as vf;
use vulkano::sync as vy;
struct QueueFamilyIndices {
graphics_family: i32,
present_family: i32,
}
impl QueueFamilyIndices {
fn new() -> Self {
Self {
graphics_family: -1,
present_family: -1,
}
}
fn is_complete(&self) -> bool {
self.graphics_family >= 0 && self.present_family >= 0
}
}
const VERSION: vi::Version = vi::Version { major: 1, minor: 0, patch: 0};
pub struct Instance<WT> {
debug_callback: vi::debug::DebugCallback,
vulkan: Arc<vi::Instance>,
physical_device_ix: Option<usize>,
device: Option<Arc<vd::Device>>,
surface: Option<Arc<vs::Surface<WT>>>,
graphics_queue: Option<Arc<vd::Queue>>,
present_queue: Option<Arc<vd::Queue>>,
swap_chain: Option<Arc<vs::Swapchain<WT>>>,
swap_chain_images: Option<Vec<Arc<vm::SwapchainImage<WT>>>>,
}
impl<WT> Instance<WT> {
pub fn new(name: String) -> Self {
let ai = vi::ApplicationInfo {
application_name: Some(name.clone().into()),
application_version: Some(VERSION),
engine_name: Some(name.clone().into()),
engine_version: Some(VERSION),
};
let exts = Self::required_instance_extensions();
let layers = ["VK_LAYER_LUNARG_standard_validation"];
let vulkan = vi::Instance::new(Some(&ai), &exts, layers.iter().cloned()).expect("could not create vulkan instance");
let debug_callback = Self::init_debug_callback(&vulkan);
Self {
debug_callback,
vulkan,
physical_device_ix: None,
device: None,
surface: None,
graphics_queue: None,
present_queue: None,
swap_chain: None,
swap_chain_images: None,
}
}
pub fn bind_surface(&mut self, surface: &Arc<vs::Surface<WT>>) {
let physical_device_ix = Self::pick_physical_device(&self.vulkan, &surface);
let physical_device = vi::PhysicalDevice::from_index(&self.vulkan, physical_device_ix).unwrap();
let indices = Self::find_queue_families(&surface, &physical_device).unwrap();
let families = [indices.graphics_family, indices.present_family];
use std::iter::FromIterator;
let unique_queue_families: HashSet<&i32> = HashSet::from_iter(families.iter());
let queue_priority = 1.0;
let qf = unique_queue_families.iter().map(|i| {
(physical_device.queue_families().nth(**i as usize).unwrap(), queue_priority)
});
let (device, mut queues) = vd::Device::new(
physical_device,
&vd::Features::none(),
&Self::required_device_extensions(),
qf
).expect("could not create logical device and queues");
let graphics_queue = queues.next().unwrap();
let present_queue = queues.next().unwrap_or_else(|| graphics_queue.clone());
self.physical_device_ix = Some(physical_device_ix);
self.device = Some(device.clone());
self.surface = Some(surface.clone());
self.graphics_queue = Some(graphics_queue.clone());
self.present_queue = Some(present_queue.clone());
let capabilities = surface.capabilities(physical_device).expect("could not get capabilities");
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,
.. vm::ImageUsage::none()
};
let sharing: vy::SharingMode = if indices.graphics_family != indices.present_family {
vec![&graphics_queue, &present_queue].as_slice().into()
} else {
(&graphics_queue).into()
};
let (swap_chain, images) = vs::Swapchain::new(
device.clone(),
surface.clone(),
image_count,
surface_format.0,
extent,
1,
image_usage,
sharing,
capabilities.current_transform,
vs::CompositeAlpha::Opaque,
present_mode,
true,
None,
).expect("could not create swap chain");
self.swap_chain = Some(swap_chain);
self.swap_chain_images = Some(images);
}
pub fn get_vulkan(&self) -> Arc<vi::Instance> {
self.vulkan.clone()
}
fn find_queue_families(surface: &Arc<vs::Surface<WT>>, device: &vi::PhysicalDevice) -> Option<QueueFamilyIndices> {
let mut indices = QueueFamilyIndices::new();
for (i, queue_family) in device.queue_families().enumerate() {
if queue_family.supports_graphics() {
indices.graphics_family = i as i32
}
if surface.is_supported(queue_family).unwrap() {
indices.present_family = i as i32
}
if indices.is_complete() {
return Some(indices);
}
}
None
}
fn pick_physical_device(instance: &Arc<vi::Instance>, surface: &Arc<vs::Surface<WT>>) -> usize {
vi::PhysicalDevice::enumerate(&instance)
.position(|dev| Self::is_device_suitable(surface, &dev))
.expect("could not find suitable GPU")
}
fn is_device_suitable(surface: &Arc<vs::Surface<WT>>, device: &vi::PhysicalDevice) -> bool {
if !Self::find_queue_families(surface, &device).is_some() {
return false;
}
let available_extensions = vd::DeviceExtensions::supported_by_device(*device);
let want_extensions = Self::required_device_extensions();
if available_extensions.intersection(&want_extensions) != want_extensions {
return false;
}
let capabilities = surface.capabilities(*device).expect("could not get device capabilities");
if capabilities.supported_formats.is_empty() {
return false;
}
if !capabilities.present_modes.iter().next().is_some() {
return false;
}
true
}
fn required_device_extensions() -> vd::DeviceExtensions {
vd::DeviceExtensions {
khr_swapchain: true,
.. vd::DeviceExtensions::none()
}
}
fn required_instance_extensions() -> vi::InstanceExtensions {
let mut exts = vulkano_win::required_extensions();
exts.ext_debug_report = true;
exts
}
fn init_debug_callback(instance: &Arc<vi::Instance>) -> vi::debug::DebugCallback {
let mt = vi::debug::MessageTypes {
error: true,
warning: true,
performance_warning: true,
information: true,
debug: true,
};
vi::debug::DebugCallback::new(&instance, mt, |msg| {
log::info!("validation layer: {:?}", msg.description);
}).expect("could not create debug callback")
}
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
}
}
fn choose_swap_extent(capabilities: &vs::Capabilities) -> [u32; 2] {
capabilities.current_extent.expect("could not get current extent")
}
}

View File

@ -0,0 +1,92 @@
use std::collections::HashSet;
use std::sync::Arc;
use vulkano::instance as vi;
use vulkano::device as vd;
use vulkano::swapchain as vs;
// A Binding to a surface, resulting in concrete device information.
pub struct Binding<WT> {
instance: Arc<vi::Instance>,
physical_device_ix: usize,
pub device: Arc<vd::Device>,
pub surface: Arc<vs::Surface<WT>>,
pub graphics_queue: Arc<vd::Queue>,
pub present_queue: Arc<vd::Queue>,
}
impl <WT> Binding<WT> {
pub fn physical_device(&self) -> vi::PhysicalDevice {
vi::PhysicalDevice::from_index(&self.instance, self.physical_device_ix).unwrap()
}
pub fn new(instance: &Arc<vi::Instance>, surface: &Arc<vs::Surface<WT>>) -> Self {
let physical_device_ix = Self::pick_physical_device(instance, &surface);
let physical_device = vi::PhysicalDevice::from_index(instance, physical_device_ix).unwrap();
let indices = super::qfi::QueueFamilyIndices::find(&surface, &physical_device).unwrap();
let families = [indices.graphics_family, indices.present_family];
use std::iter::FromIterator;
let unique_queue_families: HashSet<&i32> = HashSet::from_iter(families.iter());
let queue_priority = 1.0;
let qf = unique_queue_families.iter().map(|i| {
(physical_device.queue_families().nth(**i as usize).unwrap(), queue_priority)
});
let (device, mut queues) = vd::Device::new(
physical_device,
&vd::Features::none(),
&required_device_extensions(),
qf
).expect("could not create logical device and queues");
let graphics_queue = queues.next().unwrap();
let present_queue = queues.next().unwrap_or_else(|| graphics_queue.clone());
Self {
instance: instance.clone(),
physical_device_ix,
device: device.clone(),
surface: surface.clone(),
graphics_queue: graphics_queue.clone(),
present_queue: present_queue.clone(),
}
}
fn pick_physical_device(instance: &Arc<vi::Instance>, surface: &Arc<vs::Surface<WT>>) -> usize {
vi::PhysicalDevice::enumerate(&instance)
.position(|dev| Self::is_device_suitable(surface, &dev))
.expect("could not find suitable GPU")
}
fn is_device_suitable(surface: &Arc<vs::Surface<WT>>, device: &vi::PhysicalDevice) -> bool {
if !super::qfi::QueueFamilyIndices::find(surface, &device).is_some() {
return false;
}
let available_extensions = vd::DeviceExtensions::supported_by_device(*device);
let want_extensions = required_device_extensions();
if available_extensions.intersection(&want_extensions) != want_extensions {
return false;
}
let capabilities = surface.capabilities(*device).expect("could not get device capabilities");
if capabilities.supported_formats.is_empty() {
return false;
}
if !capabilities.present_modes.iter().next().is_some() {
return false;
}
true
}
}
fn required_device_extensions() -> vd::DeviceExtensions {
vd::DeviceExtensions {
khr_swapchain: true,
.. vd::DeviceExtensions::none()
}
}

77
src/render/vulkan/mod.rs Normal file
View File

@ -0,0 +1,77 @@
use std::sync::Arc;
use log;
use vulkano::instance as vi;
use vulkano::swapchain as vs;
mod binding;
mod swapchains;
mod qfi;
const VERSION: vi::Version = vi::Version { major: 1, minor: 0, patch: 0};
pub struct Instance<WT> {
debug_callback: vi::debug::DebugCallback,
vulkan: Arc<vi::Instance>,
binding: Option<binding::Binding<WT>>,
swapchains: Option<swapchains::Swapchains<WT>>,
}
impl<WT> Instance<WT> {
pub fn new(name: String) -> Self {
let ai = vi::ApplicationInfo {
application_name: Some(name.clone().into()),
application_version: Some(VERSION),
engine_name: Some(name.clone().into()),
engine_version: Some(VERSION),
};
let exts = Self::required_instance_extensions();
let layers = ["VK_LAYER_LUNARG_standard_validation"];
let vulkan = vi::Instance::new(Some(&ai), &exts, layers.iter().cloned()).expect("could not create vulkan instance");
let debug_callback = Self::init_debug_callback(&vulkan);
Self {
debug_callback,
vulkan,
binding: None,
swapchains: None,
}
}
pub fn get_vulkan(&self) -> Arc<vi::Instance> {
self.vulkan.clone()
}
pub fn use_surface(&mut self, surface: &Arc<vs::Surface<WT>>) {
self.binding = Some(binding::Binding::new(&self.vulkan, &surface));
self.swapchains = Some(swapchains::Swapchains::new(self.binding.as_ref().unwrap()));
log::info!("Bound to Vulkan Device: {}", self.binding.as_ref().unwrap().physical_device().name());
}
fn required_instance_extensions() -> vi::InstanceExtensions {
let mut exts = vulkano_win::required_extensions();
exts.ext_debug_report = true;
exts
}
fn init_debug_callback(instance: &Arc<vi::Instance>) -> vi::debug::DebugCallback {
let mt = vi::debug::MessageTypes {
error: true,
warning: true,
performance_warning: true,
information: true,
debug: true,
};
vi::debug::DebugCallback::new(&instance, mt, |msg| {
log::debug!("validation layer: {:?}", msg.description);
}).expect("could not create debug callback")
}
}

39
src/render/vulkan/qfi.rs Normal file
View File

@ -0,0 +1,39 @@
use std::sync::Arc;
use vulkano::instance as vi;
use vulkano::swapchain as vs;
pub struct QueueFamilyIndices {
pub graphics_family: i32,
pub present_family: i32,
}
impl QueueFamilyIndices {
fn new() -> Self {
Self {
graphics_family: -1,
present_family: -1,
}
}
fn is_complete(&self) -> bool {
self.graphics_family >= 0 && self.present_family >= 0
}
pub fn find<WT>(surface: &Arc<vs::Surface<WT>>, device: &vi::PhysicalDevice) -> Option<Self> {
let mut indices = QueueFamilyIndices::new();
for (i, queue_family) in device.queue_families().enumerate() {
if queue_family.supports_graphics() {
indices.graphics_family = i as i32
}
if surface.is_supported(queue_family).unwrap() {
indices.present_family = i as i32
}
if indices.is_complete() {
return Some(indices);
}
}
None
}
}

View File

@ -0,0 +1,85 @@
use std::sync::Arc;
use vulkano::swapchain as vs;
use vulkano::image as vm;
use vulkano::format as vf;
use vulkano::sync as vy;
pub struct Swapchains<WT> {
chain: Arc<vs::Swapchain<WT>>,
images: Vec<Arc<vm::SwapchainImage<WT>>>,
}
impl<WT> Swapchains<WT> {
pub fn new(binding: &super::binding::Binding<WT>) -> Self {
let physical_device = binding.physical_device();
let capabilities = binding.surface.capabilities(physical_device).expect("could not get capabilities");
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,
.. vm::ImageUsage::none()
};
let indices = super::qfi::QueueFamilyIndices::find(&binding.surface, &physical_device).unwrap();
let sharing: vy::SharingMode = if indices.graphics_family != indices.present_family {
vec![&binding.graphics_queue, &binding.present_queue].as_slice().into()
} else {
(&binding.graphics_queue).into()
};
let (chain, images) = vs::Swapchain::new(
binding.device.clone(),
binding.surface.clone(),
image_count,
surface_format.0,
extent,
1,
image_usage,
sharing,
capabilities.current_transform,
vs::CompositeAlpha::Opaque,
present_mode,
true,
None,
).expect("could not create swap chain");
Self {
chain, images
}
}
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
}
}
fn choose_swap_extent(capabilities: &vs::Capabilities) -> [u32; 2] {
capabilities.current_extent.expect("could not get current extent")
}
}