1use super::Instance;
3use crate::core as vk;
4use crate::load::{
5 CallError, Capabilities, CommandSupport, CreatedHandle, InitializationFailure, LoadError,
6};
7use libloading::Library;
8use std::sync::Arc;
9
10pub struct Device {
12 handle: vk::DeviceHandle,
13 fp: vk::FnDevice,
14 gdpa:
15 unsafe extern "system" fn(vk::DeviceHandle, *const std::ffi::c_char) -> vk::PFN_vkVoidFunction,
16 _library: Option<Arc<Library>>,
17 capabilities: Option<Capabilities>,
18}
19
20impl Device {
21 pub unsafe fn new_from_handle(
29 instance: &Instance,
30 handle: vk::DeviceHandle,
31 ) -> Result<Self, LoadError> {
32 if handle.is_null() {
33 return Err(LoadError::NullHandle("device"));
34 }
35 let gdpa = instance
36 .fp()
37 .get_device_proc_addr
38 .ok_or(LoadError::MissingSymbol("vkGetDeviceProcAddr"))?;
39 let fp = unsafe { vk::FnDevice::new_from_resolver(gdpa, handle) };
41 if fp.destroy_device.is_none() {
42 return Err(LoadError::MissingSymbol("vkDestroyDevice"));
43 }
44 Ok(Self {
45 handle,
46 fp,
47 gdpa,
48 _library: instance.library.clone(),
49 capabilities: None,
50 })
51 }
52
53 pub unsafe fn new_from_handle_with_capabilities(
65 instance: &Instance,
66 handle: vk::DeviceHandle,
67 capabilities: Capabilities,
68 ) -> Result<Self, LoadError> {
69 if !capabilities.is_device() {
70 return Err(LoadError::InvalidMetadata(
71 "device import needs device capabilities",
72 ));
73 }
74 if let Some(parent) = instance.capabilities()
75 && !capabilities.matches_instance(parent)
76 {
77 return Err(LoadError::InvalidMetadata(
78 "device capabilities disagree with parent instance",
79 ));
80 }
81 let mut device = unsafe { Self::new_from_handle(instance, handle) }?;
83 device
84 .fp
85 .retain_enabled(|command| capabilities.support(command) == CommandSupport::Enabled);
86 device.capabilities = Some(capabilities);
87 Ok(device)
88 }
89
90 pub fn handle(&self) -> vk::DeviceHandle {
92 self.handle
93 }
94
95 pub fn fp(&self) -> &vk::FnDevice {
97 &self.fp
98 }
99
100 pub fn capabilities(&self) -> Option<&Capabilities> {
102 self.capabilities.as_ref()
103 }
104
105 pub unsafe fn destroy(self, allocator: Option<&vk::AllocationCallbacks>) {
111 unsafe { destroy_device(self, allocator) };
113 }
114}
115
116use super::command::commands;
117commands! { Device, device;
118 pub unsafe fn get_device_queue(
124 queue_family_index: u32,
125 queue_index: u32,
126 ) -> Result<vk::Queue, CallError> {
127 let f = device
128 .fp
129 .get_device_queue
130 .ok_or(CallError::MissingCommand("vkGetDeviceQueue"))?;
131 let mut queue = vk::Queue::NULL;
132 unsafe { f(device.handle, queue_family_index, queue_index, &mut queue) };
134 Ok(queue)
135 }
136
137 pub unsafe fn get_device_proc_addr(name: &std::ffi::CStr) -> vk::PFN_vkVoidFunction {
145 unsafe { (device.gdpa)(device.handle, name.as_ptr()) }
147 }
148
149 pub unsafe fn cmd_dispatch(
159 command_buffer: vk::CommandBuffer,
160 group_count_x: u32,
161 group_count_y: u32,
162 group_count_z: u32,
163 ) -> Result<(), CallError> {
164 let f = device
165 .fp
166 .cmd_dispatch
167 .ok_or(CallError::MissingCommand("vkCmdDispatch"))?;
168 unsafe { f(command_buffer, group_count_x, group_count_y, group_count_z) };
170 Ok(())
171 }
172
173 pub unsafe fn allocate_memory(
182 allocate_info: &vk::MemoryAllocateInfo,
183 allocator: Option<&vk::AllocationCallbacks>,
184 ) -> Result<vk::DeviceMemory, CallError> {
185 let f = device
186 .fp
187 .allocate_memory
188 .ok_or(CallError::MissingCommand("vkAllocateMemory"))?;
189 let mut handle = vk::DeviceMemory::NULL;
190 let result = unsafe {
191 f(
192 device.handle,
193 allocate_info,
194 allocator.map_or(std::ptr::null(), |a| a),
195 &mut handle,
196 )
197 };
198 if result == vk::Result::SUCCESS {
199 Ok(handle)
200 } else {
201 Err(CallError::Vulkan(result))
202 }
203 }
204
205 pub unsafe fn free_memory(
211 memory: vk::DeviceMemory,
212 allocator: Option<&vk::AllocationCallbacks>,
213 ) -> Result<(), CallError> {
214 let f = device
215 .fp
216 .free_memory
217 .ok_or(CallError::MissingCommand("vkFreeMemory"))?;
218 unsafe {
219 f(
220 device.handle,
221 memory,
222 allocator.map_or(std::ptr::null(), |a| a),
223 )
224 };
225 Ok(())
226 }
227
228 pub unsafe fn map_memory(
236 memory: vk::DeviceMemory,
237 offset: vk::DeviceSize,
238 size: vk::DeviceSize,
239 flags: vk::MemoryMapFlags,
240 ) -> Result<*mut std::ffi::c_void, CallError> {
241 let f = device
242 .fp
243 .map_memory
244 .ok_or(CallError::MissingCommand("vkMapMemory"))?;
245 let mut ptr = std::ptr::null_mut();
246 let result = unsafe { f(device.handle, memory, offset, size, flags, &mut ptr) };
247 if result == vk::Result::SUCCESS {
248 Ok(ptr)
249 } else {
250 Err(CallError::Vulkan(result))
251 }
252 }
253
254 pub unsafe fn unmap_memory(memory: vk::DeviceMemory) -> Result<(), CallError> {
260 let f = device
261 .fp
262 .unmap_memory
263 .ok_or(CallError::MissingCommand("vkUnmapMemory"))?;
264 unsafe { f(device.handle, memory) };
265 Ok(())
266 }
267
268 pub unsafe fn flush_mapped_memory_ranges(
275 ranges: &[vk::MappedMemoryRange],
276 ) -> Result<(), CallError> {
277 let f = device
278 .fp
279 .flush_mapped_memory_ranges
280 .ok_or(CallError::MissingCommand("vkFlushMappedMemoryRanges"))?;
281 let result = unsafe {
282 f(
283 device.handle,
284 u32::try_from(ranges.len()).map_err(|_| CallError::CountOverflow(ranges.len()))?,
285 ranges.as_ptr(),
286 )
287 };
288 if result == vk::Result::SUCCESS {
289 Ok(())
290 } else {
291 Err(CallError::Vulkan(result))
292 }
293 }
294
295 pub unsafe fn invalidate_mapped_memory_ranges(
302 ranges: &[vk::MappedMemoryRange],
303 ) -> Result<(), CallError> {
304 let f = device
305 .fp
306 .invalidate_mapped_memory_ranges
307 .ok_or(CallError::MissingCommand("vkInvalidateMappedMemoryRanges"))?;
308 let result = unsafe {
309 f(
310 device.handle,
311 u32::try_from(ranges.len()).map_err(|_| CallError::CountOverflow(ranges.len()))?,
312 ranges.as_ptr(),
313 )
314 };
315 if result == vk::Result::SUCCESS {
316 Ok(())
317 } else {
318 Err(CallError::Vulkan(result))
319 }
320 }
321
322 pub unsafe fn create_buffer(
327 create_info: &vk::BufferCreateInfo,
328 allocator: Option<&vk::AllocationCallbacks>,
329 ) -> Result<vk::Buffer, CallError> {
330 let f = device
331 .fp
332 .create_buffer
333 .ok_or(CallError::MissingCommand("vkCreateBuffer"))?;
334 let mut handle = vk::Buffer::NULL;
335 let result = unsafe {
336 f(
337 device.handle,
338 create_info,
339 allocator.map_or(std::ptr::null(), |a| a),
340 &mut handle,
341 )
342 };
343 if result == vk::Result::SUCCESS {
344 Ok(handle)
345 } else {
346 Err(CallError::Vulkan(result))
347 }
348 }
349
350 pub unsafe fn destroy_buffer(
355 buffer: vk::Buffer,
356 allocator: Option<&vk::AllocationCallbacks>,
357 ) -> Result<(), CallError> {
358 let f = device
359 .fp
360 .destroy_buffer
361 .ok_or(CallError::MissingCommand("vkDestroyBuffer"))?;
362 unsafe {
363 f(
364 device.handle,
365 buffer,
366 allocator.map_or(std::ptr::null(), |a| a),
367 )
368 };
369 Ok(())
370 }
371
372 pub unsafe fn get_buffer_memory_requirements(
377 buffer: vk::Buffer,
378 ) -> Result<vk::MemoryRequirements, CallError> {
379 let f = device
380 .fp
381 .get_buffer_memory_requirements
382 .ok_or(CallError::MissingCommand("vkGetBufferMemoryRequirements"))?;
383 let mut reqs = unsafe { std::mem::zeroed::<vk::MemoryRequirements>() };
384 unsafe { f(device.handle, buffer, &mut reqs) };
385 Ok(reqs)
386 }
387
388 pub unsafe fn bind_buffer_memory(
394 buffer: vk::Buffer,
395 memory: vk::DeviceMemory,
396 memory_offset: vk::DeviceSize,
397 ) -> Result<(), CallError> {
398 let f = device
399 .fp
400 .bind_buffer_memory
401 .ok_or(CallError::MissingCommand("vkBindBufferMemory"))?;
402 let result = unsafe { f(device.handle, buffer, memory, memory_offset) };
403 if result == vk::Result::SUCCESS {
404 Ok(())
405 } else {
406 Err(CallError::Vulkan(result))
407 }
408 }
409
410 pub unsafe fn create_command_pool(
415 create_info: &vk::CommandPoolCreateInfo,
416 allocator: Option<&vk::AllocationCallbacks>,
417 ) -> Result<vk::CommandPool, CallError> {
418 let f = device
419 .fp
420 .create_command_pool
421 .ok_or(CallError::MissingCommand("vkCreateCommandPool"))?;
422 let mut handle = vk::CommandPool::NULL;
423 let result = unsafe {
424 f(
425 device.handle,
426 create_info,
427 allocator.map_or(std::ptr::null(), |a| a),
428 &mut handle,
429 )
430 };
431 if result == vk::Result::SUCCESS {
432 Ok(handle)
433 } else {
434 Err(CallError::Vulkan(result))
435 }
436 }
437
438 pub unsafe fn destroy_command_pool(
443 pool: vk::CommandPool,
444 allocator: Option<&vk::AllocationCallbacks>,
445 ) -> Result<(), CallError> {
446 let f = device
447 .fp
448 .destroy_command_pool
449 .ok_or(CallError::MissingCommand("vkDestroyCommandPool"))?;
450 unsafe {
451 f(
452 device.handle,
453 pool,
454 allocator.map_or(std::ptr::null(), |a| a),
455 )
456 };
457 Ok(())
458 }
459
460 pub unsafe fn allocate_command_buffers(
465 allocate_info: &vk::CommandBufferAllocateInfo,
466 ) -> Result<Vec<vk::CommandBuffer>, CallError> {
467 let f = device
468 .fp
469 .allocate_command_buffers
470 .ok_or(CallError::MissingCommand("vkAllocateCommandBuffers"))?;
471 let count = allocate_info.command_buffer_count as usize;
472 let mut bufs = vec![vk::CommandBuffer::NULL; count];
473 let result = unsafe { f(device.handle, allocate_info, bufs.as_mut_ptr()) };
474 if result == vk::Result::SUCCESS {
475 Ok(bufs)
476 } else {
477 Err(CallError::Vulkan(result))
478 }
479 }
480
481 pub unsafe fn free_command_buffers(
486 pool: vk::CommandPool,
487 buffers: &[vk::CommandBuffer],
488 ) -> Result<(), CallError> {
489 let f = device
490 .fp
491 .free_command_buffers
492 .ok_or(CallError::MissingCommand("vkFreeCommandBuffers"))?;
493 unsafe {
494 f(
495 device.handle,
496 pool,
497 u32::try_from(buffers.len()).map_err(|_| CallError::CountOverflow(buffers.len()))?,
498 buffers.as_ptr(),
499 )
500 };
501 Ok(())
502 }
503
504 pub unsafe fn begin_command_buffer(
509 command_buffer: vk::CommandBuffer,
510 begin_info: &vk::CommandBufferBeginInfo,
511 ) -> Result<(), CallError> {
512 let f = device
513 .fp
514 .begin_command_buffer
515 .ok_or(CallError::MissingCommand("vkBeginCommandBuffer"))?;
516 let result = unsafe { f(command_buffer, begin_info) };
517 if result == vk::Result::SUCCESS {
518 Ok(())
519 } else {
520 Err(CallError::Vulkan(result))
521 }
522 }
523
524 pub unsafe fn end_command_buffer(command_buffer: vk::CommandBuffer) -> Result<(), CallError> {
529 let f = device
530 .fp
531 .end_command_buffer
532 .ok_or(CallError::MissingCommand("vkEndCommandBuffer"))?;
533 let result = unsafe { f(command_buffer) };
534 if result == vk::Result::SUCCESS {
535 Ok(())
536 } else {
537 Err(CallError::Vulkan(result))
538 }
539 }
540
541 pub unsafe fn cmd_fill_buffer(
547 command_buffer: vk::CommandBuffer,
548 buffer: vk::Buffer,
549 offset: vk::DeviceSize,
550 size: vk::DeviceSize,
551 data: u32,
552 ) -> Result<(), CallError> {
553 let f = device
554 .fp
555 .cmd_fill_buffer
556 .ok_or(CallError::MissingCommand("vkCmdFillBuffer"))?;
557 unsafe { f(command_buffer, buffer, offset, size, data) };
558 Ok(())
559 }
560
561 pub unsafe fn queue_submit(
567 queue: vk::Queue,
568 submits: &[vk::SubmitInfo],
569 fence: vk::Fence,
570 ) -> Result<(), CallError> {
571 let f = device
572 .fp
573 .queue_submit
574 .ok_or(CallError::MissingCommand("vkQueueSubmit"))?;
575 let result = unsafe {
576 f(
577 queue,
578 u32::try_from(submits.len()).map_err(|_| CallError::CountOverflow(submits.len()))?,
579 submits.as_ptr(),
580 fence,
581 )
582 };
583 if result == vk::Result::SUCCESS {
584 Ok(())
585 } else {
586 Err(CallError::Vulkan(result))
587 }
588 }
589
590 pub unsafe fn queue_wait_idle(queue: vk::Queue) -> Result<(), CallError> {
595 let f = device
596 .fp
597 .queue_wait_idle
598 .ok_or(CallError::MissingCommand("vkQueueWaitIdle"))?;
599 let result = unsafe { f(queue) };
600 if result == vk::Result::SUCCESS {
601 Ok(())
602 } else {
603 Err(CallError::Vulkan(result))
604 }
605 }
606
607 pub unsafe fn create_fence(
612 create_info: &vk::FenceCreateInfo,
613 allocator: Option<&vk::AllocationCallbacks>,
614 ) -> Result<vk::Fence, CallError> {
615 let f = device
616 .fp
617 .create_fence
618 .ok_or(CallError::MissingCommand("vkCreateFence"))?;
619 let mut handle = vk::Fence::NULL;
620 let result = unsafe {
621 f(
622 device.handle,
623 create_info,
624 allocator.map_or(std::ptr::null(), |a| a),
625 &mut handle,
626 )
627 };
628 if result == vk::Result::SUCCESS {
629 Ok(handle)
630 } else {
631 Err(CallError::Vulkan(result))
632 }
633 }
634
635 pub unsafe fn destroy_fence(
640 fence: vk::Fence,
641 allocator: Option<&vk::AllocationCallbacks>,
642 ) -> Result<(), CallError> {
643 let f = device
644 .fp
645 .destroy_fence
646 .ok_or(CallError::MissingCommand("vkDestroyFence"))?;
647 unsafe {
648 f(
649 device.handle,
650 fence,
651 allocator.map_or(std::ptr::null(), |a| a),
652 )
653 };
654 Ok(())
655 }
656
657 pub unsafe fn wait_for_fences(
665 fences: &[vk::Fence],
666 wait_all: bool,
667 timeout_ns: u64,
668 ) -> Result<bool, CallError> {
669 let f = device
670 .fp
671 .wait_for_fences
672 .ok_or(CallError::MissingCommand("vkWaitForFences"))?;
673 let result = unsafe {
674 f(
675 device.handle,
676 u32::try_from(fences.len()).map_err(|_| CallError::CountOverflow(fences.len()))?,
677 fences.as_ptr(),
678 wait_all as vk::Bool32,
679 timeout_ns,
680 )
681 };
682 match result {
683 vk::Result::SUCCESS => Ok(true),
684 vk::Result::TIMEOUT => Ok(false),
685 other => Err(CallError::Vulkan(other)),
686 }
687 }
688
689 pub unsafe fn reset_fences(fences: &[vk::Fence]) -> Result<(), CallError> {
694 let f = device
695 .fp
696 .reset_fences
697 .ok_or(CallError::MissingCommand("vkResetFences"))?;
698 let result = unsafe {
699 f(
700 device.handle,
701 u32::try_from(fences.len()).map_err(|_| CallError::CountOverflow(fences.len()))?,
702 fences.as_ptr(),
703 )
704 };
705 if result == vk::Result::SUCCESS {
706 Ok(())
707 } else {
708 Err(CallError::Vulkan(result))
709 }
710 }
711
712}
713
714pub unsafe fn create_device(
725 instance: &Instance,
726 physical_device: vk::PhysicalDevice,
727 create_info: &vk::DeviceCreateInfo,
728 allocator: Option<&vk::AllocationCallbacks>,
729) -> Result<Device, CallError> {
730 let gdpa = instance
732 .fp()
733 .get_device_proc_addr
734 .ok_or(CallError::MissingCommand("vkGetDeviceProcAddr"))?;
735 let capabilities = if let Some(parent) = instance.capabilities() {
736 let physical_version = if parent.api_version() == vk::API_VERSION_1_0 {
739 vk::API_VERSION_1_0
740 } else {
741 unsafe { instance.get_physical_device_properties(physical_device) }?.api_version
743 };
744 Some(unsafe { parent.new_from_device_create_info(create_info, physical_version) }?)
746 } else {
747 None
748 };
749 let f = instance
750 .fp()
751 .create_device
752 .ok_or(CallError::MissingCommand("vkCreateDevice"))?;
753 let allocator_ptr = allocator.map_or(std::ptr::null(), |a| a);
754 let mut handle = vk::DeviceHandle::NULL;
755 let result = unsafe { f(physical_device, create_info, allocator_ptr, &mut handle) };
757 if result != vk::Result::SUCCESS {
758 return Err(CallError::Vulkan(result));
759 }
760 if handle.is_null() {
761 return Err(CallError::InvalidOutput(
762 "vkCreateDevice returned a null handle",
763 ));
764 }
765 let mut fp = unsafe { vk::FnDevice::new_from_resolver(gdpa, handle) };
767 if fp.destroy_device.is_none() {
768 let failure = InitializationFailure {
769 handle: CreatedHandle::Device(handle),
770 missing_command: "vkDestroyDevice",
771 library: instance.library.clone(),
772 instance: instance.handle(),
773 gipa: instance.gipa,
774 gdpa: Some(gdpa),
775 };
776 return match unsafe { failure.destroy(allocator) } {
778 Ok(()) => Err(CallError::MissingCommand("vkDestroyDevice")),
779 Err(failure) => Err(CallError::InitializationFailed(failure)),
780 };
781 }
782 if let Some(capabilities) = &capabilities {
783 fp.retain_enabled(|command| capabilities.support(command) == CommandSupport::Enabled);
784 }
785 Ok(Device {
786 handle,
787 fp,
788 gdpa,
789 _library: instance.library.clone(),
790 capabilities,
791 })
792}
793
794impl Device {
795 pub unsafe fn new(
799 instance: &Instance,
800 physical_device: vk::PhysicalDevice,
801 create_info: &vk::DeviceCreateInfo,
802 allocator: Option<&vk::AllocationCallbacks>,
803 ) -> Result<Self, CallError> {
804 unsafe { create_device(instance, physical_device, create_info, allocator) }
806 }
807}
808
809impl Instance {
810 pub unsafe fn create_device(
814 &self,
815 physical_device: vk::PhysicalDevice,
816 create_info: &vk::DeviceCreateInfo,
817 allocator: Option<&vk::AllocationCallbacks>,
818 ) -> Result<Device, CallError> {
819 unsafe { create_device(self, physical_device, create_info, allocator) }
821 }
822}
823
824pub unsafe fn destroy_device(device: Device, allocator: Option<&vk::AllocationCallbacks>) {
830 unsafe {
832 device.fp.destroy_device.unwrap()(device.handle, allocator.map_or(std::ptr::null(), |a| a))
833 };
834}