use std::{ffi::CString, ops::Deref, ptr};
use util::{
vk_bool, vk_call, vk_get, vk_get_many, vk_query, vk_query_many, vk_query_n, vk_run,
vk_slice_len,
};
use vk_sys as vk;
pub struct EntryPoints {
ptr: vk::EntryPoints,
}
pub type Result<T> = std::result::Result<T, vk::Result>;
impl EntryPoints {
pub fn new(ptr: vk::EntryPoints) -> Self {
Self { ptr }
}
pub fn into_inner(self) -> vk::EntryPoints {
self.ptr
}
#[inline]
pub unsafe fn create_instance(
&self,
create_info: &vk::InstanceCreateInfo,
) -> Result<vk::Instance> {
vk_query(|data| self.ptr.CreateInstance(create_info, ptr::null(), data))
}
#[inline]
pub fn enumerate_instance_extension_properties(&self) -> Result<Vec<vk::ExtensionProperties>> {
vk_query_many(|count, data| unsafe {
self.ptr
.EnumerateInstanceExtensionProperties(std::ptr::null(), count, data)
})
}
#[inline]
pub fn enumerate_instance_layer_properties(&self) -> Result<Vec<vk::LayerProperties>> {
vk_query_many(|count, data| unsafe {
self.ptr.EnumerateInstanceLayerProperties(count, data)
})
}
}
impl Deref for EntryPoints {
type Target = vk::EntryPoints;
fn deref(&self) -> &Self::Target {
&self.ptr
}
}
impl<T: Into<vk::EntryPoints>> From<T> for EntryPoints {
fn from(ptr: T) -> Self {
EntryPoints::new(ptr.into())
}
}
pub struct InstancePointers {
ptr: vk::InstancePointers,
}
impl InstancePointers {
pub fn new(ptr: vk::InstancePointers) -> Self {
Self { ptr }
}
pub fn into_inner(self) -> vk::InstancePointers {
self.ptr
}
#[inline]
pub fn destroy_instance(&self, instance: vk::Instance) {
vk_run(|| unsafe {
self.ptr.DestroyInstance(instance, ptr::null());
});
}
#[inline]
pub fn enumerate_physical_devices(
&self,
instance: vk::Instance,
) -> Result<Vec<vk::PhysicalDevice>> {
vk_query_many(|count, data| unsafe {
self.ptr.EnumeratePhysicalDevices(instance, count, data)
})
}
#[inline]
pub fn enumerate_device_extension_properties<T: Into<Vec<u8>>>(
&self,
physical_device: vk::PhysicalDevice,
layer_name: Option<&CString>,
) -> Result<Vec<vk::ExtensionProperties>> {
vk_query_many(|count, data| unsafe {
self.ptr.EnumerateDeviceExtensionProperties(
physical_device,
layer_name.map(|cstr| cstr.as_ptr()).unwrap_or(ptr::null()),
count,
data,
)
})
}
#[inline]
pub unsafe fn create_device(
&self,
physical_device: vk::PhysicalDevice,
create_info: &vk::DeviceCreateInfo,
) -> Result<vk::Device> {
vk_query(|data| {
self.ptr
.CreateDevice(physical_device, create_info, std::ptr::null(), data)
})
}
#[inline]
pub fn get_physical_device_properties(
&self,
physical_device: vk::PhysicalDevice,
) -> vk::PhysicalDeviceProperties {
vk_get(|data| {
unsafe { self.ptr.GetPhysicalDeviceProperties(physical_device, data) };
})
}
#[inline]
pub fn get_physical_device_queue_family_properties(
&self,
physical_device: vk::PhysicalDevice,
) -> Vec<vk::QueueFamilyProperties> {
vk_get_many(|count, data| unsafe {
self.ptr
.GetPhysicalDeviceQueueFamilyProperties(physical_device, count, data)
})
}
#[inline]
pub fn get_physical_device_memory_properties(
&self,
physical_device: vk::PhysicalDevice,
) -> vk::PhysicalDeviceMemoryProperties {
vk_get(|data| unsafe {
self.ptr
.GetPhysicalDeviceMemoryProperties(physical_device, data);
})
}
#[inline]
pub fn destroy_surface_khr(&self, instance: vk::Instance, surface: vk::SurfaceKHR) {
vk_run(|| unsafe {
self.ptr.DestroySurfaceKHR(instance, surface, ptr::null());
});
}
#[inline]
pub fn get_physical_device_surface_support_khr(
&self,
physical_device: vk::PhysicalDevice,
queue_family_index: u32,
surface: vk::SurfaceKHR,
) -> Result<bool> {
vk_query(|data| unsafe {
self.ptr.GetPhysicalDeviceSurfaceSupportKHR(
physical_device,
queue_family_index,
surface,
data,
)
})
.map(|supported| supported == vk::TRUE)
}
#[inline]
pub fn get_physical_device_surface_capabilities_khr(
&self,
physical_device: vk::PhysicalDevice,
surface: vk::SurfaceKHR,
) -> Result<vk::SurfaceCapabilitiesKHR> {
vk_query(|data| unsafe {
self.ptr
.GetPhysicalDeviceSurfaceCapabilitiesKHR(physical_device, surface, data)
})
}
#[inline]
pub fn get_physical_device_surface_formats_khr(
&self,
physical_device: vk::PhysicalDevice,
surface: vk::SurfaceKHR,
) -> Result<Vec<vk::SurfaceFormatKHR>> {
vk_query_many(|count, data| unsafe {
self.ptr
.GetPhysicalDeviceSurfaceFormatsKHR(physical_device, surface, count, data)
})
}
#[inline]
pub fn get_physical_device_surface_present_modes_khr(
&self,
physical_device: vk::PhysicalDevice,
surface: vk::SurfaceKHR,
) -> Result<Vec<vk::PresentModeKHR>> {
vk_query_many(|count, data| unsafe {
self.ptr
.GetPhysicalDeviceSurfacePresentModesKHR(physical_device, surface, count, data)
})
}
#[inline]
pub unsafe fn create_debug_utils_messenger_ext(
&self,
instance: vk::Instance,
create_info: &vk::DebugUtilsMessengerCreateInfoEXT,
) -> Result<vk::DebugUtilsMessengerEXT> {
vk_query(|data| {
self.ptr
.CreateDebugUtilsMessengerEXT(instance, create_info, ptr::null(), data)
})
}
#[inline]
pub fn destroy_debug_utils_messenger_ext(
&self,
instance: vk::Instance,
messenger: vk::DebugUtilsMessengerEXT,
) -> Result<()> {
vk_call(|| unsafe {
self.ptr
.DestroyDebugUtilsMessengerEXT(instance, messenger, ptr::null())
})
}
}
impl Deref for InstancePointers {
type Target = vk::InstancePointers;
fn deref(&self) -> &Self::Target {
&self.ptr
}
}
impl<T: Into<vk::InstancePointers>> From<T> for InstancePointers {
fn from(ptr: T) -> Self {
InstancePointers::new(ptr.into())
}
}
pub struct DevicePointers {
ptr: vk::DevicePointers,
}
impl DevicePointers {
pub fn new(ptr: vk::DevicePointers) -> Self {
Self { ptr }
}
pub fn into_inner(self) -> vk::DevicePointers {
self.ptr
}
#[inline]
pub fn destroy_device(&self, device: vk::Device) {
vk_run(|| unsafe {
self.ptr.DestroyDevice(device, ptr::null());
});
}
#[inline]
pub fn get_device_queue(
&self,
device: vk::Device,
queue_family_index: u32,
queue_index: u32,
) -> vk::Queue {
vk_get(|data| unsafe {
self.ptr
.GetDeviceQueue(device, queue_family_index, queue_index, data)
})
}
#[inline]
pub unsafe fn queue_submit(
&self,
queue: vk::Queue,
submits: &[vk::SubmitInfo],
fence: vk::Fence,
) -> Result<()> {
vk_call(|| {
self.ptr
.QueueSubmit(queue, vk_slice_len(submits), submits.as_ptr(), fence)
})
}
#[inline]
pub fn queue_wait_idle(&self, queue: vk::Queue) -> Result<()> {
vk_call(|| unsafe { self.ptr.QueueWaitIdle(queue) })
}
#[inline]
pub fn device_wait_idle(&self, device: vk::Device) -> Result<()> {
vk_call(|| unsafe { self.ptr.DeviceWaitIdle(device) })
}
#[inline]
pub unsafe fn allocate_memory(
&self,
device: vk::Device,
allocate_info: &vk::MemoryAllocateInfo,
) -> Result<vk::DeviceMemory> {
vk_query(|data| {
self.ptr
.AllocateMemory(device, allocate_info, ptr::null(), data)
})
}
#[inline]
pub fn free_memory(&self, device: vk::Device, memory: vk::DeviceMemory) {
vk_run(|| unsafe {
self.ptr.FreeMemory(device, memory, ptr::null());
});
}
#[inline]
pub fn map_memory(
&self,
device: vk::Device,
memory: vk::DeviceMemory,
offset: vk::DeviceSize,
size: vk::DeviceSize,
flags: vk::MemoryMapFlags,
) -> Result<*mut std::ffi::c_void> {
vk_query(|data| unsafe {
self.ptr
.MapMemory(device, memory, offset, size, flags, data)
})
}
#[inline]
pub fn unmap_memory(&self, device: vk::Device, memory: vk::DeviceMemory) {
vk_run(|| unsafe {
self.ptr.UnmapMemory(device, memory);
});
}
#[inline]
pub fn bind_buffer_memory(
&self,
device: vk::Device,
buffer: vk::Buffer,
memory: vk::DeviceMemory,
memory_offset: vk::DeviceSize,
) -> Result<()> {
vk_call(|| unsafe {
self.ptr
.BindBufferMemory(device, buffer, memory, memory_offset)
})
}
#[inline]
pub fn get_buffer_memory_requirements(
&self,
device: vk::Device,
buffer: vk::Buffer,
) -> vk::MemoryRequirements {
vk_get(|data| unsafe { self.ptr.GetBufferMemoryRequirements(device, buffer, data) })
}
#[inline]
pub unsafe fn create_fence(
&self,
device: vk::Device,
create_info: &vk::FenceCreateInfo,
) -> Result<vk::Fence> {
vk_query(|data| self.ptr.CreateFence(device, create_info, ptr::null(), data))
}
#[inline]
pub fn destroy_fence(&self, device: vk::Device, fence: vk::Fence) {
vk_run(|| unsafe {
self.ptr.DestroyFence(device, fence, ptr::null());
});
}
#[inline]
pub fn reset_fences(&self, device: vk::Device, fences: &[vk::Fence]) -> Result<()> {
vk_call(|| unsafe {
self.ptr
.ResetFences(device, vk_slice_len(&fences), fences.as_ptr())
})
}
#[inline]
pub fn wait_for_fences(
&self,
device: vk::Device,
fences: &[vk::Fence],
wait_all: bool,
timeout: u64,
) -> Result<()> {
vk_call(|| unsafe {
self.ptr.WaitForFences(
device,
vk_slice_len(fences),
fences.as_ptr(),
vk_bool(wait_all),
timeout,
)
})
}
#[inline]
pub unsafe fn create_semaphore(
&self,
device: vk::Device,
create_info: &vk::SemaphoreCreateInfo,
) -> Result<vk::Semaphore> {
vk_query(|data| {
self.ptr
.CreateSemaphore(device, create_info, ptr::null(), data)
})
}
#[inline]
pub fn destroy_semaphore(&self, device: vk::Device, semaphore: vk::Semaphore) {
vk_run(|| unsafe {
self.ptr.DestroySemaphore(device, semaphore, ptr::null());
});
}
#[inline]
pub unsafe fn create_buffer(
&self,
device: vk::Device,
create_info: &vk::BufferCreateInfo,
) -> Result<vk::Buffer> {
vk_query(|data| {
self.ptr
.CreateBuffer(device, create_info, ptr::null(), data)
})
}
#[inline]
pub fn destroy_buffer(&self, device: vk::Device, buffer: vk::Buffer) {
vk_run(|| unsafe {
self.ptr.DestroyBuffer(device, buffer, ptr::null());
});
}
#[inline]
pub unsafe fn create_image_view(
&self,
device: vk::Device,
create_info: &vk::ImageViewCreateInfo,
) -> Result<vk::ImageView> {
vk_query(|data| {
self.ptr
.CreateImageView(device, create_info, ptr::null(), data)
})
}
#[inline]
pub fn destroy_image_view(&self, device: vk::Device, image_view: vk::ImageView) {
vk_run(|| unsafe {
self.ptr.DestroyImageView(device, image_view, ptr::null());
});
}
#[inline]
pub unsafe fn create_shader_module(
&self,
device: vk::Device,
create_info: &vk::ShaderModuleCreateInfo,
) -> Result<vk::ShaderModule> {
vk_query(|data| {
self.ptr
.CreateShaderModule(device, create_info, ptr::null(), data)
})
}
#[inline]
pub fn destroy_shader_module(&self, device: vk::Device, shader_module: vk::ShaderModule) {
vk_run(|| unsafe {
self.ptr
.DestroyShaderModule(device, shader_module, ptr::null());
});
}
#[inline]
pub unsafe fn create_graphics_pipelines(
&self,
device: vk::Device,
pipeline_cache: vk::PipelineCache,
create_infos: &[vk::GraphicsPipelineCreateInfo],
) -> Result<Vec<vk::Pipeline>> {
let count = vk_slice_len(create_infos);
vk_query_n(count, |data| {
self.ptr.CreateGraphicsPipelines(
device,
pipeline_cache,
count,
create_infos.as_ptr(),
ptr::null(),
data,
)
})
}
#[inline]
pub fn destroy_pipeline(&self, device: vk::Device, pipeline: vk::Pipeline) {
vk_run(|| unsafe {
self.ptr.DestroyPipeline(device, pipeline, ptr::null());
});
}
#[inline]
pub unsafe fn create_pipeline_layout(
&self,
device: vk::Device,
create_info: &vk::PipelineLayoutCreateInfo,
) -> Result<vk::PipelineLayout> {
vk_query(|data| {
self.ptr
.CreatePipelineLayout(device, create_info, ptr::null(), data)
})
}
#[inline]
pub fn destroy_pipeline_layout(&self, device: vk::Device, pipeline_layout: vk::PipelineLayout) {
vk_run(|| unsafe {
self.ptr
.DestroyPipelineLayout(device, pipeline_layout, ptr::null());
});
}
#[inline]
pub unsafe fn create_framebuffer(
&self,
device: vk::Device,
create_info: &vk::FramebufferCreateInfo,
) -> Result<vk::Framebuffer> {
vk_query(|data| {
self.ptr
.CreateFramebuffer(device, create_info, ptr::null(), data)
})
}
#[inline]
pub fn destroy_framebuffer(&self, device: vk::Device, framebuffer: vk::Framebuffer) {
vk_run(|| unsafe {
self.ptr
.DestroyFramebuffer(device, framebuffer, ptr::null());
});
}
#[inline]
pub unsafe fn create_render_pass(
&self,
device: vk::Device,
create_info: &vk::RenderPassCreateInfo,
) -> Result<vk::RenderPass> {
vk_query(|data| {
self.ptr
.CreateRenderPass(device, create_info, ptr::null(), data)
})
}
#[inline]
pub fn destroy_render_pass(&self, device: vk::Device, render_pass: vk::RenderPass) {
vk_run(|| unsafe {
self.ptr.DestroyRenderPass(device, render_pass, ptr::null());
});
}
#[inline]
pub unsafe fn create_command_pool(
&self,
device: vk::Device,
create_info: &vk::CommandPoolCreateInfo,
) -> Result<vk::CommandPool> {
vk_query(|data| {
self.ptr
.CreateCommandPool(device, create_info, ptr::null(), data)
})
}
#[inline]
pub fn destroy_command_pool(&self, device: vk::Device, command_pool: vk::CommandPool) {
vk_run(|| unsafe {
self.ptr
.DestroyCommandPool(device, command_pool, ptr::null());
});
}
#[inline]
pub unsafe fn allocate_command_buffers(
&self,
device: vk::Device,
allocate_info: &vk::CommandBufferAllocateInfo,
) -> Result<Vec<vk::CommandBuffer>> {
let count = allocate_info.commandBufferCount;
vk_query_n(count, |data| {
self.ptr.AllocateCommandBuffers(device, allocate_info, data)
})
}
#[inline]
pub fn free_command_buffers(
&self,
device: vk::Device,
command_pool: vk::CommandPool,
command_buffers: &[vk::CommandBuffer],
) {
vk_run(|| unsafe {
self.ptr.FreeCommandBuffers(
device,
command_pool,
vk_slice_len(command_buffers),
command_buffers.as_ptr(),
);
});
}
#[inline]
pub unsafe fn begin_command_buffer(
&self,
command_buffer: vk::CommandBuffer,
begin_info: &vk::CommandBufferBeginInfo,
) -> Result<()> {
vk_call(|| self.ptr.BeginCommandBuffer(command_buffer, begin_info))
}
#[inline]
pub fn end_command_buffer(&self, command_buffer: vk::CommandBuffer) -> Result<()> {
vk_call(|| unsafe { self.ptr.EndCommandBuffer(command_buffer) })
}
#[inline]
pub fn reset_command_buffer(
&self,
command_buffer: vk::CommandBuffer,
flags: vk::CommandBufferResetFlags,
) -> Result<()> {
vk_call(|| unsafe { self.ptr.ResetCommandBuffer(command_buffer, flags) })
}
#[inline]
pub fn cmd_bind_pipeline(
&self,
command_buffer: vk::CommandBuffer,
pipeline_bind_point: vk::PipelineBindPoint,
pipeline: vk::Pipeline,
) {
vk_run(|| unsafe {
self.ptr
.CmdBindPipeline(command_buffer, pipeline_bind_point, pipeline)
})
}
#[inline]
pub fn cmd_bind_vertex_buffers(
&self,
command_buffer: vk::CommandBuffer,
first_binding: u32,
buffers: &[vk::Buffer],
offsets: &[vk::DeviceSize],
) {
let count = buffers.len();
assert_eq!(count, offsets.len());
vk_run(|| unsafe {
self.ptr.CmdBindVertexBuffers(
command_buffer,
first_binding,
count as u32,
buffers.as_ptr(),
offsets.as_ptr(),
);
});
}
#[inline]
pub fn cmd_draw(
&self,
command_buffer: vk::CommandBuffer,
vertex_count: u32,
instance_count: u32,
first_vertex: u32,
first_instance: u32,
) {
vk_run(|| unsafe {
self.ptr.CmdDraw(
command_buffer,
vertex_count,
instance_count,
first_vertex,
first_instance,
);
});
}
#[inline]
pub unsafe fn cmd_begin_render_pass(
&self,
command_buffer: vk::CommandBuffer,
render_pass_begin: &vk::RenderPassBeginInfo,
contents: vk::SubpassContents,
) {
vk_run(|| {
self.ptr
.CmdBeginRenderPass(command_buffer, render_pass_begin, contents);
});
}
#[inline]
pub fn cmd_end_render_pass(&self, command_buffer: vk::CommandBuffer) {
vk_run(|| unsafe {
self.ptr.CmdEndRenderPass(command_buffer);
});
}
#[inline]
pub unsafe fn create_swapchain_khr(
&self,
device: vk::Device,
create_info: &vk::SwapchainCreateInfoKHR,
) -> Result<vk::SwapchainKHR> {
vk_query(|data| {
self.ptr
.CreateSwapchainKHR(device, create_info, ptr::null(), data)
})
}
#[inline]
pub fn destroy_swapchain_khr(&self, device: vk::Device, swapchain: vk::SwapchainKHR) {
vk_run(|| unsafe {
self.ptr.DestroySwapchainKHR(device, swapchain, ptr::null());
});
}
#[inline]
pub fn get_swapchain_images_khr(
&self,
device: vk::Device,
swapchain: vk::SwapchainKHR,
) -> Result<Vec<vk::Image>> {
vk_query_many(|count, data| unsafe {
self.ptr
.GetSwapchainImagesKHR(device, swapchain, count, data)
})
}
#[inline]
pub fn acquire_next_image_khr(
&self,
device: vk::Device,
swapchain: vk::SwapchainKHR,
timeout: u64,
semaphore: vk::Semaphore,
fence: vk::Fence,
) -> Result<u32> {
vk_query(|data| unsafe {
self.ptr
.AcquireNextImageKHR(device, swapchain, timeout, semaphore, fence, data)
})
}
#[inline]
pub unsafe fn queue_present_khr(
&self,
queue: vk::Queue,
present_info: &vk::PresentInfoKHR,
) -> Result<()> {
vk_call(|| self.ptr.QueuePresentKHR(queue, present_info))
}
}
impl Deref for DevicePointers {
type Target = vk::DevicePointers;
fn deref(&self) -> &Self::Target {
&self.ptr
}
}
impl<T: Into<vk::DevicePointers>> From<T> for DevicePointers {
fn from(ptr: T) -> Self {
DevicePointers::new(ptr.into())
}
}
mod util {
use super::Result;
use std::mem;
use vk_sys as vk;
#[inline]
pub fn vk_bool(b: bool) -> vk::Bool32 {
if b {
vk::TRUE
} else {
vk::FALSE
}
}
#[inline]
pub fn vk_slice_len<T>(slice: &[T]) -> u32 {
let len = slice.len();
debug_assert!(len <= u32::MAX as usize);
len as u32
}
#[inline]
pub fn vk_run<F: FnOnce()>(vk_api_call: F) {
vk_api_call();
}
pub fn vk_call<F: FnOnce() -> vk::Result>(vk_api_call: F) -> Result<()> {
let result = vk_api_call();
if result == vk::SUCCESS {
Ok(())
} else {
Err(result)
}
}
pub fn vk_query_many<T, F: Fn(*mut u32, *mut T) -> vk::Result>(
vk_api_call: F,
) -> Result<Vec<T>> {
let mut count = mem::MaybeUninit::<u32>::uninit();
let result = vk_api_call(count.as_mut_ptr(), std::ptr::null_mut());
if result != vk::SUCCESS {
return Err(result);
}
let len = unsafe { count.assume_init() } as usize;
let mut data = Vec::<T>::with_capacity(len);
let result = vk_api_call(count.as_mut_ptr(), data.as_mut_ptr());
if result != vk::SUCCESS {
return Err(result);
}
unsafe { data.set_len(len) };
Ok(data)
}
pub fn vk_query_n<T, F: FnOnce(*mut T) -> vk::Result>(
count: u32,
vk_api_call: F,
) -> Result<Vec<T>> {
let len = count as usize;
let mut data = Vec::<T>::with_capacity(len);
let result = vk_api_call(data.as_mut_ptr());
if result != vk::SUCCESS {
return Err(result);
}
unsafe { data.set_len(len) };
Ok(data)
}
pub fn vk_get<T, F: FnOnce(*mut T)>(vk_api_call: F) -> T {
let mut data = mem::MaybeUninit::<T>::uninit();
vk_api_call(data.as_mut_ptr());
unsafe { data.assume_init() }
}
pub fn vk_get_many<T, F: Fn(*mut u32, *mut T)>(vk_api_call: F) -> Vec<T> {
let mut count = mem::MaybeUninit::<u32>::uninit();
vk_api_call(count.as_mut_ptr(), std::ptr::null_mut());
let len = unsafe { count.assume_init() } as usize;
let mut data = Vec::<T>::with_capacity(len);
vk_api_call(count.as_mut_ptr(), data.as_mut_ptr());
unsafe { data.set_len(len) };
data
}
pub fn vk_query<T, F: FnOnce(*mut T) -> vk::Result>(vk_api_call: F) -> Result<T> {
let mut data = mem::MaybeUninit::<T>::uninit();
let result = vk_api_call(data.as_mut_ptr());
if result != vk::SUCCESS {
return Err(result);
}
Ok(unsafe { data.assume_init() })
}
}