use super::vulkan_global_api::{proc_loader, read_into_vec};
use crate::IVulkanDevice;
use ash::vk;
use std::ffi::c_void;
use std::ptr;
pub struct VulkanDeviceApi {
fp: ash::DeviceFnV1_0,
swapchain: ash::khr::swapchain::DeviceFn,
external_semaphore_fd: ash::khr::external_semaphore_fd::DeviceFn,
external_semaphore_win32: ash::khr::external_semaphore_win32::DeviceFn,
}
fn created<T>(result: vk::Result, value: T) -> Result<T, vk::Result> {
match result {
vk::Result::SUCCESS => Ok(value),
error => Err(error),
}
}
impl VulkanDeviceApi {
pub fn new(device: &dyn IVulkanDevice) -> Self {
let instance = device.instance();
let device_handle = device.handle();
let instance_handle = instance.handle();
let lookup = |name: &str| {
let addr = instance.get_device_proc_address(device_handle, name);
if addr != 0 {
return addr;
}
instance.get_instance_proc_address(instance_handle, name)
};
Self {
fp: ash::DeviceFnV1_0::load(proc_loader(lookup)),
swapchain: ash::khr::swapchain::DeviceFn::load(proc_loader(lookup)),
external_semaphore_fd: ash::khr::external_semaphore_fd::DeviceFn::load(proc_loader(lookup)),
external_semaphore_win32: ash::khr::external_semaphore_win32::DeviceFn::load(proc_loader(lookup)),
}
}
pub fn create_fence(&self, device: vk::Device, create_info: &vk::FenceCreateInfo<'_>) -> Result<vk::Fence, vk::Result> {
let mut fence = vk::Fence::null();
let result = unsafe { (self.fp.create_fence)(device, create_info, ptr::null(), &mut fence) };
created(result, fence)
}
pub fn destroy_fence(&self, device: vk::Device, fence: vk::Fence) {
unsafe { (self.fp.destroy_fence)(device, fence, ptr::null()) };
}
pub fn create_command_pool(
&self,
device: vk::Device,
create_info: &vk::CommandPoolCreateInfo<'_>,
) -> Result<vk::CommandPool, vk::Result> {
let mut pool = vk::CommandPool::null();
let result = unsafe { (self.fp.create_command_pool)(device, create_info, ptr::null(), &mut pool) };
created(result, pool)
}
pub fn destroy_command_pool(&self, device: vk::Device, pool: vk::CommandPool) {
unsafe { (self.fp.destroy_command_pool)(device, pool, ptr::null()) };
}
pub fn allocate_command_buffers(
&self,
device: vk::Device,
allocate_info: &vk::CommandBufferAllocateInfo<'_>,
) -> Result<Vec<vk::CommandBuffer>, vk::Result> {
let mut buffers = vec![vk::CommandBuffer::null(); allocate_info.command_buffer_count as usize];
let result = unsafe { (self.fp.allocate_command_buffers)(device, allocate_info, buffers.as_mut_ptr()) };
created(result, buffers)
}
pub fn free_command_buffers(&self, device: vk::Device, command_pool: vk::CommandPool, buffers: &[vk::CommandBuffer]) {
unsafe { (self.fp.free_command_buffers)(device, command_pool, buffers.len() as u32, buffers.as_ptr()) };
}
pub fn wait_for_fences(&self, device: vk::Device, fences: &[vk::Fence], wait_all: bool, timeout: u64) -> vk::Result {
unsafe {
(self.fp.wait_for_fences)(device, fences.len() as u32, fences.as_ptr(), wait_all as vk::Bool32, timeout)
}
}
pub fn get_fence_status(&self, device: vk::Device, fence: vk::Fence) -> vk::Result {
unsafe { (self.fp.get_fence_status)(device, fence) }
}
pub fn begin_command_buffer(
&self,
command_buffer: vk::CommandBuffer,
begin_info: &vk::CommandBufferBeginInfo<'_>,
) -> vk::Result {
unsafe { (self.fp.begin_command_buffer)(command_buffer, begin_info) }
}
pub fn end_command_buffer(&self, command_buffer: vk::CommandBuffer) -> vk::Result {
unsafe { (self.fp.end_command_buffer)(command_buffer) }
}
pub fn create_semaphore(
&self,
device: vk::Device,
create_info: &vk::SemaphoreCreateInfo<'_>,
) -> Result<vk::Semaphore, vk::Result> {
let mut semaphore = vk::Semaphore::null();
let result = unsafe { (self.fp.create_semaphore)(device, create_info, ptr::null(), &mut semaphore) };
created(result, semaphore)
}
pub fn destroy_semaphore(&self, device: vk::Device, semaphore: vk::Semaphore) {
unsafe { (self.fp.destroy_semaphore)(device, semaphore, ptr::null()) };
}
pub fn reset_fences(&self, device: vk::Device, fences: &[vk::Fence]) -> vk::Result {
unsafe { (self.fp.reset_fences)(device, fences.len() as u32, fences.as_ptr()) }
}
pub fn queue_submit(
&self,
queue: vk::Queue,
wait_semaphores: &[vk::Semaphore],
wait_dst_stage_mask: &[vk::PipelineStageFlags],
command_buffers: &[vk::CommandBuffer],
signal_semaphores: &[vk::Semaphore],
fence: vk::Fence,
) -> vk::Result {
assert!(wait_dst_stage_mask.len() >= wait_semaphores.len(), "a stage mask for every semaphore to wait for");
let submit_info = vk::SubmitInfo {
wait_semaphore_count: wait_semaphores.len() as u32,
p_wait_semaphores: wait_semaphores.as_ptr(),
p_wait_dst_stage_mask: wait_dst_stage_mask.as_ptr(),
command_buffer_count: command_buffers.len() as u32,
p_command_buffers: command_buffers.as_ptr(),
signal_semaphore_count: signal_semaphores.len() as u32,
p_signal_semaphores: signal_semaphores.as_ptr(),
..Default::default()
};
unsafe { (self.fp.queue_submit)(queue, 1, &submit_info, fence) }
}
pub fn create_image(&self, device: vk::Device, create_info: &vk::ImageCreateInfo<'_>) -> Result<vk::Image, vk::Result> {
let mut image = vk::Image::null();
let result = unsafe { (self.fp.create_image)(device, create_info, ptr::null(), &mut image) };
created(result, image)
}
pub fn destroy_image(&self, device: vk::Device, image: vk::Image) {
unsafe { (self.fp.destroy_image)(device, image, ptr::null()) };
}
pub fn get_image_memory_requirements(&self, device: vk::Device, image: vk::Image) -> vk::MemoryRequirements {
let mut requirements = vk::MemoryRequirements::default();
unsafe { (self.fp.get_image_memory_requirements)(device, image, &mut requirements) };
requirements
}
pub fn allocate_memory(
&self,
device: vk::Device,
allocate_info: &vk::MemoryAllocateInfo<'_>,
) -> Result<vk::DeviceMemory, vk::Result> {
let mut memory = vk::DeviceMemory::null();
let result = unsafe { (self.fp.allocate_memory)(device, allocate_info, ptr::null(), &mut memory) };
created(result, memory)
}
pub fn free_memory(&self, device: vk::Device, memory: vk::DeviceMemory) {
unsafe { (self.fp.free_memory)(device, memory, ptr::null()) };
}
pub fn bind_image_memory(
&self,
device: vk::Device,
image: vk::Image,
memory: vk::DeviceMemory,
memory_offset: vk::DeviceSize,
) -> vk::Result {
unsafe { (self.fp.bind_image_memory)(device, image, memory, memory_offset) }
}
pub fn create_image_view(
&self,
device: vk::Device,
create_info: &vk::ImageViewCreateInfo<'_>,
) -> Result<vk::ImageView, vk::Result> {
let mut view = vk::ImageView::null();
let result = unsafe { (self.fp.create_image_view)(device, create_info, ptr::null(), &mut view) };
created(result, view)
}
pub fn destroy_image_view(&self, device: vk::Device, image_view: vk::ImageView) {
unsafe { (self.fp.destroy_image_view)(device, image_view, ptr::null()) };
}
pub fn create_buffer(&self, device: vk::Device, create_info: &vk::BufferCreateInfo<'_>) -> Result<vk::Buffer, vk::Result> {
let mut buffer = vk::Buffer::null();
let result = unsafe { (self.fp.create_buffer)(device, create_info, ptr::null(), &mut buffer) };
created(result, buffer)
}
pub fn destroy_buffer(&self, device: vk::Device, buffer: vk::Buffer) {
unsafe { (self.fp.destroy_buffer)(device, buffer, ptr::null()) };
}
pub fn get_buffer_memory_requirements(&self, device: vk::Device, buffer: vk::Buffer) -> vk::MemoryRequirements {
let mut requirements = vk::MemoryRequirements::default();
unsafe { (self.fp.get_buffer_memory_requirements)(device, buffer, &mut requirements) };
requirements
}
pub fn bind_buffer_memory(
&self,
device: vk::Device,
buffer: vk::Buffer,
memory: vk::DeviceMemory,
memory_offset: vk::DeviceSize,
) -> vk::Result {
unsafe { (self.fp.bind_buffer_memory)(device, buffer, memory, memory_offset) }
}
pub fn map_memory(
&self,
device: vk::Device,
memory: vk::DeviceMemory,
offset: vk::DeviceSize,
size: vk::DeviceSize,
flags: u32,
) -> Result<*mut c_void, vk::Result> {
let mut data = ptr::null_mut();
let result = unsafe {
(self.fp.map_memory)(device, memory, offset, size, vk::MemoryMapFlags::from_raw(flags), &mut data)
};
created(result, data)
}
pub fn unmap_memory(&self, device: vk::Device, memory: vk::DeviceMemory) {
unsafe { (self.fp.unmap_memory)(device, memory) };
}
pub fn cmd_copy_image_to_buffer(
&self,
command_buffer: vk::CommandBuffer,
src_image: vk::Image,
src_image_layout: vk::ImageLayout,
dst_buffer: vk::Buffer,
regions: &[vk::BufferImageCopy],
) {
unsafe {
(self.fp.cmd_copy_image_to_buffer)(
command_buffer,
src_image,
src_image_layout,
dst_buffer,
regions.len() as u32,
regions.as_ptr(),
)
};
}
pub fn cmd_pipeline_barrier(
&self,
command_buffer: vk::CommandBuffer,
src_stage_mask: vk::PipelineStageFlags,
dst_stage_mask: vk::PipelineStageFlags,
dependency_flags: vk::DependencyFlags,
image_memory_barriers: &[vk::ImageMemoryBarrier<'_>],
) {
unsafe {
(self.fp.cmd_pipeline_barrier)(
command_buffer,
src_stage_mask,
dst_stage_mask,
dependency_flags,
0,
ptr::null(),
0,
ptr::null(),
image_memory_barriers.len() as u32,
image_memory_barriers.as_ptr(),
)
};
}
pub fn create_swapchain_khr(
&self,
device: vk::Device,
create_info: &vk::SwapchainCreateInfoKHR<'_>,
) -> Result<vk::SwapchainKHR, vk::Result> {
let mut swapchain = vk::SwapchainKHR::null();
let result = unsafe { (self.swapchain.create_swapchain_khr)(device, create_info, ptr::null(), &mut swapchain) };
created(result, swapchain)
}
pub fn destroy_swapchain_khr(&self, device: vk::Device, swapchain: vk::SwapchainKHR) {
unsafe { (self.swapchain.destroy_swapchain_khr)(device, swapchain, ptr::null()) };
}
pub fn get_swapchain_images_khr(
&self,
device: vk::Device,
swapchain: vk::SwapchainKHR,
) -> Result<Vec<vk::Image>, vk::Result> {
read_into_vec(|count, data| unsafe { (self.swapchain.get_swapchain_images_khr)(device, swapchain, count, data) })
}
pub fn device_wait_idle(&self, device: vk::Device) -> vk::Result {
unsafe { (self.fp.device_wait_idle)(device) }
}
pub fn queue_wait_idle(&self, queue: vk::Queue) -> vk::Result {
unsafe { (self.fp.queue_wait_idle)(queue) }
}
pub fn acquire_next_image_khr(
&self,
device: vk::Device,
swapchain: vk::SwapchainKHR,
timeout: u64,
semaphore: vk::Semaphore,
fence: vk::Fence,
) -> (vk::Result, u32) {
let mut image_index = 0;
let result = unsafe {
(self.swapchain.acquire_next_image_khr)(device, swapchain, timeout, semaphore, fence, &mut image_index)
};
(result, image_index)
}
#[allow(clippy::too_many_arguments)]
pub fn cmd_blit_image(
&self,
command_buffer: vk::CommandBuffer,
src_image: vk::Image,
src_image_layout: vk::ImageLayout,
dst_image: vk::Image,
dst_image_layout: vk::ImageLayout,
regions: &[vk::ImageBlit],
filter: vk::Filter,
) {
unsafe {
(self.fp.cmd_blit_image)(
command_buffer,
src_image,
src_image_layout,
dst_image,
dst_image_layout,
regions.len() as u32,
regions.as_ptr(),
filter,
)
};
}
pub fn vk_queue_present_khr(
&self,
queue: vk::Queue,
wait_semaphore: vk::Semaphore,
swapchain: vk::SwapchainKHR,
image_index: u32,
) -> (vk::Result, vk::Result) {
let mut result = vk::Result::SUCCESS;
let present_info = vk::PresentInfoKHR {
wait_semaphore_count: 1,
p_wait_semaphores: &wait_semaphore,
swapchain_count: 1,
p_swapchains: &swapchain,
p_image_indices: &image_index,
p_results: &mut result,
..Default::default()
};
let call_result = unsafe { (self.swapchain.queue_present_khr)(queue, &present_info) };
(call_result, result)
}
pub fn import_semaphore_fd_khr(&self, device: vk::Device, info: &vk::ImportSemaphoreFdInfoKHR<'_>) -> vk::Result {
unsafe { (self.external_semaphore_fd.import_semaphore_fd_khr)(device, info) }
}
pub fn import_semaphore_win32_handle_khr(
&self,
device: vk::Device,
info: &vk::ImportSemaphoreWin32HandleInfoKHR<'_>,
) -> vk::Result {
unsafe { (self.external_semaphore_win32.import_semaphore_win32_handle_khr)(device, info) }
}
}