use super::internal::*;
use ash::vk;
use raw_window_handle::{HasRawDisplayHandle, HasRawWindowHandle};
use std::sync::Arc;
use crate::vulkan::{RafxDeviceContextVulkan, RafxDeviceContextVulkanInner};
use crate::*;
use std::ffi::CString;
#[derive(Copy, Clone, Debug)]
pub enum VulkanLinkMethod {
Dynamic,
#[cfg(feature = "static-vulkan")]
Static,
}
impl Default for VulkanLinkMethod {
fn default() -> Self {
#[cfg(not(feature = "static-vulkan"))]
let link_method = VulkanLinkMethod::Dynamic;
#[cfg(feature = "static-vulkan")]
let link_method = VulkanLinkMethod::Static;
link_method
}
}
pub struct RafxApiDefVulkan {
pub app_name: CString,
pub link_method: VulkanLinkMethod,
pub validation_mode: RafxValidationMode,
pub physical_device_features: Option<vk::PhysicalDeviceFeatures>,
pub enable_debug_names: bool,
}
impl Default for RafxApiDefVulkan {
fn default() -> Self {
RafxApiDefVulkan {
app_name: CString::new("Rafx Application").unwrap(),
link_method: Default::default(),
validation_mode: Default::default(),
physical_device_features: None,
enable_debug_names: false,
}
}
}
pub struct RafxApiVulkan {
instance: VkInstance,
device_context: Option<RafxDeviceContextVulkan>,
}
impl Drop for RafxApiVulkan {
fn drop(&mut self) {
self.destroy().unwrap();
}
}
impl RafxApiVulkan {
pub fn device_context(&self) -> &RafxDeviceContextVulkan {
self.device_context.as_ref().unwrap()
}
pub fn vk_instance(&self) -> &ash::Instance {
&self.instance.instance
}
pub unsafe fn new(
display: &dyn HasRawDisplayHandle,
window: &dyn HasRawWindowHandle,
_api_def: &RafxApiDef,
vk_api_def: &RafxApiDefVulkan,
) -> RafxResult<Self> {
let link_method = vk_api_def.link_method;
let app_name = vk_api_def.app_name.clone();
let all_severity_flags = vk::DebugUtilsMessageSeverityFlagsEXT::VERBOSE
| vk::DebugUtilsMessageSeverityFlagsEXT::INFO
| vk::DebugUtilsMessageSeverityFlagsEXT::WARNING
| vk::DebugUtilsMessageSeverityFlagsEXT::ERROR;
let (require_validation_layers_present, validation_layer_debug_report_flags) =
match vk_api_def.validation_mode {
RafxValidationMode::Disabled => {
(false, vk::DebugUtilsMessageSeverityFlagsEXT::empty())
}
RafxValidationMode::EnabledIfAvailable => (false, all_severity_flags),
RafxValidationMode::Enabled => (true, all_severity_flags),
};
log::info!("Validation mode: {:?}", vk_api_def.validation_mode);
log::info!("Link method for vulkan: {:?}", link_method);
let entry = match link_method {
VulkanLinkMethod::Dynamic => VkEntry::new_dynamic(),
#[cfg(feature = "static-vulkan")]
VulkanLinkMethod::Static => VkEntry::new_static(),
}?;
let instance = VkInstance::new(
entry,
display,
window,
&app_name,
require_validation_layers_present,
validation_layer_debug_report_flags,
vk_api_def.enable_debug_names,
)?;
let inner = Arc::new(RafxDeviceContextVulkanInner::new(&instance, &vk_api_def)?);
let device_context = RafxDeviceContextVulkan::new(inner)?;
Ok(RafxApiVulkan {
instance,
device_context: Some(device_context),
})
}
pub(crate) fn destroy(&mut self) -> RafxResult<()> {
if let Some(device_context) = self.device_context.take() {
let inner = device_context.inner.clone();
inner.descriptor_heap.clear_pools(device_context.device());
inner.resource_cache.clear_caches();
#[cfg(debug_assertions)]
#[cfg(feature = "track-device-contexts")]
let _create_index = device_context.create_index;
std::mem::drop(device_context);
let _strong_count = Arc::strong_count(&inner);
match Arc::try_unwrap(inner) {
Ok(inner) => std::mem::drop(inner),
Err(_arc) => {
Err(format!(
"Could not destroy device, {} references to it exist",
_strong_count
))?;
#[cfg(debug_assertions)]
#[cfg(feature = "track-device-contexts")]
{
let mut all_contexts = _arc.all_contexts.lock().unwrap();
all_contexts.remove(&_create_index);
for (k, v) in all_contexts.iter_mut() {
v.resolve();
println!("context allocation: {}\n{:?}", k, v);
}
}
}
}
}
Ok(())
}
}