1.2 万一手滑了怎么办?

我之前可能有提到过Vulkan自带一个非常强大的验证层(Validation Layer),可以帮我们打打log,看看内存泄漏,之类的,总之是贤妻良母级别的.

首先呢,之前我们一直是在main.rs中创建EventsLoop的,我们可以把这个加入到App中,反正也就有一个loop

use super::super::events_handler::*;
use super::vki::*;
use winit::EventsLoop;
use super::super::window::*;
pub const WINDOW_TITLE: &'static str = "When Vulkan meets Rust";

pub struct App {
    pub window: winit::Window,
    pub vki: VKI,
    pub events_loop: EventsLoop,
}

impl App {
    pub fn new() -> App {
        let ev = EventsLoop::new();
        let window = window_create(WINDOW_TITLE, 800, 600, &ev);
        return App {
            window: window,
            vki: VKI::new(),
            events_loop: ev,
        };
    }
    pub fn main_loop(&mut self) {
        self.events_loop.run_forever(event_handler);
    }
}

然后把 window.rs里的String 换成&'static str这样能提升性能(忽略不计的)

我们需要准备一个叫vk_to_string的函数,因为vulkan的log都是C语言的string,我们需要把他转换到Rust的String 新建目录utils\tools.rs自行补全lib.rsmod.rs

use std::ffi::CStr;
use std::os::raw::c_char;
use std::path::Path;
//请大家不要忘记 char* 他可是我最喜欢的C语言类型
pub fn vk_to_string(raw_string_array: &[c_char]) -> String {
    let raw_string = unsafe {
        let pointer = raw_string_array.as_ptr();
        CStr::from_ptr(pointer)
    };
    raw_string
        .to_str()
        .expect("转换失败!")
        .to_owned()
}

现在开始重头戏

app下创建validation.rs

use super::super::platforms::required_extension::*;
use super::super::utils::tools::*;
use ash::version::EntryV1_0;
use ash::version::InstanceV1_0;
use ash::vk;
use ash::vk_make_version;
use std::ffi::{CStr, CString};
use std::os::raw::{c_char, c_void};
use std::ptr;

pub struct ValidationInfo {
    pub is_enable: bool,
    pub required_validation_layers: [&'static str; 1],
}

//下面这个常数是方便开关validation的,有点 #ifdef 的意思
pub const VALIDATION: ValidationInfo = ValidationInfo {
    is_enable: true,
    required_validation_layers: ["VK_LAYER_LUNARG_standard_validation"], 
    //我们需要拿过来LUNARG写的标准的验证层
};

pub fn check_validation_layer_support(entry: &ash::Entry) -> bool {
    // 这个函数检查支持验证层的情况
    //如果支持会返回一个true

    let layer_properties = entry
        .enumerate_instance_layer_properties() //枚举实例层属性
        .expect("枚举实例层失败!");

    if layer_properties.len() <= 0 {
        eprintln!("没有可用层.");
        return false;
    } else {
        println!("可用实例层: ");
        for layer in layer_properties.iter() { //把可用的实例层都打印出来
            let layer_name = vk_to_string(&layer.layer_name);
            println!("\t{}", layer_name);
        }
    }

    //把所有的layer翻个遍,找找咱要的那个layer,没找着就return false了
    for required_layer_name in VALIDATION.required_validation_layers.iter() {
        let mut is_layer_found = false;

        for layer_property in layer_properties.iter() {
            let test_layer_name = vk_to_string(&layer_property.layer_name);
            if (*required_layer_name) == test_layer_name {
                is_layer_found = true;
                break;
            }
        }

        if is_layer_found == false {
            return false;
        }
    }

    true
}
pub unsafe extern "system" fn vk_debug_callback( //unsafe extern "system" 一看就是给C用的
    _: vk::DebugReportFlagsEXT,
    _: vk::DebugReportObjectTypeEXT,
    _: u64,
    _: usize,
    _: i32,
    _: *const c_char,
    p_message: *const c_char,
    _: *mut c_void,
) -> u32 {
    println!("{:?}", CStr::from_ptr(p_message)); //打印一下回调信息
    vk::FALSE
}

pub fn setup_debug_callback(
    entry: &ash::Entry,
    instance: &ash::Instance,
) -> (
    ash::extensions::ext::DebugReport,
    vk::DebugReportCallbackEXT,
) {
    let debug_report_loader = ash::extensions::ext::DebugReport::new(entry, instance); 
    //创建调试反馈

    if VALIDATION.is_enable == false { //看看实例层开着没有
        (debug_report_loader, ash::vk::DebugReportCallbackEXT::null())
    } else {
        let debug_create_info = vk::DebugReportCallbackCreateInfoEXT { //debug的创建信息,下面这个结构体是不是跟某个结构体很像?
            s_type: vk::StructureType::DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT,
            p_next: ptr::null(),
            //flags标注了这个东西大概需要干什么
            flags: vk::DebugReportFlagsEXT::ERROR //报个错
                    | vk::DebugReportFlagsEXT::INFORMATION //给个信息
                    //| vk::DebugReportFlagsEXT::DEBUG
                    | vk::DebugReportFlagsEXT::WARNING //报个警
                    | vk::DebugReportFlagsEXT::PERFORMANCE_WARNING, //性能不足报个警
            pfn_callback: Some(vk_debug_callback), //回调
            p_user_data: ptr::null_mut(),
        };

        let debug_call_back = unsafe {
            debug_report_loader
                .create_debug_report_callback(&debug_create_info, None)
                .expect("创建调试回调失败 原因:")
        };

        (debug_report_loader, debug_call_back) //返回值是一个报告和一个回调
    }
}

现在我们重新回到vki.rs 我们需要把我们写的验证层加入到我们的vulkan实例中去 所以我决定在impl VKI里面加入一个create_instance,在VKI结构体里塞一个debug_reportdebug_callback

pub struct VKI {
    pub entry: ash::Entry,
    pub instance: ash::Instance,
    pub debug_report: ash::extensions::ext::DebugReport,//新增
    pub debug_callback: vk::DebugReportCallbackEXT,//新增
}

impl VKI{

    pub fn new() -> VKI {
        let entry = ash::Entry::new().unwrap();
        let instance = VKI::create_instance(&entry);
        let (debug_report, debug_callback) = setup_debug_callback(&entry, &instance); //新增
        return VKI {
            entry: entry,
            instance: instance,
            debug_report: debug_report, //新增
            debug_callback: debug_callback, //新增
        };
    }

        fn create_instance(entry: &ash::Entry) -> ash::Instance {
        if VALIDATION.is_enable && check_validation_layer_support(entry) == false {
            panic!("验证层不可用!");
        }

        let app_name = CString::new(WINDOW_TITLE).unwrap();
        let engine_name = CString::new("Vulkan Engine").unwrap();
        let app_info = vk::ApplicationInfo { //我发现Vulkan特别喜欢让我们填表
            p_application_name: app_name.as_ptr(),
            s_type: vk::StructureType::APPLICATION_INFO,
            p_next: ptr::null(),
            application_version: APPLICATION_VERSION,
            p_engine_name: engine_name.as_ptr(),
            engine_version: ENGINE_VERSION,
            api_version: API_VERSION,
        };

        //收集一下扩展的名字.
        let extension_names = required_extension_names();

        //便利一下我们常量需要的扩展
        let requred_validation_layer_raw_names: Vec<CString> = VALIDATION
            .required_validation_layers
            .iter()
            .map(|layer_name| CString::new(*layer_name).unwrap())
            .collect();
        //便利一下我们开着的扩展
        let enable_layer_names: Vec<*const i8> = requred_validation_layer_raw_names
            .iter()
            .map(|layer_name| layer_name.as_ptr())
            .collect();

        let create_info = vk::InstanceCreateInfo {//填表不解释
            s_type: vk::StructureType::INSTANCE_CREATE_INFO,
            p_next: ptr::null(),
            flags: vk::InstanceCreateFlags::empty(),
            p_application_info: &app_info,
            pp_enabled_layer_names: if VALIDATION.is_enable {//如果开着验证层把名字告诉他,要不啥没有
                enable_layer_names.as_ptr()
            } else {
                ptr::null()
            },
            enabled_layer_count: if VALIDATION.is_enable {//开这几个层
                enable_layer_names.len()
            } else {
                0
            } as u32,
            pp_enabled_extension_names: extension_names.as_ptr(),//扩展的名字们
            enabled_extension_count: extension_names.len() as u32,//开着几个扩展
        };

        let instance: ash::Instance = unsafe {
            entry
                .create_instance(&create_info, None)
                .expect("创建实例失败!")
        };

        instance
    }
}

现在看着补补use,补完之后,我们来讲一下为什么会发生之前的那个错误 可能就是因为我们drop的方法不太对 现在我们来重新写一下drop因为这此我们还带了一个验证层,所以,有什么错误他会告诉咱的 我相信大家知道要改的是那个文件

impl Drop for VKI {
    fn drop(&mut self) {
        unsafe {
            if VALIDATION.is_enable {
                self.debug_report
                    .destroy_debug_report_callback(self.debug_callback, None);
            }
            self.instance.destroy_instance(None);
        }
    }
}

现在我们尝试运行一下看看有什么会被打印出来cargo run

差不多以下内容就证明你写的还凑合

Instance Available Layers:
        VK_LAYER_NV_optimus
        VK_LAYER_VALVE_steam_overlay
        VK_LAYER_VALVE_steam_fossilize
        VK_LAYER_LUNARG_standard_validation

关闭窗口后,没有报错 我觉得这章写到这里就行了,大家赶紧去抄抄代码

后面的章节将会越来越难理解,还是鼓励一下吧

results matching ""

    No results matching ""