crystal-api 0.0.6

Crystal API is a unified GPU API's wrapper
Documentation
use std::ffi::c_void;
use std::process::abort;

use ash::vk::{
    self, DebugUtilsMessageSeverityFlagsEXT, DebugUtilsMessageTypeFlagsEXT,
    DebugUtilsMessengerCallbackDataEXT,
};

use ash::ext::debug_utils;
use ash::{Entry, Instance};

use crate::debug::{error, log};
use crate::errors::{GraphicsError, GraphicsResult};

pub(crate) struct DebugUtilsMessanger {
    _debug_utils: debug_utils::Instance,
    _debug_utils_messanger: vk::DebugUtilsMessengerEXT,
}

impl Drop for DebugUtilsMessanger {
    fn drop(&mut self) {
        unsafe {
            self._debug_utils
                .destroy_debug_utils_messenger(self._debug_utils_messanger, None);
        }
    }
}

#[allow(unused)]
unsafe extern "system" fn debug_callback(
    message_severity: DebugUtilsMessageSeverityFlagsEXT,
    message_type: DebugUtilsMessageTypeFlagsEXT,
    callback_data_ptr: *const DebugUtilsMessengerCallbackDataEXT,
    user_data_ptr: *mut c_void,
) -> u32 {
    let callback_data = unsafe { callback_data_ptr.read() };
    match unsafe { callback_data.message_as_c_str() } {
        Some(cstr) => {
            let message = cstr.to_str().unwrap();

            if message_severity.contains(DebugUtilsMessageSeverityFlagsEXT::ERROR) {
                #[allow(clippy::panic)]
                {
                    println!("[FATAL] {message}");
                    abort()
                };
            } else if message_severity.contains(DebugUtilsMessageSeverityFlagsEXT::INFO) {
                log!("[VALIDATION INFO] {}", message);
            } else if message_severity.contains(DebugUtilsMessageSeverityFlagsEXT::VERBOSE) {
                log!("[VALIDATION VERBOSE] {}", message);
            } else if message_severity.contains(DebugUtilsMessageSeverityFlagsEXT::WARNING) {
                log!("[VALIDATION WARNING] {}", message);
            }
        }
        None => log!("debug callback was called, but invalid callback data was provided"),
    }
    0
}

#[allow(unused)]
pub(crate) fn create_debug_utils_messanger(
    entry: &Entry,
    instance: &Instance,
) -> GraphicsResult<DebugUtilsMessanger> {
    let debug_utils = debug_utils::Instance::new(entry, instance);
    let debug_messanger_create_info = vk::DebugUtilsMessengerCreateInfoEXT::default()
        .message_severity(
            DebugUtilsMessageSeverityFlagsEXT::ERROR
                | DebugUtilsMessageSeverityFlagsEXT::WARNING
                | DebugUtilsMessageSeverityFlagsEXT::VERBOSE
                | DebugUtilsMessageSeverityFlagsEXT::INFO,
        )
        .message_type(
            DebugUtilsMessageTypeFlagsEXT::GENERAL
                | DebugUtilsMessageTypeFlagsEXT::VALIDATION
                | DebugUtilsMessageTypeFlagsEXT::PERFORMANCE,
        )
        .pfn_user_callback(Some(debug_callback));

    let debug_utils_messanger = match unsafe {
        debug_utils.create_debug_utils_messenger(&debug_messanger_create_info, None)
    } {
        Ok(messanger) => messanger,
        Err(e) => {
            error!("cannot create vulkan debug messanger: {}", e);
            return Err(GraphicsError::DebugError);
        }
    };

    Ok(DebugUtilsMessanger {
        _debug_utils: debug_utils,
        _debug_utils_messanger: debug_utils_messanger,
    })
}