Modularize AppData struct
This commit is contained in:
parent
71449ae29b
commit
3dbc718446
84
src/app.rs
84
src/app.rs
@ -1,9 +1,7 @@
|
|||||||
|
mod data;
|
||||||
mod functions;
|
mod functions;
|
||||||
use functions::{
|
|
||||||
create_command_buffers, create_command_pool, create_framebuffers, create_instance,
|
use data::AppData;
|
||||||
create_logical_device, create_pipeline, create_render_pass, create_swapchain,
|
|
||||||
create_swapchain_image_views, create_sync_objects, create_vertex_buffer, pick_physical_device,
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::VALIDATION_ENABLED;
|
use crate::VALIDATION_ENABLED;
|
||||||
use ::anyhow::{anyhow, Result};
|
use ::anyhow::{anyhow, Result};
|
||||||
@ -54,21 +52,21 @@ impl App {
|
|||||||
let entry = Entry::new(loader).map_err(|b| anyhow!("{}", b))?;
|
let entry = Entry::new(loader).map_err(|b| anyhow!("{}", b))?;
|
||||||
|
|
||||||
let mut data = AppData::default();
|
let mut data = AppData::default();
|
||||||
let instance = create_instance(window, &entry, &mut data)?;
|
let instance = data.create_instance(window, &entry)?;
|
||||||
data.surface = vk_window::create_surface(&instance, window)?;
|
data.surface = vk_window::create_surface(&instance, window)?;
|
||||||
|
|
||||||
pick_physical_device(&instance, &mut data)?;
|
data.pick_physical_device(&instance)?;
|
||||||
let device = create_logical_device(&instance, &mut data)?;
|
let device = data.create_logical_device(&instance)?;
|
||||||
|
|
||||||
create_swapchain(window, &instance, &device, &mut data)?;
|
data.create_swapchain(window, &instance, &device)?;
|
||||||
create_swapchain_image_views(&device, &mut data)?;
|
data.create_swapchain_image_views(&device)?;
|
||||||
create_render_pass(&instance, &device, &mut data)?;
|
data.create_render_pass(&instance, &device)?;
|
||||||
create_pipeline(&device, &mut data)?;
|
data.create_pipeline(&device)?;
|
||||||
create_framebuffers(&device, &mut data)?;
|
data.create_framebuffers(&device)?;
|
||||||
create_command_pool(&instance, &device, &mut data)?;
|
data.create_command_pool(&instance, &device)?;
|
||||||
create_vertex_buffer(&instance, &device, &mut data)?;
|
data.create_vertex_buffer(&instance, &device)?;
|
||||||
create_command_buffers(&device, &mut data)?;
|
data.create_command_buffers(&device)?;
|
||||||
create_sync_objects(&device, &mut data)?;
|
data.create_sync_objects(&device)?;
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
_entry: entry,
|
_entry: entry,
|
||||||
@ -214,12 +212,13 @@ impl App {
|
|||||||
self.device.device_wait_idle()?;
|
self.device.device_wait_idle()?;
|
||||||
self.destroy_swapchain();
|
self.destroy_swapchain();
|
||||||
|
|
||||||
create_swapchain(window, &self.instance, &self.device, &mut self.data)?;
|
self.data
|
||||||
create_swapchain_image_views(&self.device, &mut self.data)?;
|
.create_swapchain(window, &self.instance, &self.device)?;
|
||||||
create_render_pass(&self.instance, &self.device, &mut self.data)?;
|
self.data.create_swapchain_image_views(&self.device)?;
|
||||||
create_pipeline(&self.device, &mut self.data)?;
|
self.data.create_render_pass(&self.instance, &self.device)?;
|
||||||
create_framebuffers(&self.device, &mut self.data)?;
|
self.data.create_pipeline(&self.device)?;
|
||||||
create_command_buffers(&self.device, &mut self.data)?;
|
self.data.create_framebuffers(&self.device)?;
|
||||||
|
self.data.create_command_buffers(&self.device)?;
|
||||||
|
|
||||||
self.data
|
self.data
|
||||||
.images_in_flight
|
.images_in_flight
|
||||||
@ -230,45 +229,6 @@ impl App {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The Vulkan handles and associated properties used by our Vulkan app.
|
|
||||||
#[derive(Clone, Debug, Default)]
|
|
||||||
pub struct AppData {
|
|
||||||
// Debug
|
|
||||||
messenger: vk::DebugUtilsMessengerEXT,
|
|
||||||
// Surface
|
|
||||||
surface: vk::SurfaceKHR,
|
|
||||||
// Physical Device / Logical Device
|
|
||||||
physical_device: vk::PhysicalDevice,
|
|
||||||
graphics_queue: vk::Queue,
|
|
||||||
present_queue: vk::Queue,
|
|
||||||
// Swapchain
|
|
||||||
swapchain_format: vk::Format,
|
|
||||||
swapchain_extent: vk::Extent2D,
|
|
||||||
swapchain: vk::SwapchainKHR,
|
|
||||||
swapchain_images: Vec<vk::Image>,
|
|
||||||
swapchain_image_views: Vec<vk::ImageView>,
|
|
||||||
// Pipeline
|
|
||||||
render_pass: vk::RenderPass,
|
|
||||||
pipeline_layout: vk::PipelineLayout,
|
|
||||||
pipeline: vk::Pipeline,
|
|
||||||
// Framebuffers
|
|
||||||
framebuffers: Vec<vk::Framebuffer>,
|
|
||||||
// Command Pool
|
|
||||||
command_pool: vk::CommandPool,
|
|
||||||
// Buffers
|
|
||||||
vertex_buffer: vk::Buffer,
|
|
||||||
vertex_buffer_memory: vk::DeviceMemory,
|
|
||||||
// Command Buffers
|
|
||||||
command_buffers: Vec<vk::CommandBuffer>,
|
|
||||||
// Sync Objects
|
|
||||||
image_available_semaphores: Vec<vk::Semaphore>,
|
|
||||||
render_finished_semaphores: Vec<vk::Semaphore>,
|
|
||||||
in_flight_fences: Vec<vk::Fence>,
|
|
||||||
images_in_flight: Vec<vk::Fence>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl AppData {}
|
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
#[error("Missing {0}.")]
|
#[error("Missing {0}.")]
|
||||||
pub struct SuitabilityError(pub &'static str);
|
pub struct SuitabilityError(pub &'static str);
|
||||||
|
670
src/app/data.rs
Normal file
670
src/app/data.rs
Normal file
@ -0,0 +1,670 @@
|
|||||||
|
use super::functions::*;
|
||||||
|
use super::*;
|
||||||
|
use crate::VALIDATION_ENABLED;
|
||||||
|
|
||||||
|
use ::anyhow::{anyhow, Result};
|
||||||
|
use ::log::*;
|
||||||
|
use ::std::collections::HashSet;
|
||||||
|
use ::std::ffi::CStr;
|
||||||
|
use ::std::os::raw::c_void;
|
||||||
|
use ::std::ptr::copy_nonoverlapping as memcpy;
|
||||||
|
use ::vulkanalia::prelude::v1_0::*;
|
||||||
|
use ::vulkanalia::vk::ExtDebugUtilsExtension;
|
||||||
|
use ::vulkanalia::window as vk_window;
|
||||||
|
use ::winit::window::Window;
|
||||||
|
|
||||||
|
extern "system" fn debug_callback(
|
||||||
|
severity: vk::DebugUtilsMessageSeverityFlagsEXT,
|
||||||
|
type_: vk::DebugUtilsMessageTypeFlagsEXT,
|
||||||
|
data: *const vk::DebugUtilsMessengerCallbackDataEXT,
|
||||||
|
_: *mut c_void,
|
||||||
|
) -> vk::Bool32 {
|
||||||
|
let data = unsafe { *data };
|
||||||
|
let message = unsafe { CStr::from_ptr(data.message) }.to_string_lossy();
|
||||||
|
|
||||||
|
if severity >= vk::DebugUtilsMessageSeverityFlagsEXT::ERROR {
|
||||||
|
error!("({:?}) {}", type_, message);
|
||||||
|
} else if severity >= vk::DebugUtilsMessageSeverityFlagsEXT::WARNING {
|
||||||
|
warn!("({:?}) {}", type_, message);
|
||||||
|
} else if severity >= vk::DebugUtilsMessageSeverityFlagsEXT::INFO {
|
||||||
|
debug!("({:?}) {}", type_, message);
|
||||||
|
} else {
|
||||||
|
trace!("({:?}) {}", type_, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
vk::FALSE
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The Vulkan handles and associated properties used by our Vulkan app.
|
||||||
|
#[derive(Clone, Debug, Default)]
|
||||||
|
pub struct AppData {
|
||||||
|
// Debug
|
||||||
|
pub(crate) messenger: vk::DebugUtilsMessengerEXT,
|
||||||
|
// Surface
|
||||||
|
pub(crate) surface: vk::SurfaceKHR,
|
||||||
|
// Physical Device / Logical Device
|
||||||
|
pub(crate) physical_device: vk::PhysicalDevice,
|
||||||
|
pub(crate) graphics_queue: vk::Queue,
|
||||||
|
pub(crate) present_queue: vk::Queue,
|
||||||
|
// Swapchain
|
||||||
|
pub(crate) swapchain_format: vk::Format,
|
||||||
|
pub(crate) swapchain_extent: vk::Extent2D,
|
||||||
|
pub(crate) swapchain: vk::SwapchainKHR,
|
||||||
|
pub(crate) swapchain_images: Vec<vk::Image>,
|
||||||
|
pub(crate) swapchain_image_views: Vec<vk::ImageView>,
|
||||||
|
// Pipeline
|
||||||
|
pub(crate) render_pass: vk::RenderPass,
|
||||||
|
pub(crate) pipeline_layout: vk::PipelineLayout,
|
||||||
|
pub(crate) pipeline: vk::Pipeline,
|
||||||
|
// Framebuffers
|
||||||
|
pub(crate) framebuffers: Vec<vk::Framebuffer>,
|
||||||
|
// Command Pool
|
||||||
|
pub(crate) command_pool: vk::CommandPool,
|
||||||
|
// Buffers
|
||||||
|
pub(crate) vertex_buffer: vk::Buffer,
|
||||||
|
pub(crate) vertex_buffer_memory: vk::DeviceMemory,
|
||||||
|
// Command Buffers
|
||||||
|
pub(crate) command_buffers: Vec<vk::CommandBuffer>,
|
||||||
|
// Sync Objects
|
||||||
|
pub(crate) image_available_semaphores: Vec<vk::Semaphore>,
|
||||||
|
pub(crate) render_finished_semaphores: Vec<vk::Semaphore>,
|
||||||
|
pub(crate) in_flight_fences: Vec<vk::Fence>,
|
||||||
|
pub(crate) images_in_flight: Vec<vk::Fence>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AppData {
|
||||||
|
pub unsafe fn create_instance(&mut self, window: &Window, entry: &Entry) -> Result<Instance> {
|
||||||
|
// Application Info
|
||||||
|
let application_info = vk::ApplicationInfo::builder()
|
||||||
|
.application_name(b"Vulkan Tutorial\0")
|
||||||
|
.application_version(vk::make_version(1, 0, 0))
|
||||||
|
.engine_name(b"No Engine\0")
|
||||||
|
.engine_version(vk::make_version(1, 0, 0))
|
||||||
|
.api_version(vk::make_version(1, 0, 0));
|
||||||
|
|
||||||
|
// Layers
|
||||||
|
let available_layers = entry
|
||||||
|
.enumerate_instance_layer_properties()?
|
||||||
|
.iter()
|
||||||
|
.map(|l| l.layer_name)
|
||||||
|
.collect::<HashSet<_>>();
|
||||||
|
|
||||||
|
if VALIDATION_ENABLED && !available_layers.contains(&VALIDATION_LAYER) {
|
||||||
|
return Err(anyhow!("Validation layer requested but not supported."));
|
||||||
|
}
|
||||||
|
|
||||||
|
let layers = if VALIDATION_ENABLED {
|
||||||
|
vec![VALIDATION_LAYER.as_ptr()]
|
||||||
|
} else {
|
||||||
|
Vec::new()
|
||||||
|
};
|
||||||
|
|
||||||
|
// Extensions
|
||||||
|
let mut extensions = vk_window::get_required_instance_extensions(window)
|
||||||
|
.iter()
|
||||||
|
.map(|e| e.as_ptr())
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
if VALIDATION_ENABLED {
|
||||||
|
extensions.push(vk::EXT_DEBUG_UTILS_EXTENSION.name.as_ptr());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compatibility extension for macOS
|
||||||
|
let flags = if (cfg!(target_os = "macos") && entry.version()? >= PORTABILITY_MACOS_VERSION)
|
||||||
|
|| entry
|
||||||
|
.enumerate_instance_extension_properties(None)?
|
||||||
|
.iter()
|
||||||
|
.any(|e| e.extension_name == vk::KHR_PORTABILITY_ENUMERATION_EXTENSION.name)
|
||||||
|
{
|
||||||
|
info!("Enabling extensions for macOS compatibility.");
|
||||||
|
extensions.push(vk::KHR_PORTABILITY_ENUMERATION_EXTENSION.name.as_ptr());
|
||||||
|
extensions.push(
|
||||||
|
vk::KHR_GET_PHYSICAL_DEVICE_PROPERTIES2_EXTENSION
|
||||||
|
.name
|
||||||
|
.as_ptr(),
|
||||||
|
);
|
||||||
|
vk::InstanceCreateFlags::ENUMERATE_PORTABILITY_KHR
|
||||||
|
} else {
|
||||||
|
vk::InstanceCreateFlags::empty()
|
||||||
|
};
|
||||||
|
|
||||||
|
// Create
|
||||||
|
let mut info = vk::InstanceCreateInfo::builder()
|
||||||
|
.application_info(&application_info)
|
||||||
|
.enabled_layer_names(&layers)
|
||||||
|
.enabled_extension_names(&extensions)
|
||||||
|
.flags(flags);
|
||||||
|
|
||||||
|
let mut debug_info = vk::DebugUtilsMessengerCreateInfoEXT::builder()
|
||||||
|
.message_severity(vk::DebugUtilsMessageSeverityFlagsEXT::all())
|
||||||
|
.message_type(vk::DebugUtilsMessageTypeFlagsEXT::all())
|
||||||
|
.user_callback(Some(debug_callback));
|
||||||
|
|
||||||
|
if VALIDATION_ENABLED {
|
||||||
|
info = info.push_next(&mut debug_info);
|
||||||
|
}
|
||||||
|
|
||||||
|
let instance = entry.create_instance(&info, None)?;
|
||||||
|
|
||||||
|
// Messenger
|
||||||
|
if VALIDATION_ENABLED {
|
||||||
|
self.messenger = instance.create_debug_utils_messenger_ext(&debug_info, None)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(instance)
|
||||||
|
}
|
||||||
|
|
||||||
|
//================================================
|
||||||
|
// Physical Device
|
||||||
|
//================================================
|
||||||
|
|
||||||
|
pub(super) unsafe fn pick_physical_device(&mut self, instance: &Instance) -> Result<()> {
|
||||||
|
for physical_device in instance.enumerate_physical_devices()? {
|
||||||
|
let properties = instance.get_physical_device_properties(physical_device);
|
||||||
|
|
||||||
|
if let Err(error) = self.check_physical_device(instance, physical_device) {
|
||||||
|
warn!(
|
||||||
|
"Skipping physical device (`{}`): {}",
|
||||||
|
properties.device_name, error
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
info!("Selected physical device (`{}`).", properties.device_name);
|
||||||
|
self.physical_device = physical_device;
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Err(anyhow!("Failed to find suitable physical device."))
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn check_physical_device(
|
||||||
|
&self,
|
||||||
|
instance: &Instance,
|
||||||
|
physical_device: vk::PhysicalDevice,
|
||||||
|
) -> Result<()> {
|
||||||
|
QueueFamilyIndices::get(instance, self, physical_device)?;
|
||||||
|
check_physical_device_extensions(instance, physical_device)?;
|
||||||
|
|
||||||
|
let support = SwapchainSupport::get(instance, self, physical_device)?;
|
||||||
|
if support.formats.is_empty() || support.present_modes.is_empty() {
|
||||||
|
return Err(anyhow!(SuitabilityError("Insufficient swapchain support.")));
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
//================================================
|
||||||
|
// Logical Device
|
||||||
|
//================================================
|
||||||
|
|
||||||
|
pub(super) unsafe fn create_logical_device(&mut self, instance: &Instance) -> Result<Device> {
|
||||||
|
// Queue Create Infos
|
||||||
|
let indices = QueueFamilyIndices::get(instance, self, self.physical_device)?;
|
||||||
|
|
||||||
|
let mut unique_indices = HashSet::new();
|
||||||
|
unique_indices.insert(indices.graphics);
|
||||||
|
unique_indices.insert(indices.present);
|
||||||
|
|
||||||
|
let queue_priorities = &[1.0];
|
||||||
|
let queue_infos = unique_indices
|
||||||
|
.iter()
|
||||||
|
.map(|i| {
|
||||||
|
vk::DeviceQueueCreateInfo::builder()
|
||||||
|
.queue_family_index(*i)
|
||||||
|
.queue_priorities(queue_priorities)
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
// Layers
|
||||||
|
let layers = if VALIDATION_ENABLED {
|
||||||
|
vec![VALIDATION_LAYER.as_ptr()]
|
||||||
|
} else {
|
||||||
|
vec![]
|
||||||
|
};
|
||||||
|
|
||||||
|
// Extensions
|
||||||
|
let mut extensions = DEVICE_EXTENSIONS
|
||||||
|
.iter()
|
||||||
|
.map(|n| n.as_ptr())
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
// mac OS Metal -> Vulkan rendering fix
|
||||||
|
if instance
|
||||||
|
.enumerate_device_extension_properties(self.physical_device, None)?
|
||||||
|
.iter()
|
||||||
|
.any(|e| e.extension_name == vk::KHR_PORTABILITY_SUBSET_EXTENSION.name)
|
||||||
|
{
|
||||||
|
extensions.push(vk::KHR_PORTABILITY_SUBSET_EXTENSION.name.as_ptr());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Features
|
||||||
|
let features = vk::PhysicalDeviceFeatures::builder();
|
||||||
|
|
||||||
|
// Create
|
||||||
|
let info = vk::DeviceCreateInfo::builder()
|
||||||
|
.queue_create_infos(&queue_infos)
|
||||||
|
.enabled_layer_names(&layers)
|
||||||
|
.enabled_extension_names(&extensions)
|
||||||
|
.enabled_features(&features);
|
||||||
|
|
||||||
|
let device = instance.create_device(self.physical_device, &info, None)?;
|
||||||
|
|
||||||
|
// Queues
|
||||||
|
self.graphics_queue = device.get_device_queue(indices.graphics, 0);
|
||||||
|
self.present_queue = device.get_device_queue(indices.present, 0);
|
||||||
|
|
||||||
|
Ok(device)
|
||||||
|
}
|
||||||
|
|
||||||
|
//================================================
|
||||||
|
// Swapchain
|
||||||
|
//================================================
|
||||||
|
|
||||||
|
pub(super) unsafe fn create_swapchain(
|
||||||
|
&mut self,
|
||||||
|
window: &Window,
|
||||||
|
instance: &Instance,
|
||||||
|
device: &Device,
|
||||||
|
) -> Result<()> {
|
||||||
|
let indices = QueueFamilyIndices::get(instance, self, self.physical_device)?;
|
||||||
|
let support = SwapchainSupport::get(instance, self, self.physical_device)?;
|
||||||
|
|
||||||
|
let surface_format = get_swapchain_surface_format(&support.formats);
|
||||||
|
let present_mode = get_swapchain_present_mode(&support.present_modes);
|
||||||
|
let extent = get_swapchain_extent(window, support.capabilities);
|
||||||
|
|
||||||
|
let mut image_count = support.capabilities.min_image_count + 1;
|
||||||
|
if support.capabilities.max_image_count != 0
|
||||||
|
&& image_count > support.capabilities.max_image_count
|
||||||
|
{
|
||||||
|
image_count = support.capabilities.max_image_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut queue_family_indices = vec![];
|
||||||
|
let image_sharing_mode = if indices.graphics != indices.present {
|
||||||
|
queue_family_indices.push(indices.graphics);
|
||||||
|
queue_family_indices.push(indices.present);
|
||||||
|
vk::SharingMode::CONCURRENT
|
||||||
|
} else {
|
||||||
|
vk::SharingMode::EXCLUSIVE
|
||||||
|
};
|
||||||
|
|
||||||
|
let info = vk::SwapchainCreateInfoKHR::builder()
|
||||||
|
.surface(self.surface)
|
||||||
|
.min_image_count(image_count)
|
||||||
|
.image_format(surface_format.format)
|
||||||
|
.image_color_space(surface_format.color_space)
|
||||||
|
.image_extent(extent)
|
||||||
|
.image_array_layers(1)
|
||||||
|
.image_usage(vk::ImageUsageFlags::COLOR_ATTACHMENT)
|
||||||
|
.image_sharing_mode(image_sharing_mode)
|
||||||
|
.queue_family_indices(&queue_family_indices)
|
||||||
|
.pre_transform(support.capabilities.current_transform)
|
||||||
|
.composite_alpha(vk::CompositeAlphaFlagsKHR::OPAQUE)
|
||||||
|
.present_mode(present_mode)
|
||||||
|
.clipped(true)
|
||||||
|
.old_swapchain(vk::SwapchainKHR::null());
|
||||||
|
|
||||||
|
self.swapchain = device.create_swapchain_khr(&info, None)?;
|
||||||
|
self.swapchain_images = device.get_swapchain_images_khr(self.swapchain)?;
|
||||||
|
self.swapchain_format = surface_format.format;
|
||||||
|
self.swapchain_extent = extent;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) unsafe fn create_swapchain_image_views(&mut self, device: &Device) -> Result<()> {
|
||||||
|
self.swapchain_image_views = self
|
||||||
|
.swapchain_images
|
||||||
|
.iter()
|
||||||
|
.map(|i| {
|
||||||
|
let components = vk::ComponentMapping::builder()
|
||||||
|
.r(vk::ComponentSwizzle::IDENTITY)
|
||||||
|
.g(vk::ComponentSwizzle::IDENTITY)
|
||||||
|
.b(vk::ComponentSwizzle::IDENTITY)
|
||||||
|
.a(vk::ComponentSwizzle::IDENTITY);
|
||||||
|
|
||||||
|
let subresource_range = vk::ImageSubresourceRange::builder()
|
||||||
|
.aspect_mask(vk::ImageAspectFlags::COLOR)
|
||||||
|
.base_mip_level(0)
|
||||||
|
.level_count(1)
|
||||||
|
.base_array_layer(0)
|
||||||
|
.layer_count(1);
|
||||||
|
|
||||||
|
let info = vk::ImageViewCreateInfo::builder()
|
||||||
|
.image(*i)
|
||||||
|
.view_type(vk::ImageViewType::_2D)
|
||||||
|
.format(self.swapchain_format)
|
||||||
|
.components(components)
|
||||||
|
.subresource_range(subresource_range);
|
||||||
|
|
||||||
|
device.create_image_view(&info, None)
|
||||||
|
})
|
||||||
|
.collect::<Result<Vec<_>, _>>()?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
//================================================
|
||||||
|
// Pipeline
|
||||||
|
//================================================
|
||||||
|
|
||||||
|
pub(super) unsafe fn create_render_pass(
|
||||||
|
&mut self,
|
||||||
|
_instance: &Instance,
|
||||||
|
device: &Device,
|
||||||
|
) -> Result<()> {
|
||||||
|
let color_attachment = vk::AttachmentDescription::builder()
|
||||||
|
.format(self.swapchain_format)
|
||||||
|
.samples(vk::SampleCountFlags::_1)
|
||||||
|
.load_op(vk::AttachmentLoadOp::CLEAR)
|
||||||
|
.store_op(vk::AttachmentStoreOp::STORE)
|
||||||
|
.stencil_load_op(vk::AttachmentLoadOp::DONT_CARE)
|
||||||
|
.stencil_store_op(vk::AttachmentStoreOp::DONT_CARE)
|
||||||
|
.initial_layout(vk::ImageLayout::UNDEFINED)
|
||||||
|
.final_layout(vk::ImageLayout::PRESENT_SRC_KHR);
|
||||||
|
|
||||||
|
// Subpasses
|
||||||
|
let color_attachment_ref = vk::AttachmentReference::builder()
|
||||||
|
.attachment(0)
|
||||||
|
.layout(vk::ImageLayout::COLOR_ATTACHMENT_OPTIMAL);
|
||||||
|
let color_attachments = &[color_attachment_ref];
|
||||||
|
let subpass = vk::SubpassDescription::builder()
|
||||||
|
.pipeline_bind_point(vk::PipelineBindPoint::GRAPHICS)
|
||||||
|
.color_attachments(color_attachments);
|
||||||
|
let dependency = vk::SubpassDependency::builder()
|
||||||
|
.src_subpass(vk::SUBPASS_EXTERNAL)
|
||||||
|
.dst_subpass(0)
|
||||||
|
.src_stage_mask(vk::PipelineStageFlags::COLOR_ATTACHMENT_OUTPUT)
|
||||||
|
.src_access_mask(vk::AccessFlags::empty())
|
||||||
|
.dst_stage_mask(vk::PipelineStageFlags::COLOR_ATTACHMENT_OUTPUT)
|
||||||
|
.dst_access_mask(vk::AccessFlags::COLOR_ATTACHMENT_WRITE);
|
||||||
|
|
||||||
|
let attachments = &[color_attachment];
|
||||||
|
let subpasses = &[subpass];
|
||||||
|
let dependencies = &[dependency];
|
||||||
|
let info = vk::RenderPassCreateInfo::builder()
|
||||||
|
.attachments(attachments)
|
||||||
|
.subpasses(subpasses)
|
||||||
|
.dependencies(dependencies);
|
||||||
|
|
||||||
|
self.render_pass = device.create_render_pass(&info, None)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) unsafe fn create_pipeline(&mut self, device: &Device) -> Result<()> {
|
||||||
|
let vert = include_bytes!("../../shaders/vert.spv");
|
||||||
|
let frag = include_bytes!("../../shaders/frag.spv");
|
||||||
|
|
||||||
|
let vert_shader_module = create_shader_module(device, &vert[..])?;
|
||||||
|
let frag_shader_module = create_shader_module(device, &frag[..])?;
|
||||||
|
|
||||||
|
let vert_stage = vk::PipelineShaderStageCreateInfo::builder()
|
||||||
|
.stage(vk::ShaderStageFlags::VERTEX)
|
||||||
|
.module(vert_shader_module)
|
||||||
|
.name(b"main\0");
|
||||||
|
|
||||||
|
let frag_stage = vk::PipelineShaderStageCreateInfo::builder()
|
||||||
|
.stage(vk::ShaderStageFlags::FRAGMENT)
|
||||||
|
.module(frag_shader_module)
|
||||||
|
.name(b"main\0");
|
||||||
|
|
||||||
|
let binding_descriptions = &[Vertex::binding_description()];
|
||||||
|
let attribute_descriptions = Vertex::attribute_descriptions();
|
||||||
|
let vertex_input_state = vk::PipelineVertexInputStateCreateInfo::builder()
|
||||||
|
.vertex_binding_descriptions(binding_descriptions)
|
||||||
|
.vertex_attribute_descriptions(&attribute_descriptions);
|
||||||
|
|
||||||
|
let input_assembly_state = vk::PipelineInputAssemblyStateCreateInfo::builder()
|
||||||
|
.topology(vk::PrimitiveTopology::TRIANGLE_LIST)
|
||||||
|
.primitive_restart_enable(false);
|
||||||
|
|
||||||
|
let viewport = vk::Viewport::builder()
|
||||||
|
.x(0.0)
|
||||||
|
.y(0.0)
|
||||||
|
.width(self.swapchain_extent.width as f32)
|
||||||
|
.height(self.swapchain_extent.height as f32)
|
||||||
|
.min_depth(0.0)
|
||||||
|
.max_depth(1.0);
|
||||||
|
|
||||||
|
let scissor = vk::Rect2D::builder()
|
||||||
|
.offset(vk::Offset2D { x: 0, y: 0 })
|
||||||
|
.extent(self.swapchain_extent);
|
||||||
|
|
||||||
|
let viewports = &[viewport];
|
||||||
|
let scissors = &[scissor];
|
||||||
|
let viewport_state = vk::PipelineViewportStateCreateInfo::builder()
|
||||||
|
.viewports(viewports)
|
||||||
|
.scissors(scissors);
|
||||||
|
|
||||||
|
let rasterization_state = vk::PipelineRasterizationStateCreateInfo::builder()
|
||||||
|
.depth_clamp_enable(false)
|
||||||
|
.rasterizer_discard_enable(false)
|
||||||
|
.polygon_mode(vk::PolygonMode::FILL)
|
||||||
|
.line_width(1.0)
|
||||||
|
.cull_mode(vk::CullModeFlags::BACK)
|
||||||
|
.front_face(vk::FrontFace::CLOCKWISE)
|
||||||
|
.depth_bias_enable(false);
|
||||||
|
|
||||||
|
let multisample_state = vk::PipelineMultisampleStateCreateInfo::builder()
|
||||||
|
.sample_shading_enable(false)
|
||||||
|
.rasterization_samples(vk::SampleCountFlags::_1);
|
||||||
|
|
||||||
|
let attachment = vk::PipelineColorBlendAttachmentState::builder()
|
||||||
|
.color_write_mask(vk::ColorComponentFlags::all())
|
||||||
|
.blend_enable(false)
|
||||||
|
.src_color_blend_factor(vk::BlendFactor::ONE)
|
||||||
|
.dst_color_blend_factor(vk::BlendFactor::ZERO)
|
||||||
|
.color_blend_op(vk::BlendOp::ADD)
|
||||||
|
.src_alpha_blend_factor(vk::BlendFactor::ONE)
|
||||||
|
.dst_alpha_blend_factor(vk::BlendFactor::ZERO)
|
||||||
|
.alpha_blend_op(vk::BlendOp::ADD);
|
||||||
|
|
||||||
|
let attachments = &[attachment];
|
||||||
|
let color_blend_state = vk::PipelineColorBlendStateCreateInfo::builder()
|
||||||
|
.logic_op_enable(false)
|
||||||
|
.logic_op(vk::LogicOp::COPY)
|
||||||
|
.attachments(attachments)
|
||||||
|
.blend_constants([0.0, 0.0, 0.0, 0.0]);
|
||||||
|
|
||||||
|
let layout_info = vk::PipelineLayoutCreateInfo::builder();
|
||||||
|
self.pipeline_layout = device.create_pipeline_layout(&layout_info, None)?;
|
||||||
|
|
||||||
|
let stages = &[vert_stage, frag_stage];
|
||||||
|
let info = vk::GraphicsPipelineCreateInfo::builder()
|
||||||
|
.stages(stages)
|
||||||
|
.vertex_input_state(&vertex_input_state)
|
||||||
|
.input_assembly_state(&input_assembly_state)
|
||||||
|
.viewport_state(&viewport_state)
|
||||||
|
.rasterization_state(&rasterization_state)
|
||||||
|
.multisample_state(&multisample_state)
|
||||||
|
.color_blend_state(&color_blend_state)
|
||||||
|
.layout(self.pipeline_layout)
|
||||||
|
.render_pass(self.render_pass)
|
||||||
|
.subpass(0);
|
||||||
|
|
||||||
|
self.pipeline = device
|
||||||
|
.create_graphics_pipelines(vk::PipelineCache::null(), &[info], None)?
|
||||||
|
.0;
|
||||||
|
|
||||||
|
// Cleanup
|
||||||
|
device.destroy_shader_module(vert_shader_module, None);
|
||||||
|
device.destroy_shader_module(frag_shader_module, None);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) unsafe fn create_framebuffers(&mut self, device: &Device) -> Result<()> {
|
||||||
|
self.framebuffers = self
|
||||||
|
.swapchain_image_views
|
||||||
|
.iter()
|
||||||
|
.map(|i| {
|
||||||
|
let attachments = &[*i];
|
||||||
|
let create_info = vk::FramebufferCreateInfo::builder()
|
||||||
|
.render_pass(self.render_pass)
|
||||||
|
.attachments(attachments)
|
||||||
|
.width(self.swapchain_extent.width)
|
||||||
|
.height(self.swapchain_extent.height)
|
||||||
|
.layers(1);
|
||||||
|
|
||||||
|
device.create_framebuffer(&create_info, None)
|
||||||
|
})
|
||||||
|
.collect::<Result<Vec<_>, _>>()?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
//================================================
|
||||||
|
// Command Pool
|
||||||
|
//================================================
|
||||||
|
|
||||||
|
pub(super) unsafe fn create_command_pool(
|
||||||
|
&mut self,
|
||||||
|
instance: &Instance,
|
||||||
|
device: &Device,
|
||||||
|
) -> Result<()> {
|
||||||
|
let indices = QueueFamilyIndices::get(instance, self, self.physical_device)?;
|
||||||
|
|
||||||
|
let info = vk::CommandPoolCreateInfo::builder()
|
||||||
|
.flags(vk::CommandPoolCreateFlags::empty())
|
||||||
|
.queue_family_index(indices.graphics);
|
||||||
|
|
||||||
|
self.command_pool = device.create_command_pool(&info, None)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
//================================================
|
||||||
|
// Command Buffers
|
||||||
|
//================================================
|
||||||
|
|
||||||
|
pub(super) unsafe fn create_command_buffers(&mut self, device: &Device) -> Result<()> {
|
||||||
|
// Create the buffers
|
||||||
|
let allocate_info = vk::CommandBufferAllocateInfo::builder()
|
||||||
|
.command_pool(self.command_pool)
|
||||||
|
.level(vk::CommandBufferLevel::PRIMARY)
|
||||||
|
.command_buffer_count(self.framebuffers.len() as u32);
|
||||||
|
|
||||||
|
self.command_buffers = device.allocate_command_buffers(&allocate_info)?;
|
||||||
|
|
||||||
|
// Add commands
|
||||||
|
for (i, command_buffer) in self.command_buffers.iter().enumerate() {
|
||||||
|
let inheritance = vk::CommandBufferInheritanceInfo::builder();
|
||||||
|
|
||||||
|
let info = vk::CommandBufferBeginInfo::builder()
|
||||||
|
.flags(vk::CommandBufferUsageFlags::empty())
|
||||||
|
.inheritance_info(&inheritance);
|
||||||
|
|
||||||
|
device.begin_command_buffer(*command_buffer, &info)?;
|
||||||
|
|
||||||
|
let render_area = vk::Rect2D::builder()
|
||||||
|
.offset(vk::Offset2D::default())
|
||||||
|
.extent(self.swapchain_extent);
|
||||||
|
|
||||||
|
let color_clear_value = vk::ClearValue {
|
||||||
|
color: vk::ClearColorValue {
|
||||||
|
float32: [0.0, 0.0, 0.0, 1.0],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
let clear_values = &[color_clear_value];
|
||||||
|
let info = vk::RenderPassBeginInfo::builder()
|
||||||
|
.render_pass(self.render_pass)
|
||||||
|
.framebuffer(self.framebuffers[i])
|
||||||
|
.render_area(render_area)
|
||||||
|
.clear_values(clear_values);
|
||||||
|
|
||||||
|
device.cmd_begin_render_pass(*command_buffer, &info, vk::SubpassContents::INLINE);
|
||||||
|
device.cmd_bind_pipeline(
|
||||||
|
*command_buffer,
|
||||||
|
vk::PipelineBindPoint::GRAPHICS,
|
||||||
|
self.pipeline,
|
||||||
|
);
|
||||||
|
device.cmd_bind_vertex_buffers(*command_buffer, 0, &[self.vertex_buffer], &[0]);
|
||||||
|
device.cmd_draw(*command_buffer, 3, 1, 0, 0);
|
||||||
|
device.cmd_end_render_pass(*command_buffer);
|
||||||
|
|
||||||
|
device.end_command_buffer(*command_buffer)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) unsafe fn create_sync_objects(&mut self, device: &Device) -> Result<()> {
|
||||||
|
let semaphore_info = vk::SemaphoreCreateInfo::builder();
|
||||||
|
let fence_info = vk::FenceCreateInfo::builder().flags(vk::FenceCreateFlags::SIGNALED);
|
||||||
|
|
||||||
|
for _ in 0..MAX_FRAMES_IN_FLIGHT {
|
||||||
|
self.image_available_semaphores
|
||||||
|
.push(device.create_semaphore(&semaphore_info, None)?);
|
||||||
|
self.render_finished_semaphores
|
||||||
|
.push(device.create_semaphore(&semaphore_info, None)?);
|
||||||
|
|
||||||
|
self.in_flight_fences
|
||||||
|
.push(device.create_fence(&fence_info, None)?);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.images_in_flight = self
|
||||||
|
.swapchain_images
|
||||||
|
.iter()
|
||||||
|
.map(|_| vk::Fence::null())
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) unsafe fn create_vertex_buffer(
|
||||||
|
&mut self,
|
||||||
|
instance: &Instance,
|
||||||
|
device: &Device,
|
||||||
|
) -> Result<()> {
|
||||||
|
let buffer_info = vk::BufferCreateInfo::builder()
|
||||||
|
.size((size_of::<Vertex>() * VERTICES.len()) as u64)
|
||||||
|
.usage(vk::BufferUsageFlags::VERTEX_BUFFER)
|
||||||
|
.sharing_mode(vk::SharingMode::EXCLUSIVE);
|
||||||
|
|
||||||
|
self.vertex_buffer = device.create_buffer(&buffer_info, None)?;
|
||||||
|
|
||||||
|
let requirements = device.get_buffer_memory_requirements(self.vertex_buffer);
|
||||||
|
let memory_info = vk::MemoryAllocateInfo::builder()
|
||||||
|
.allocation_size(requirements.size)
|
||||||
|
.memory_type_index(self.get_memory_type_index(
|
||||||
|
instance,
|
||||||
|
vk::MemoryPropertyFlags::HOST_COHERENT | vk::MemoryPropertyFlags::HOST_VISIBLE,
|
||||||
|
requirements,
|
||||||
|
)?);
|
||||||
|
|
||||||
|
self.vertex_buffer_memory = device.allocate_memory(&memory_info, None)?;
|
||||||
|
|
||||||
|
device.bind_buffer_memory(self.vertex_buffer, self.vertex_buffer_memory, 0)?;
|
||||||
|
|
||||||
|
let memory = device.map_memory(
|
||||||
|
self.vertex_buffer_memory,
|
||||||
|
0,
|
||||||
|
buffer_info.size,
|
||||||
|
vk::MemoryMapFlags::empty(),
|
||||||
|
)?;
|
||||||
|
|
||||||
|
memcpy(VERTICES.as_ptr(), memory.cast(), VERTICES.len());
|
||||||
|
device.unmap_memory(self.vertex_buffer_memory);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn get_memory_type_index(
|
||||||
|
&self,
|
||||||
|
instance: &Instance,
|
||||||
|
properties: vk::MemoryPropertyFlags,
|
||||||
|
requirements: vk::MemoryRequirements,
|
||||||
|
) -> Result<u32> {
|
||||||
|
let memory = instance.get_physical_device_memory_properties(self.physical_device);
|
||||||
|
|
||||||
|
(0..memory.memory_type_count)
|
||||||
|
.find(|i| {
|
||||||
|
let suitable = (requirements.memory_type_bits & (1 << i)) != 0;
|
||||||
|
let memory_type = memory.memory_types[*i as usize];
|
||||||
|
suitable && memory_type.property_flags.contains(properties)
|
||||||
|
})
|
||||||
|
.ok_or_else(|| anyhow!("Failed to find suitable memory type."))
|
||||||
|
}
|
||||||
|
}
|
@ -1,162 +1,11 @@
|
|||||||
use super::*;
|
use super::*;
|
||||||
use crate::VALIDATION_ENABLED;
|
|
||||||
|
|
||||||
use ::anyhow::{anyhow, Result};
|
use ::anyhow::{anyhow, Result};
|
||||||
use ::log::*;
|
|
||||||
use ::std::collections::HashSet;
|
use ::std::collections::HashSet;
|
||||||
use ::std::ffi::CStr;
|
|
||||||
use ::std::os::raw::c_void;
|
|
||||||
use ::std::ptr::copy_nonoverlapping as memcpy;
|
|
||||||
use ::vulkanalia::prelude::v1_0::*;
|
use ::vulkanalia::prelude::v1_0::*;
|
||||||
use ::vulkanalia::window as vk_window;
|
|
||||||
use ::winit::window::Window;
|
use ::winit::window::Window;
|
||||||
|
|
||||||
extern "system" fn debug_callback(
|
pub unsafe fn check_physical_device_extensions(
|
||||||
severity: vk::DebugUtilsMessageSeverityFlagsEXT,
|
|
||||||
type_: vk::DebugUtilsMessageTypeFlagsEXT,
|
|
||||||
data: *const vk::DebugUtilsMessengerCallbackDataEXT,
|
|
||||||
_: *mut c_void,
|
|
||||||
) -> vk::Bool32 {
|
|
||||||
let data = unsafe { *data };
|
|
||||||
let message = unsafe { CStr::from_ptr(data.message) }.to_string_lossy();
|
|
||||||
|
|
||||||
if severity >= vk::DebugUtilsMessageSeverityFlagsEXT::ERROR {
|
|
||||||
error!("({:?}) {}", type_, message);
|
|
||||||
} else if severity >= vk::DebugUtilsMessageSeverityFlagsEXT::WARNING {
|
|
||||||
warn!("({:?}) {}", type_, message);
|
|
||||||
} else if severity >= vk::DebugUtilsMessageSeverityFlagsEXT::INFO {
|
|
||||||
debug!("({:?}) {}", type_, message);
|
|
||||||
} else {
|
|
||||||
trace!("({:?}) {}", type_, message);
|
|
||||||
}
|
|
||||||
|
|
||||||
vk::FALSE
|
|
||||||
}
|
|
||||||
|
|
||||||
//================================================
|
|
||||||
// Physical Device
|
|
||||||
//================================================
|
|
||||||
|
|
||||||
pub(super) unsafe fn create_instance(
|
|
||||||
window: &Window,
|
|
||||||
entry: &Entry,
|
|
||||||
data: &mut AppData,
|
|
||||||
) -> Result<Instance> {
|
|
||||||
// Application Info
|
|
||||||
let application_info = vk::ApplicationInfo::builder()
|
|
||||||
.application_name(b"Vulkan Tutorial\0")
|
|
||||||
.application_version(vk::make_version(1, 0, 0))
|
|
||||||
.engine_name(b"No Engine\0")
|
|
||||||
.engine_version(vk::make_version(1, 0, 0))
|
|
||||||
.api_version(vk::make_version(1, 0, 0));
|
|
||||||
|
|
||||||
// Layers
|
|
||||||
let available_layers = entry
|
|
||||||
.enumerate_instance_layer_properties()?
|
|
||||||
.iter()
|
|
||||||
.map(|l| l.layer_name)
|
|
||||||
.collect::<HashSet<_>>();
|
|
||||||
|
|
||||||
if VALIDATION_ENABLED && !available_layers.contains(&VALIDATION_LAYER) {
|
|
||||||
return Err(anyhow!("Validation layer requested but not supported."));
|
|
||||||
}
|
|
||||||
|
|
||||||
let layers = if VALIDATION_ENABLED {
|
|
||||||
vec![VALIDATION_LAYER.as_ptr()]
|
|
||||||
} else {
|
|
||||||
Vec::new()
|
|
||||||
};
|
|
||||||
|
|
||||||
// Extensions
|
|
||||||
let mut extensions = vk_window::get_required_instance_extensions(window)
|
|
||||||
.iter()
|
|
||||||
.map(|e| e.as_ptr())
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
if VALIDATION_ENABLED {
|
|
||||||
extensions.push(vk::EXT_DEBUG_UTILS_EXTENSION.name.as_ptr());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Compatibility extension for macOS
|
|
||||||
let flags = if (cfg!(target_os = "macos") && entry.version()? >= PORTABILITY_MACOS_VERSION)
|
|
||||||
|| entry
|
|
||||||
.enumerate_instance_extension_properties(None)?
|
|
||||||
.iter()
|
|
||||||
.any(|e| e.extension_name == vk::KHR_PORTABILITY_ENUMERATION_EXTENSION.name)
|
|
||||||
{
|
|
||||||
info!("Enabling extensions for macOS compatibility.");
|
|
||||||
extensions.push(vk::KHR_PORTABILITY_ENUMERATION_EXTENSION.name.as_ptr());
|
|
||||||
extensions.push(
|
|
||||||
vk::KHR_GET_PHYSICAL_DEVICE_PROPERTIES2_EXTENSION
|
|
||||||
.name
|
|
||||||
.as_ptr(),
|
|
||||||
);
|
|
||||||
vk::InstanceCreateFlags::ENUMERATE_PORTABILITY_KHR
|
|
||||||
} else {
|
|
||||||
vk::InstanceCreateFlags::empty()
|
|
||||||
};
|
|
||||||
|
|
||||||
// Create
|
|
||||||
let mut info = vk::InstanceCreateInfo::builder()
|
|
||||||
.application_info(&application_info)
|
|
||||||
.enabled_layer_names(&layers)
|
|
||||||
.enabled_extension_names(&extensions)
|
|
||||||
.flags(flags);
|
|
||||||
|
|
||||||
let mut debug_info = vk::DebugUtilsMessengerCreateInfoEXT::builder()
|
|
||||||
.message_severity(vk::DebugUtilsMessageSeverityFlagsEXT::all())
|
|
||||||
.message_type(vk::DebugUtilsMessageTypeFlagsEXT::all())
|
|
||||||
.user_callback(Some(debug_callback));
|
|
||||||
|
|
||||||
if VALIDATION_ENABLED {
|
|
||||||
info = info.push_next(&mut debug_info);
|
|
||||||
}
|
|
||||||
|
|
||||||
let instance = entry.create_instance(&info, None)?;
|
|
||||||
|
|
||||||
// Messenger
|
|
||||||
if VALIDATION_ENABLED {
|
|
||||||
data.messenger = instance.create_debug_utils_messenger_ext(&debug_info, None)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(instance)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(super) unsafe fn pick_physical_device(instance: &Instance, data: &mut AppData) -> Result<()> {
|
|
||||||
for physical_device in instance.enumerate_physical_devices()? {
|
|
||||||
let properties = instance.get_physical_device_properties(physical_device);
|
|
||||||
|
|
||||||
if let Err(error) = check_physical_device(instance, data, physical_device) {
|
|
||||||
warn!(
|
|
||||||
"Skipping physical device (`{}`): {}",
|
|
||||||
properties.device_name, error
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
info!("Selected physical device (`{}`).", properties.device_name);
|
|
||||||
data.physical_device = physical_device;
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Err(anyhow!("Failed to find suitable physical device."))
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe fn check_physical_device(
|
|
||||||
instance: &Instance,
|
|
||||||
data: &AppData,
|
|
||||||
physical_device: vk::PhysicalDevice,
|
|
||||||
) -> Result<()> {
|
|
||||||
QueueFamilyIndices::get(instance, data, physical_device)?;
|
|
||||||
check_physical_device_extensions(instance, physical_device)?;
|
|
||||||
|
|
||||||
let support = SwapchainSupport::get(instance, data, physical_device)?;
|
|
||||||
if support.formats.is_empty() || support.present_modes.is_empty() {
|
|
||||||
return Err(anyhow!(SuitabilityError("Insufficient swapchain support.")));
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe fn check_physical_device_extensions(
|
|
||||||
instance: &Instance,
|
instance: &Instance,
|
||||||
physical_device: vk::PhysicalDevice,
|
physical_device: vk::PhysicalDevice,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
@ -175,130 +24,11 @@ unsafe fn check_physical_device_extensions(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//================================================
|
|
||||||
// Logical Device
|
|
||||||
//================================================
|
|
||||||
|
|
||||||
pub(super) unsafe fn create_logical_device(
|
|
||||||
instance: &Instance,
|
|
||||||
data: &mut AppData,
|
|
||||||
) -> Result<Device> {
|
|
||||||
// Queue Create Infos
|
|
||||||
let indices = QueueFamilyIndices::get(instance, data, data.physical_device)?;
|
|
||||||
|
|
||||||
let mut unique_indices = HashSet::new();
|
|
||||||
unique_indices.insert(indices.graphics);
|
|
||||||
unique_indices.insert(indices.present);
|
|
||||||
|
|
||||||
let queue_priorities = &[1.0];
|
|
||||||
let queue_infos = unique_indices
|
|
||||||
.iter()
|
|
||||||
.map(|i| {
|
|
||||||
vk::DeviceQueueCreateInfo::builder()
|
|
||||||
.queue_family_index(*i)
|
|
||||||
.queue_priorities(queue_priorities)
|
|
||||||
})
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
|
|
||||||
// Layers
|
|
||||||
let layers = if VALIDATION_ENABLED {
|
|
||||||
vec![VALIDATION_LAYER.as_ptr()]
|
|
||||||
} else {
|
|
||||||
vec![]
|
|
||||||
};
|
|
||||||
|
|
||||||
// Extensions
|
|
||||||
let mut extensions = DEVICE_EXTENSIONS
|
|
||||||
.iter()
|
|
||||||
.map(|n| n.as_ptr())
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
|
|
||||||
// mac OS Metal -> Vulkan rendering fix
|
|
||||||
if instance
|
|
||||||
.enumerate_device_extension_properties(data.physical_device, None)?
|
|
||||||
.iter()
|
|
||||||
.any(|e| e.extension_name == vk::KHR_PORTABILITY_SUBSET_EXTENSION.name)
|
|
||||||
{
|
|
||||||
extensions.push(vk::KHR_PORTABILITY_SUBSET_EXTENSION.name.as_ptr());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Features
|
|
||||||
let features = vk::PhysicalDeviceFeatures::builder();
|
|
||||||
|
|
||||||
// Create
|
|
||||||
let info = vk::DeviceCreateInfo::builder()
|
|
||||||
.queue_create_infos(&queue_infos)
|
|
||||||
.enabled_layer_names(&layers)
|
|
||||||
.enabled_extension_names(&extensions)
|
|
||||||
.enabled_features(&features);
|
|
||||||
|
|
||||||
let device = instance.create_device(data.physical_device, &info, None)?;
|
|
||||||
|
|
||||||
// Queues
|
|
||||||
data.graphics_queue = device.get_device_queue(indices.graphics, 0);
|
|
||||||
data.present_queue = device.get_device_queue(indices.present, 0);
|
|
||||||
|
|
||||||
Ok(device)
|
|
||||||
}
|
|
||||||
|
|
||||||
//================================================
|
//================================================
|
||||||
// Swapchain
|
// Swapchain
|
||||||
//================================================
|
//================================================
|
||||||
|
|
||||||
pub(super) unsafe fn create_swapchain(
|
pub fn get_swapchain_surface_format(formats: &[vk::SurfaceFormatKHR]) -> vk::SurfaceFormatKHR {
|
||||||
window: &Window,
|
|
||||||
instance: &Instance,
|
|
||||||
device: &Device,
|
|
||||||
data: &mut AppData,
|
|
||||||
) -> Result<()> {
|
|
||||||
let indices = QueueFamilyIndices::get(instance, data, data.physical_device)?;
|
|
||||||
let support = SwapchainSupport::get(instance, data, data.physical_device)?;
|
|
||||||
|
|
||||||
let surface_format = get_swapchain_surface_format(&support.formats);
|
|
||||||
let present_mode = get_swapchain_present_mode(&support.present_modes);
|
|
||||||
let extent = get_swapchain_extent(window, support.capabilities);
|
|
||||||
|
|
||||||
let mut image_count = support.capabilities.min_image_count + 1;
|
|
||||||
if support.capabilities.max_image_count != 0
|
|
||||||
&& image_count > support.capabilities.max_image_count
|
|
||||||
{
|
|
||||||
image_count = support.capabilities.max_image_count;
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut queue_family_indices = vec![];
|
|
||||||
let image_sharing_mode = if indices.graphics != indices.present {
|
|
||||||
queue_family_indices.push(indices.graphics);
|
|
||||||
queue_family_indices.push(indices.present);
|
|
||||||
vk::SharingMode::CONCURRENT
|
|
||||||
} else {
|
|
||||||
vk::SharingMode::EXCLUSIVE
|
|
||||||
};
|
|
||||||
|
|
||||||
let info = vk::SwapchainCreateInfoKHR::builder()
|
|
||||||
.surface(data.surface)
|
|
||||||
.min_image_count(image_count)
|
|
||||||
.image_format(surface_format.format)
|
|
||||||
.image_color_space(surface_format.color_space)
|
|
||||||
.image_extent(extent)
|
|
||||||
.image_array_layers(1)
|
|
||||||
.image_usage(vk::ImageUsageFlags::COLOR_ATTACHMENT)
|
|
||||||
.image_sharing_mode(image_sharing_mode)
|
|
||||||
.queue_family_indices(&queue_family_indices)
|
|
||||||
.pre_transform(support.capabilities.current_transform)
|
|
||||||
.composite_alpha(vk::CompositeAlphaFlagsKHR::OPAQUE)
|
|
||||||
.present_mode(present_mode)
|
|
||||||
.clipped(true)
|
|
||||||
.old_swapchain(vk::SwapchainKHR::null());
|
|
||||||
|
|
||||||
data.swapchain = device.create_swapchain_khr(&info, None)?;
|
|
||||||
data.swapchain_images = device.get_swapchain_images_khr(data.swapchain)?;
|
|
||||||
data.swapchain_format = surface_format.format;
|
|
||||||
data.swapchain_extent = extent;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_swapchain_surface_format(formats: &[vk::SurfaceFormatKHR]) -> vk::SurfaceFormatKHR {
|
|
||||||
formats
|
formats
|
||||||
.iter()
|
.iter()
|
||||||
.cloned()
|
.cloned()
|
||||||
@ -309,7 +39,7 @@ fn get_swapchain_surface_format(formats: &[vk::SurfaceFormatKHR]) -> vk::Surface
|
|||||||
.unwrap_or_else(|| formats[0])
|
.unwrap_or_else(|| formats[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_swapchain_present_mode(present_modes: &[vk::PresentModeKHR]) -> vk::PresentModeKHR {
|
pub fn get_swapchain_present_mode(present_modes: &[vk::PresentModeKHR]) -> vk::PresentModeKHR {
|
||||||
present_modes
|
present_modes
|
||||||
.iter()
|
.iter()
|
||||||
.cloned()
|
.cloned()
|
||||||
@ -317,7 +47,10 @@ fn get_swapchain_present_mode(present_modes: &[vk::PresentModeKHR]) -> vk::Prese
|
|||||||
.unwrap_or(vk::PresentModeKHR::FIFO)
|
.unwrap_or(vk::PresentModeKHR::FIFO)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_swapchain_extent(window: &Window, capabilities: vk::SurfaceCapabilitiesKHR) -> vk::Extent2D {
|
pub fn get_swapchain_extent(
|
||||||
|
window: &Window,
|
||||||
|
capabilities: vk::SurfaceCapabilitiesKHR,
|
||||||
|
) -> vk::Extent2D {
|
||||||
if capabilities.current_extent.width != u32::MAX {
|
if capabilities.current_extent.width != u32::MAX {
|
||||||
capabilities.current_extent
|
capabilities.current_extent
|
||||||
} else {
|
} else {
|
||||||
@ -338,192 +71,11 @@ fn get_swapchain_extent(window: &Window, capabilities: vk::SurfaceCapabilitiesKH
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) unsafe fn create_swapchain_image_views(
|
|
||||||
device: &Device,
|
|
||||||
data: &mut AppData,
|
|
||||||
) -> Result<()> {
|
|
||||||
data.swapchain_image_views = data
|
|
||||||
.swapchain_images
|
|
||||||
.iter()
|
|
||||||
.map(|i| {
|
|
||||||
let components = vk::ComponentMapping::builder()
|
|
||||||
.r(vk::ComponentSwizzle::IDENTITY)
|
|
||||||
.g(vk::ComponentSwizzle::IDENTITY)
|
|
||||||
.b(vk::ComponentSwizzle::IDENTITY)
|
|
||||||
.a(vk::ComponentSwizzle::IDENTITY);
|
|
||||||
|
|
||||||
let subresource_range = vk::ImageSubresourceRange::builder()
|
|
||||||
.aspect_mask(vk::ImageAspectFlags::COLOR)
|
|
||||||
.base_mip_level(0)
|
|
||||||
.level_count(1)
|
|
||||||
.base_array_layer(0)
|
|
||||||
.layer_count(1);
|
|
||||||
|
|
||||||
let info = vk::ImageViewCreateInfo::builder()
|
|
||||||
.image(*i)
|
|
||||||
.view_type(vk::ImageViewType::_2D)
|
|
||||||
.format(data.swapchain_format)
|
|
||||||
.components(components)
|
|
||||||
.subresource_range(subresource_range);
|
|
||||||
|
|
||||||
device.create_image_view(&info, None)
|
|
||||||
})
|
|
||||||
.collect::<Result<Vec<_>, _>>()?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
//================================================
|
//================================================
|
||||||
// Pipeline
|
// Pipeline
|
||||||
//================================================
|
//================================================
|
||||||
|
|
||||||
pub(super) unsafe fn create_render_pass(
|
pub unsafe fn create_shader_module(device: &Device, bytecode: &[u8]) -> Result<vk::ShaderModule> {
|
||||||
_instance: &Instance,
|
|
||||||
device: &Device,
|
|
||||||
data: &mut AppData,
|
|
||||||
) -> Result<()> {
|
|
||||||
let color_attachment = vk::AttachmentDescription::builder()
|
|
||||||
.format(data.swapchain_format)
|
|
||||||
.samples(vk::SampleCountFlags::_1)
|
|
||||||
.load_op(vk::AttachmentLoadOp::CLEAR)
|
|
||||||
.store_op(vk::AttachmentStoreOp::STORE)
|
|
||||||
.stencil_load_op(vk::AttachmentLoadOp::DONT_CARE)
|
|
||||||
.stencil_store_op(vk::AttachmentStoreOp::DONT_CARE)
|
|
||||||
.initial_layout(vk::ImageLayout::UNDEFINED)
|
|
||||||
.final_layout(vk::ImageLayout::PRESENT_SRC_KHR);
|
|
||||||
|
|
||||||
// Subpasses
|
|
||||||
let color_attachment_ref = vk::AttachmentReference::builder()
|
|
||||||
.attachment(0)
|
|
||||||
.layout(vk::ImageLayout::COLOR_ATTACHMENT_OPTIMAL);
|
|
||||||
let color_attachments = &[color_attachment_ref];
|
|
||||||
let subpass = vk::SubpassDescription::builder()
|
|
||||||
.pipeline_bind_point(vk::PipelineBindPoint::GRAPHICS)
|
|
||||||
.color_attachments(color_attachments);
|
|
||||||
let dependency = vk::SubpassDependency::builder()
|
|
||||||
.src_subpass(vk::SUBPASS_EXTERNAL)
|
|
||||||
.dst_subpass(0)
|
|
||||||
.src_stage_mask(vk::PipelineStageFlags::COLOR_ATTACHMENT_OUTPUT)
|
|
||||||
.src_access_mask(vk::AccessFlags::empty())
|
|
||||||
.dst_stage_mask(vk::PipelineStageFlags::COLOR_ATTACHMENT_OUTPUT)
|
|
||||||
.dst_access_mask(vk::AccessFlags::COLOR_ATTACHMENT_WRITE);
|
|
||||||
|
|
||||||
let attachments = &[color_attachment];
|
|
||||||
let subpasses = &[subpass];
|
|
||||||
let dependencies = &[dependency];
|
|
||||||
let info = vk::RenderPassCreateInfo::builder()
|
|
||||||
.attachments(attachments)
|
|
||||||
.subpasses(subpasses)
|
|
||||||
.dependencies(dependencies);
|
|
||||||
|
|
||||||
data.render_pass = device.create_render_pass(&info, None)?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(super) unsafe fn create_pipeline(device: &Device, data: &mut AppData) -> Result<()> {
|
|
||||||
let vert = include_bytes!("../../shaders/vert.spv");
|
|
||||||
let frag = include_bytes!("../../shaders/frag.spv");
|
|
||||||
|
|
||||||
let vert_shader_module = create_shader_module(device, &vert[..])?;
|
|
||||||
let frag_shader_module = create_shader_module(device, &frag[..])?;
|
|
||||||
|
|
||||||
let vert_stage = vk::PipelineShaderStageCreateInfo::builder()
|
|
||||||
.stage(vk::ShaderStageFlags::VERTEX)
|
|
||||||
.module(vert_shader_module)
|
|
||||||
.name(b"main\0");
|
|
||||||
|
|
||||||
let frag_stage = vk::PipelineShaderStageCreateInfo::builder()
|
|
||||||
.stage(vk::ShaderStageFlags::FRAGMENT)
|
|
||||||
.module(frag_shader_module)
|
|
||||||
.name(b"main\0");
|
|
||||||
|
|
||||||
let binding_descriptions = &[Vertex::binding_description()];
|
|
||||||
let attribute_descriptions = Vertex::attribute_descriptions();
|
|
||||||
let vertex_input_state = vk::PipelineVertexInputStateCreateInfo::builder()
|
|
||||||
.vertex_binding_descriptions(binding_descriptions)
|
|
||||||
.vertex_attribute_descriptions(&attribute_descriptions);
|
|
||||||
|
|
||||||
let input_assembly_state = vk::PipelineInputAssemblyStateCreateInfo::builder()
|
|
||||||
.topology(vk::PrimitiveTopology::TRIANGLE_LIST)
|
|
||||||
.primitive_restart_enable(false);
|
|
||||||
|
|
||||||
let viewport = vk::Viewport::builder()
|
|
||||||
.x(0.0)
|
|
||||||
.y(0.0)
|
|
||||||
.width(data.swapchain_extent.width as f32)
|
|
||||||
.height(data.swapchain_extent.height as f32)
|
|
||||||
.min_depth(0.0)
|
|
||||||
.max_depth(1.0);
|
|
||||||
|
|
||||||
let scissor = vk::Rect2D::builder()
|
|
||||||
.offset(vk::Offset2D { x: 0, y: 0 })
|
|
||||||
.extent(data.swapchain_extent);
|
|
||||||
|
|
||||||
let viewports = &[viewport];
|
|
||||||
let scissors = &[scissor];
|
|
||||||
let viewport_state = vk::PipelineViewportStateCreateInfo::builder()
|
|
||||||
.viewports(viewports)
|
|
||||||
.scissors(scissors);
|
|
||||||
|
|
||||||
let rasterization_state = vk::PipelineRasterizationStateCreateInfo::builder()
|
|
||||||
.depth_clamp_enable(false)
|
|
||||||
.rasterizer_discard_enable(false)
|
|
||||||
.polygon_mode(vk::PolygonMode::FILL)
|
|
||||||
.line_width(1.0)
|
|
||||||
.cull_mode(vk::CullModeFlags::BACK)
|
|
||||||
.front_face(vk::FrontFace::CLOCKWISE)
|
|
||||||
.depth_bias_enable(false);
|
|
||||||
|
|
||||||
let multisample_state = vk::PipelineMultisampleStateCreateInfo::builder()
|
|
||||||
.sample_shading_enable(false)
|
|
||||||
.rasterization_samples(vk::SampleCountFlags::_1);
|
|
||||||
|
|
||||||
let attachment = vk::PipelineColorBlendAttachmentState::builder()
|
|
||||||
.color_write_mask(vk::ColorComponentFlags::all())
|
|
||||||
.blend_enable(false)
|
|
||||||
.src_color_blend_factor(vk::BlendFactor::ONE)
|
|
||||||
.dst_color_blend_factor(vk::BlendFactor::ZERO)
|
|
||||||
.color_blend_op(vk::BlendOp::ADD)
|
|
||||||
.src_alpha_blend_factor(vk::BlendFactor::ONE)
|
|
||||||
.dst_alpha_blend_factor(vk::BlendFactor::ZERO)
|
|
||||||
.alpha_blend_op(vk::BlendOp::ADD);
|
|
||||||
|
|
||||||
let attachments = &[attachment];
|
|
||||||
let color_blend_state = vk::PipelineColorBlendStateCreateInfo::builder()
|
|
||||||
.logic_op_enable(false)
|
|
||||||
.logic_op(vk::LogicOp::COPY)
|
|
||||||
.attachments(attachments)
|
|
||||||
.blend_constants([0.0, 0.0, 0.0, 0.0]);
|
|
||||||
|
|
||||||
let layout_info = vk::PipelineLayoutCreateInfo::builder();
|
|
||||||
data.pipeline_layout = device.create_pipeline_layout(&layout_info, None)?;
|
|
||||||
|
|
||||||
let stages = &[vert_stage, frag_stage];
|
|
||||||
let info = vk::GraphicsPipelineCreateInfo::builder()
|
|
||||||
.stages(stages)
|
|
||||||
.vertex_input_state(&vertex_input_state)
|
|
||||||
.input_assembly_state(&input_assembly_state)
|
|
||||||
.viewport_state(&viewport_state)
|
|
||||||
.rasterization_state(&rasterization_state)
|
|
||||||
.multisample_state(&multisample_state)
|
|
||||||
.color_blend_state(&color_blend_state)
|
|
||||||
.layout(data.pipeline_layout)
|
|
||||||
.render_pass(data.render_pass)
|
|
||||||
.subpass(0);
|
|
||||||
|
|
||||||
data.pipeline = device
|
|
||||||
.create_graphics_pipelines(vk::PipelineCache::null(), &[info], None)?
|
|
||||||
.0;
|
|
||||||
|
|
||||||
// Cleanup
|
|
||||||
device.destroy_shader_module(vert_shader_module, None);
|
|
||||||
device.destroy_shader_module(frag_shader_module, None);
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe fn create_shader_module(device: &Device, bytecode: &[u8]) -> Result<vk::ShaderModule> {
|
|
||||||
let bytecode = Vec::<u8>::from(bytecode);
|
let bytecode = Vec::<u8>::from(bytecode);
|
||||||
let (prefix, code, suffix) = bytecode.align_to::<u32>();
|
let (prefix, code, suffix) = bytecode.align_to::<u32>();
|
||||||
if !prefix.is_empty() || !suffix.is_empty() {
|
if !prefix.is_empty() || !suffix.is_empty() {
|
||||||
@ -536,178 +88,3 @@ unsafe fn create_shader_module(device: &Device, bytecode: &[u8]) -> Result<vk::S
|
|||||||
|
|
||||||
Ok(device.create_shader_module(&info, None)?)
|
Ok(device.create_shader_module(&info, None)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) unsafe fn create_framebuffers(device: &Device, data: &mut AppData) -> Result<()> {
|
|
||||||
data.framebuffers = data
|
|
||||||
.swapchain_image_views
|
|
||||||
.iter()
|
|
||||||
.map(|i| {
|
|
||||||
let attachments = &[*i];
|
|
||||||
let create_info = vk::FramebufferCreateInfo::builder()
|
|
||||||
.render_pass(data.render_pass)
|
|
||||||
.attachments(attachments)
|
|
||||||
.width(data.swapchain_extent.width)
|
|
||||||
.height(data.swapchain_extent.height)
|
|
||||||
.layers(1);
|
|
||||||
|
|
||||||
device.create_framebuffer(&create_info, None)
|
|
||||||
})
|
|
||||||
.collect::<Result<Vec<_>, _>>()?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
//================================================
|
|
||||||
// Command Pool
|
|
||||||
//================================================
|
|
||||||
|
|
||||||
pub(super) unsafe fn create_command_pool(
|
|
||||||
instance: &Instance,
|
|
||||||
device: &Device,
|
|
||||||
data: &mut AppData,
|
|
||||||
) -> Result<()> {
|
|
||||||
let indices = QueueFamilyIndices::get(instance, data, data.physical_device)?;
|
|
||||||
|
|
||||||
let info = vk::CommandPoolCreateInfo::builder()
|
|
||||||
.flags(vk::CommandPoolCreateFlags::empty())
|
|
||||||
.queue_family_index(indices.graphics);
|
|
||||||
|
|
||||||
data.command_pool = device.create_command_pool(&info, None)?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
//================================================
|
|
||||||
// Command Buffers
|
|
||||||
//================================================
|
|
||||||
|
|
||||||
pub(super) unsafe fn create_command_buffers(device: &Device, data: &mut AppData) -> Result<()> {
|
|
||||||
// Create the buffers
|
|
||||||
let allocate_info = vk::CommandBufferAllocateInfo::builder()
|
|
||||||
.command_pool(data.command_pool)
|
|
||||||
.level(vk::CommandBufferLevel::PRIMARY)
|
|
||||||
.command_buffer_count(data.framebuffers.len() as u32);
|
|
||||||
|
|
||||||
data.command_buffers = device.allocate_command_buffers(&allocate_info)?;
|
|
||||||
|
|
||||||
// Add commands
|
|
||||||
for (i, command_buffer) in data.command_buffers.iter().enumerate() {
|
|
||||||
let inheritance = vk::CommandBufferInheritanceInfo::builder();
|
|
||||||
|
|
||||||
let info = vk::CommandBufferBeginInfo::builder()
|
|
||||||
.flags(vk::CommandBufferUsageFlags::empty())
|
|
||||||
.inheritance_info(&inheritance);
|
|
||||||
|
|
||||||
device.begin_command_buffer(*command_buffer, &info)?;
|
|
||||||
|
|
||||||
let render_area = vk::Rect2D::builder()
|
|
||||||
.offset(vk::Offset2D::default())
|
|
||||||
.extent(data.swapchain_extent);
|
|
||||||
|
|
||||||
let color_clear_value = vk::ClearValue {
|
|
||||||
color: vk::ClearColorValue {
|
|
||||||
float32: [0.0, 0.0, 0.0, 1.0],
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
let clear_values = &[color_clear_value];
|
|
||||||
let info = vk::RenderPassBeginInfo::builder()
|
|
||||||
.render_pass(data.render_pass)
|
|
||||||
.framebuffer(data.framebuffers[i])
|
|
||||||
.render_area(render_area)
|
|
||||||
.clear_values(clear_values);
|
|
||||||
|
|
||||||
device.cmd_begin_render_pass(*command_buffer, &info, vk::SubpassContents::INLINE);
|
|
||||||
device.cmd_bind_pipeline(
|
|
||||||
*command_buffer,
|
|
||||||
vk::PipelineBindPoint::GRAPHICS,
|
|
||||||
data.pipeline,
|
|
||||||
);
|
|
||||||
device.cmd_bind_vertex_buffers(*command_buffer, 0, &[data.vertex_buffer], &[0]);
|
|
||||||
device.cmd_draw(*command_buffer, 3, 1, 0, 0);
|
|
||||||
device.cmd_end_render_pass(*command_buffer);
|
|
||||||
|
|
||||||
device.end_command_buffer(*command_buffer)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(super) unsafe fn create_sync_objects(device: &Device, data: &mut AppData) -> Result<()> {
|
|
||||||
let semaphore_info = vk::SemaphoreCreateInfo::builder();
|
|
||||||
let fence_info = vk::FenceCreateInfo::builder().flags(vk::FenceCreateFlags::SIGNALED);
|
|
||||||
|
|
||||||
for _ in 0..MAX_FRAMES_IN_FLIGHT {
|
|
||||||
data.image_available_semaphores
|
|
||||||
.push(device.create_semaphore(&semaphore_info, None)?);
|
|
||||||
data.render_finished_semaphores
|
|
||||||
.push(device.create_semaphore(&semaphore_info, None)?);
|
|
||||||
|
|
||||||
data.in_flight_fences
|
|
||||||
.push(device.create_fence(&fence_info, None)?);
|
|
||||||
}
|
|
||||||
|
|
||||||
data.images_in_flight = data
|
|
||||||
.swapchain_images
|
|
||||||
.iter()
|
|
||||||
.map(|_| vk::Fence::null())
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(super) unsafe fn create_vertex_buffer(
|
|
||||||
instance: &Instance,
|
|
||||||
device: &Device,
|
|
||||||
data: &mut AppData,
|
|
||||||
) -> Result<()> {
|
|
||||||
let buffer_info = vk::BufferCreateInfo::builder()
|
|
||||||
.size((size_of::<Vertex>() * VERTICES.len()) as u64)
|
|
||||||
.usage(vk::BufferUsageFlags::VERTEX_BUFFER)
|
|
||||||
.sharing_mode(vk::SharingMode::EXCLUSIVE);
|
|
||||||
|
|
||||||
data.vertex_buffer = device.create_buffer(&buffer_info, None)?;
|
|
||||||
|
|
||||||
let requirements = device.get_buffer_memory_requirements(data.vertex_buffer);
|
|
||||||
let memory_info = vk::MemoryAllocateInfo::builder()
|
|
||||||
.allocation_size(requirements.size)
|
|
||||||
.memory_type_index(get_memory_type_index(
|
|
||||||
instance,
|
|
||||||
data,
|
|
||||||
vk::MemoryPropertyFlags::HOST_COHERENT | vk::MemoryPropertyFlags::HOST_VISIBLE,
|
|
||||||
requirements,
|
|
||||||
)?);
|
|
||||||
|
|
||||||
data.vertex_buffer_memory = device.allocate_memory(&memory_info, None)?;
|
|
||||||
|
|
||||||
device.bind_buffer_memory(data.vertex_buffer, data.vertex_buffer_memory, 0)?;
|
|
||||||
|
|
||||||
let memory = device.map_memory(
|
|
||||||
data.vertex_buffer_memory,
|
|
||||||
0,
|
|
||||||
buffer_info.size,
|
|
||||||
vk::MemoryMapFlags::empty(),
|
|
||||||
)?;
|
|
||||||
|
|
||||||
memcpy(VERTICES.as_ptr(), memory.cast(), VERTICES.len());
|
|
||||||
device.unmap_memory(data.vertex_buffer_memory);
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe fn get_memory_type_index(
|
|
||||||
instance: &Instance,
|
|
||||||
data: &AppData,
|
|
||||||
properties: vk::MemoryPropertyFlags,
|
|
||||||
requirements: vk::MemoryRequirements,
|
|
||||||
) -> Result<u32> {
|
|
||||||
let memory = instance.get_physical_device_memory_properties(data.physical_device);
|
|
||||||
|
|
||||||
(0..memory.memory_type_count)
|
|
||||||
.find(|i| {
|
|
||||||
let suitable = (requirements.memory_type_bits & (1 << i)) != 0;
|
|
||||||
let memory_type = memory.memory_types[*i as usize];
|
|
||||||
suitable && memory_type.property_flags.contains(properties)
|
|
||||||
})
|
|
||||||
.ok_or_else(|| anyhow!("Failed to find suitable memory type."))
|
|
||||||
}
|
|
||||||
|
Loading…
Reference in New Issue
Block a user