1.1 搞了半天了Vulkan的影儿都没看见,老板,能不能把主菜端上来?
好吧,我们在上小节里创建了需要承载vulkan的窗口(注意不是Vulkan实例正在运行的窗口),现在可以实现一下vulkan的实例了.
上面这个流程图呢简单的介绍了一下大概我们Vulkan是怎么搞工作的,那么我们的实例在哪里呢?
你看到Vulkan App 右边第一个加载没有? 这就是我们实例所在的位置,实例负责加载(初始化)一个Vulkan加载器,然后加载器会加载一些其他的层和驱动之类的东西,在下一节我们会讲到验证层,也就是一个最常用的层.
现在我们开始实际写代码,我们在app
目录下创建一个vki.rs
use super::super::platforms::required_extension::*;//这个马上写
use ash::version::EntryV1_0;
use ash::version::InstanceV1_0;
use ash::vk;
use ash::vk_make_version;
use std::ffi::CString;
use std::ptr;
pub const WINDOW_TITLE: &'static str = "When Vulkan meets Rust";
//vulkan的版本需要使用一个宏来构造,其实是u32类型的,这里大家可以根据自己vulkan的版本来进行配置
pub const APPLICATION_VERSION: u32 = vk_make_version!(1, 0, 0);
pub const ENGINE_VERSION: u32 = vk_make_version!(1, 0, 0);
pub const API_VERSION: u32 = vk_make_version!(1, 0, 92);
pub struct VKI {
pub instance: ash::Instance, //Vulkan实例
}
现在我们实现一下new
方法
impl VKI {
pub fn new() -> VKI {
let entry = ash::Entry::new().unwrap(); //入口
let app_name = CString::new(WINDOW_TITLE).unwrap(); //vulkan内部描述应用的名称
let engine_name = CString::new("Vulkan Engine").unwrap();
let app_info = vk::ApplicationInfo {
s_type: vk::StructureType::APPLICATION_INFO,//结构类型
p_next: ptr::null(),//一会儿再讲
p_application_name: app_name.as_ptr(),//app名称
application_version: APPLICATION_VERSION,//app版本
p_engine_name: engine_name.as_ptr(),//引擎名称
engine_version: ENGINE_VERSION,//引擎版本
api_version: API_VERSION, //api版本
}; //应用信息
let extension_names = required_extension_names();//这个马上写
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: ptr::null(),//一会儿讲,暂时用不到
enabled_layer_count: 0,//同上
pp_enabled_extension_names: extension_names.as_ptr(),//启用的扩展
enabled_extension_count: extension_names.len() as u32,//扩展表列长度
};
let instance: ash::Instance = unsafe { //unsafe因为vulkan是C语言写的
entry
.create_instance(&create_info, None)
.expect("Vulkan实例创建失败 原因:")
};
VKI { instance: instance }
}
}
因为vulkan是C语言写的(为了追求最强性能),所以他的内存管理完全是手动的.
而Rust没怎么用过free()
函数是因为Rust采用了RAII,当对象从作用空间里消失的时候会自动调用drop
函数
一般情况下drop
函数都是Rust替我们写好的,不过这次不一样,我们需要手动去释放vulkan创建出来的一堆东西,所以我们需要手动写drop函数
还是那个文件
impl Drop for VKI {
fn drop(&mut self) {
unsafe {//因为涉及到了裸指针操作
self.instance.destroy_instance(None);
}
}
}
因为vulkan每个平台上用的渲染方法都不太一样
所以我们要实现一个非常平台相关的一堆函数
在src
下创建platforms
文件夹,自行配置lib.rs
在platforms
下创建required_extension.rs
自行写mod.rs
#[cfg(target_os = "windows")] //对于windows平台用的是win32的surface
use ash::extensions::khr::Win32Surface;
#[cfg(all(unix, not(target_os = "android"), not(target_os = "macos")))]
//对于不是安卓,苹果的unix(linux BSD HPUnix之类的)用的Xlib
use ash::extensions::khr::XlibSurface;
use ash::extensions::khr::Surface;
use ash::extensions::ext::DebugReport;
// *const i8 是指针类型,这个也是因为vulkan是C写的所以我们需要传递裸指针
#[cfg(all(windows))]
pub fn required_extension_names() -> Vec<*const i8> {
vec![
Surface::name().as_ptr(),
Win32Surface::name().as_ptr(),
DebugReport::name().as_ptr(),
]
}
#[cfg(all(unix, not(target_os = "android"), not(target_os = "macos")))]
pub fn required_extension_names() -> Vec<*const i8> {
vec![
Surface::name().as_ptr(),
XlibSurface::name().as_ptr(),
DebugReport::name().as_ptr(),
]
}
现在呢,我们写好了一切创建一个vulkan实例用的东西了,我们只需要把我们的VKI
加入到App
里就好了,还是app.rs
pub struct App {
pub window: winit::Window,
pub vki: VKI, //新增
}
impl App {
pub fn new(events_loop: &EventsLoop) -> App {
let window = window_create(WINDOW_TITLE.to_string(), 800, 600, events_loop);
return App {
window: window,
vki: VKI::new(),//新增
};
}
}
一切准备就绪,可以cargo run
跑跑看看了
补充: 如果终端显示 error: process didn't exit successfully: target\debug\vk_00.exe
(exit code: 0xc0000005, STATUS_ACCESS_VIOLATION)或类似问题,请不要急,在1.2会解决这个问题的