Loader cleanup
This commit is contained in:
parent
b9273b8db5
commit
4ace1cc780
|
@ -22,7 +22,7 @@ struct Vertex {
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
unsafe {
|
unsafe {
|
||||||
let base: ExampleBase = ExampleBase::new(1920, 1080);
|
let base = ExampleBase::new(1920, 1080);
|
||||||
let renderpass_attachments =
|
let renderpass_attachments =
|
||||||
[vk::AttachmentDescription {
|
[vk::AttachmentDescription {
|
||||||
format: base.surface_format.format,
|
format: base.surface_format.format,
|
||||||
|
|
|
@ -9,15 +9,15 @@ extern crate winapi;
|
||||||
|
|
||||||
use ash::vk;
|
use ash::vk;
|
||||||
use std::default::Default;
|
use std::default::Default;
|
||||||
use ash::entry::Entry;
|
use ash::Entry;
|
||||||
use ash::instance::Instance;
|
use ash::Instance;
|
||||||
|
use ash::Device;
|
||||||
|
pub use ash::version::{FunctionPointers, V1_0, InstanceV1_0, DeviceV1_0};
|
||||||
use ash::extensions::{Swapchain, XlibSurface, Surface, DebugReport, Win32Surface};
|
use ash::extensions::{Swapchain, XlibSurface, Surface, DebugReport, Win32Surface};
|
||||||
use ash::device::Device;
|
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
use std::ffi::{CStr, CString};
|
use std::ffi::{CStr, CString};
|
||||||
use std::ops::Drop;
|
use std::ops::Drop;
|
||||||
pub use ash::instance::{V1_0, InstanceV1_0};
|
use ash::entry::EntryExt;
|
||||||
pub use ash::device::DeviceV1_0;
|
|
||||||
|
|
||||||
// Simple offset_of macro akin to C++ offsetof
|
// Simple offset_of macro akin to C++ offsetof
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
|
@ -33,7 +33,7 @@ macro_rules! offset_of{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn record_submit_commandbuffer<F: FnOnce(&Device<V1_0>, vk::CommandBuffer)>(device: &Device<V1_0>,
|
pub fn record_submit_commandbuffer<D: DeviceV1_0, F: FnOnce(&D, vk::CommandBuffer)>(device: &D,
|
||||||
command_buffer: vk::CommandBuffer,
|
command_buffer: vk::CommandBuffer,
|
||||||
submit_queue: vk::Queue,
|
submit_queue: vk::Queue,
|
||||||
wait_mask: &[vk::PipelineStageFlags],
|
wait_mask: &[vk::PipelineStageFlags],
|
||||||
|
@ -592,6 +592,7 @@ impl ExampleBase {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for ExampleBase {
|
impl Drop for ExampleBase {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
unsafe {
|
unsafe {
|
||||||
|
|
|
@ -4,14 +4,11 @@ use std::mem;
|
||||||
use vk;
|
use vk;
|
||||||
use ::RawPtr;
|
use ::RawPtr;
|
||||||
|
|
||||||
use instance::{VkVersion, V1_0};
|
use version::{FunctionPointers, V1_0, DeviceFpV1_0};
|
||||||
|
|
||||||
// unsafe impl Sync for Device {}
|
// unsafe impl Sync for Device {}
|
||||||
// unsafe impl Send for Device {}
|
// unsafe impl Send for Device {}
|
||||||
|
|
||||||
pub struct DeviceFpV1_0 {
|
|
||||||
pub device_fn: vk::DeviceFnV1_0,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait DeviceV1_0 {
|
pub trait DeviceV1_0 {
|
||||||
fn handle(&self) -> vk::Device;
|
fn handle(&self) -> vk::Device;
|
||||||
|
@ -751,7 +748,7 @@ pub trait DeviceV1_0 {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Device<V: VkVersion> {
|
pub struct Device<V: FunctionPointers> {
|
||||||
handle: vk::Device,
|
handle: vk::Device,
|
||||||
device_fn: V::DeviceFp,
|
device_fn: V::DeviceFp,
|
||||||
}
|
}
|
||||||
|
@ -766,7 +763,7 @@ impl DeviceV1_0 for Device<V1_0> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<V: VkVersion> Device<V> {
|
impl<V: FunctionPointers> Device<V> {
|
||||||
pub fn handle(&self) -> vk::Device {
|
pub fn handle(&self) -> vk::Device {
|
||||||
self.handle
|
self.handle
|
||||||
}
|
}
|
||||||
|
|
52
src/entry.rs
52
src/entry.rs
|
@ -2,12 +2,12 @@ use prelude::*;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
use vk;
|
use vk;
|
||||||
use instance::{Instance, V1_0, InstanceFpV1_0};
|
use instance::Instance;
|
||||||
use shared_library::dynamic_library::DynamicLibrary;
|
use shared_library::dynamic_library::DynamicLibrary;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use ::RawPtr;
|
use ::RawPtr;
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
use instance::VkVersion;
|
use version::{FunctionPointers, V1_0, InstanceFpV1_0, InstanceLoader};
|
||||||
|
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
fn get_path() -> &'static Path {
|
fn get_path() -> &'static Path {
|
||||||
|
@ -29,11 +29,10 @@ lazy_static!{
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Entry<V: VkVersion> {
|
pub struct Entry<V: FunctionPointers> {
|
||||||
static_fn: vk::StaticFn,
|
static_fn: vk::StaticFn,
|
||||||
entry_fn: vk::EntryFn,
|
entry_fn: vk::EntryFn,
|
||||||
_v: PhantomData<V>
|
_v: PhantomData<V>,
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -48,12 +47,39 @@ pub enum InstanceError {
|
||||||
LoadError(Vec<&'static str>),
|
LoadError(Vec<&'static str>),
|
||||||
VkError(vk::Result),
|
VkError(vk::Result),
|
||||||
}
|
}
|
||||||
|
pub trait EntryExt {
|
||||||
impl Entry<V1_0>{
|
fn load_vulkan<V: FunctionPointers>() -> Result<Entry<V>, LoadingError> {
|
||||||
|
let static_fn = match *VK_LIB {
|
||||||
|
Ok(ref lib) => {
|
||||||
|
let static_fn = vk::StaticFn::load(|name| unsafe {
|
||||||
|
let name = name.to_str().unwrap();
|
||||||
|
let f = match lib.symbol(name) {
|
||||||
|
Ok(s) => s,
|
||||||
|
Err(_) => ptr::null(),
|
||||||
|
};
|
||||||
|
f
|
||||||
|
}).map_err(|err| LoadingError::StaticLoadError(err))?;
|
||||||
|
Ok(static_fn)
|
||||||
|
}
|
||||||
|
Err(ref err) => Err(LoadingError::LibraryLoadError(err.clone())),
|
||||||
|
}?;
|
||||||
|
let entry_fn = vk::EntryFn::load(|name| unsafe {
|
||||||
|
mem::transmute(static_fn.get_instance_proc_addr(vk::Instance::null(), name.as_ptr()))
|
||||||
|
}).map_err(|err| LoadingError::EntryLoadError(err))?;
|
||||||
|
Ok(Entry {
|
||||||
|
static_fn: static_fn,
|
||||||
|
entry_fn: entry_fn,
|
||||||
|
_v: PhantomData,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<V: FunctionPointers> EntryExt for Entry<V> {}
|
||||||
|
impl Entry<V1_0> {}
|
||||||
|
impl<V: FunctionPointers> Entry<V> {
|
||||||
pub fn create_instance(&self,
|
pub fn create_instance(&self,
|
||||||
create_info: &vk::InstanceCreateInfo,
|
create_info: &vk::InstanceCreateInfo,
|
||||||
allocation_callbacks: Option<&vk::AllocationCallbacks>)
|
allocation_callbacks: Option<&vk::AllocationCallbacks>)
|
||||||
-> Result<Instance<V1_0>, InstanceError> {
|
-> Result<Instance<V>, InstanceError> {
|
||||||
unsafe {
|
unsafe {
|
||||||
let mut instance: vk::Instance = mem::uninitialized();
|
let mut instance: vk::Instance = mem::uninitialized();
|
||||||
let err_code = self.entry_fn.create_instance(create_info,
|
let err_code = self.entry_fn.create_instance(create_info,
|
||||||
|
@ -62,14 +88,10 @@ impl Entry<V1_0>{
|
||||||
if err_code != vk::Result::Success {
|
if err_code != vk::Result::Success {
|
||||||
return Err(InstanceError::VkError(err_code));
|
return Err(InstanceError::VkError(err_code));
|
||||||
}
|
}
|
||||||
let instance_fn = vk::InstanceFnV1_0::load(|name| {
|
let instance_fp = V::InstanceFp::load(&self.static_fn, instance).map_err(|err| InstanceError::LoadError(err))?;
|
||||||
mem::transmute(self.static_fn.get_instance_proc_addr(instance, name.as_ptr()))
|
Ok(Instance::from_raw(instance, instance_fp))
|
||||||
}).map_err(|err| InstanceError::LoadError(err))?;
|
|
||||||
Ok(Instance::from_raw(instance, InstanceFpV1_0 { instance_fn: instance_fn }))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
impl<V: VkVersion> Entry<V> {
|
|
||||||
pub fn load_vulkan() -> Result<Entry<V>, LoadingError> {
|
pub fn load_vulkan() -> Result<Entry<V>, LoadingError> {
|
||||||
let static_fn = match *VK_LIB {
|
let static_fn = match *VK_LIB {
|
||||||
Ok(ref lib) => {
|
Ok(ref lib) => {
|
||||||
|
@ -91,7 +113,7 @@ impl<V: VkVersion> Entry<V> {
|
||||||
Ok(Entry {
|
Ok(Entry {
|
||||||
static_fn: static_fn,
|
static_fn: static_fn,
|
||||||
entry_fn: entry_fn,
|
entry_fn: entry_fn,
|
||||||
_v: PhantomData
|
_v: PhantomData,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@ use entry::Entry;
|
||||||
use vk;
|
use vk;
|
||||||
use std::ffi::CStr;
|
use std::ffi::CStr;
|
||||||
use ::RawPtr;
|
use ::RawPtr;
|
||||||
use instance::{V1_0, InstanceV1_0};
|
use version::{V1_0, InstanceFpV1_0};
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct DebugReport {
|
pub struct DebugReport {
|
||||||
|
|
|
@ -7,7 +7,7 @@ use entry::Entry;
|
||||||
use vk;
|
use vk;
|
||||||
use std::ffi::CStr;
|
use std::ffi::CStr;
|
||||||
use ::RawPtr;
|
use ::RawPtr;
|
||||||
use instance::{V1_0, InstanceV1_0};
|
use version::{V1_0};
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Surface {
|
pub struct Surface {
|
||||||
|
|
|
@ -6,7 +6,8 @@ use device::Device;
|
||||||
use vk;
|
use vk;
|
||||||
use std::ffi::CStr;
|
use std::ffi::CStr;
|
||||||
use ::RawPtr;
|
use ::RawPtr;
|
||||||
use instance::{V1_0, InstanceV1_0};
|
use instance::InstanceV1_0;
|
||||||
|
use version::{V1_0};
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Swapchain {
|
pub struct Swapchain {
|
||||||
|
|
|
@ -6,7 +6,8 @@ use entry::Entry;
|
||||||
use vk;
|
use vk;
|
||||||
use std::ffi::CStr;
|
use std::ffi::CStr;
|
||||||
use ::RawPtr;
|
use ::RawPtr;
|
||||||
use instance::{V1_0, InstanceV1_0};
|
use instance::InstanceV1_0;
|
||||||
|
use version::{V1_0};
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Win32Surface {
|
pub struct Win32Surface {
|
||||||
|
|
|
@ -6,7 +6,8 @@ use entry::Entry;
|
||||||
use vk;
|
use vk;
|
||||||
use std::ffi::CStr;
|
use std::ffi::CStr;
|
||||||
use ::RawPtr;
|
use ::RawPtr;
|
||||||
use instance::{V1_0, InstanceV1_0};
|
use instance::InstanceV1_0;
|
||||||
|
use version::{V1_0};
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct XlibSurface {
|
pub struct XlibSurface {
|
||||||
|
@ -15,7 +16,9 @@ pub struct XlibSurface {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl XlibSurface {
|
impl XlibSurface {
|
||||||
pub fn new(entry: &Entry<V1_0>, instance: &Instance<V1_0>) -> Result<XlibSurface, Vec<&'static str>> {
|
pub fn new(entry: &Entry<V1_0>,
|
||||||
|
instance: &Instance<V1_0>)
|
||||||
|
-> Result<XlibSurface, Vec<&'static str>> {
|
||||||
let surface_fn = vk::XlibSurfaceFn::load(|name| {
|
let surface_fn = vk::XlibSurfaceFn::load(|name| {
|
||||||
unsafe {
|
unsafe {
|
||||||
mem::transmute(entry.get_instance_proc_addr(instance.handle(), name.as_ptr()))
|
mem::transmute(entry.get_instance_proc_addr(instance.handle(), name.as_ptr()))
|
||||||
|
|
|
@ -3,8 +3,11 @@ use prelude::*;
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use vk;
|
use vk;
|
||||||
use device::{Device, DeviceFpV1_0};
|
use device::Device;
|
||||||
use ::RawPtr;
|
use ::RawPtr;
|
||||||
|
use version::{FunctionPointers, V1_0, InstanceFpV1_0, DeviceFpV1_0};
|
||||||
|
use version::{InstanceLoader, DeviceLoader};
|
||||||
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum DeviceError {
|
pub enum DeviceError {
|
||||||
|
@ -12,25 +15,9 @@ pub enum DeviceError {
|
||||||
VkError(vk::Result),
|
VkError(vk::Result),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait VkVersion {
|
|
||||||
type InstanceFp;
|
|
||||||
type DeviceFp;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[warn(non_camel_case_types)]
|
|
||||||
pub struct V1_0;
|
|
||||||
impl VkVersion for V1_0 {
|
|
||||||
type InstanceFp = InstanceFpV1_0;
|
|
||||||
type DeviceFp = DeviceFpV1_0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[warn(non_camel_case_types)]
|
|
||||||
pub struct InstanceFpV1_0 {
|
|
||||||
pub instance_fn: vk::InstanceFnV1_0,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Instance<V: VkVersion> {
|
pub struct Instance<V: FunctionPointers> {
|
||||||
handle: vk::Instance,
|
handle: vk::Instance,
|
||||||
instance_fp: V::InstanceFp,
|
instance_fp: V::InstanceFp,
|
||||||
}
|
}
|
||||||
|
@ -44,7 +31,7 @@ impl InstanceV1_0 for Instance<V1_0> {
|
||||||
&self.instance_fp.instance_fn
|
&self.instance_fp.instance_fn
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl<V: VkVersion> Instance<V> {
|
impl<V: FunctionPointers> Instance<V> {
|
||||||
pub fn handle(&self) -> vk::Instance {
|
pub fn handle(&self) -> vk::Instance {
|
||||||
self.handle
|
self.handle
|
||||||
}
|
}
|
||||||
|
@ -57,14 +44,15 @@ impl<V: VkVersion> Instance<V> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Instance<V1_0> {
|
impl<V: FunctionPointers> Instance<V> {
|
||||||
pub unsafe fn create_device(&self,
|
pub unsafe fn create_device(&self,
|
||||||
physical_device: vk::PhysicalDevice,
|
physical_device: vk::PhysicalDevice,
|
||||||
create_info: &vk::DeviceCreateInfo,
|
create_info: &vk::DeviceCreateInfo,
|
||||||
allocation_callbacks: Option<&vk::AllocationCallbacks>)
|
allocation_callbacks: Option<&vk::AllocationCallbacks>)
|
||||||
-> Result<Device<V1_0>, DeviceError> {
|
-> Result<Device<V>, DeviceError> {
|
||||||
let mut device: vk::Device = mem::uninitialized();
|
let mut device: vk::Device = mem::uninitialized();
|
||||||
let err_code = self.fp_v1_0()
|
let err_code = self.instance_fp
|
||||||
|
.fp_v1_0()
|
||||||
.create_device(physical_device,
|
.create_device(physical_device,
|
||||||
create_info,
|
create_info,
|
||||||
allocation_callbacks.as_raw_ptr(),
|
allocation_callbacks.as_raw_ptr(),
|
||||||
|
@ -72,10 +60,8 @@ impl Instance<V1_0> {
|
||||||
if err_code != vk::Result::Success {
|
if err_code != vk::Result::Success {
|
||||||
return Err(DeviceError::VkError(err_code));
|
return Err(DeviceError::VkError(err_code));
|
||||||
}
|
}
|
||||||
let device_fn = vk::DeviceFnV1_0::load(|name| {
|
let device_fn = V::DeviceFp::load(self.instance_fp.fp_v1_0(), device).map_err(|err| DeviceError::LoadError(err))?;
|
||||||
mem::transmute(self.fp_v1_0().get_device_proc_addr(device, name.as_ptr()))
|
Ok(Device::from_raw(device, device_fn))
|
||||||
}).map_err(|err| DeviceError::LoadError(err))?;
|
|
||||||
Ok(Device::from_raw(device, DeviceFpV1_0 { device_fn: device_fn }))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,13 +1,18 @@
|
||||||
extern crate shared_library;
|
extern crate shared_library;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate lazy_static;
|
extern crate lazy_static;
|
||||||
pub mod instance;
|
pub use instance::Instance;
|
||||||
pub mod device;
|
pub use device::Device;
|
||||||
|
pub use entry::Entry;
|
||||||
|
|
||||||
|
mod instance;
|
||||||
|
mod device;
|
||||||
pub mod entry;
|
pub mod entry;
|
||||||
pub mod prelude;
|
pub mod prelude;
|
||||||
pub mod vk;
|
pub mod vk;
|
||||||
pub mod allocator;
|
pub mod allocator;
|
||||||
pub mod extensions;
|
pub mod extensions;
|
||||||
|
pub mod version;
|
||||||
|
|
||||||
pub trait RawPtr<T>{
|
pub trait RawPtr<T>{
|
||||||
fn as_raw_ptr(&self) -> *const T;
|
fn as_raw_ptr(&self) -> *const T;
|
||||||
|
|
64
src/version.rs
Normal file
64
src/version.rs
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
use vk;
|
||||||
|
pub use instance::InstanceV1_0;
|
||||||
|
pub use device::DeviceV1_0;
|
||||||
|
use entry::EntryExt;
|
||||||
|
use std::mem;
|
||||||
|
pub trait FunctionPointers {
|
||||||
|
type InstanceFp: InstanceLoader;
|
||||||
|
type DeviceFp: DeviceLoader;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(non_camel_case_types)]
|
||||||
|
pub struct V1_0;
|
||||||
|
impl FunctionPointers for V1_0 {
|
||||||
|
type InstanceFp = InstanceFpV1_0;
|
||||||
|
type DeviceFp = DeviceFpV1_0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(non_camel_case_types)]
|
||||||
|
pub struct InstanceFpV1_0 {
|
||||||
|
pub instance_fn: vk::InstanceFnV1_0,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait InstanceLoader: Sized {
|
||||||
|
fn fp_v1_0(&self) -> &vk::InstanceFnV1_0;
|
||||||
|
unsafe fn load(static_fn: &vk::StaticFn,
|
||||||
|
instance: vk::Instance)
|
||||||
|
-> Result<Self, Vec<&'static str>>;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait DeviceLoader: Sized {
|
||||||
|
unsafe fn load(instance_fn: &vk::InstanceFnV1_0,
|
||||||
|
device: vk::Device)
|
||||||
|
-> Result<Self, Vec<&'static str>>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DeviceLoader for DeviceFpV1_0 {
|
||||||
|
unsafe fn load(instance_fn: &vk::InstanceFnV1_0,
|
||||||
|
device: vk::Device)
|
||||||
|
-> Result<Self, Vec<&'static str>> {
|
||||||
|
let device_fn = vk::DeviceFnV1_0::load(|name| {
|
||||||
|
mem::transmute(instance_fn.get_device_proc_addr(device, name.as_ptr()))
|
||||||
|
})?;
|
||||||
|
Ok(DeviceFpV1_0 { device_fn: device_fn })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl InstanceLoader for InstanceFpV1_0 {
|
||||||
|
fn fp_v1_0(&self) -> &vk::InstanceFnV1_0{
|
||||||
|
&self.instance_fn
|
||||||
|
}
|
||||||
|
unsafe fn load(static_fn: &vk::StaticFn,
|
||||||
|
instance: vk::Instance)
|
||||||
|
-> Result<Self, Vec<&'static str>> {
|
||||||
|
let instance_fn = vk::InstanceFnV1_0::load(|name| {
|
||||||
|
mem::transmute(static_fn.get_instance_proc_addr(instance, name.as_ptr()))
|
||||||
|
})?;
|
||||||
|
Ok(InstanceFpV1_0 { instance_fn: instance_fn })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(non_camel_case_types)]
|
||||||
|
pub struct DeviceFpV1_0 {
|
||||||
|
pub device_fn: vk::DeviceFnV1_0,
|
||||||
|
}
|
Loading…
Reference in a new issue