From 6a755cd2f36e720319e02a80d7e6ad9584a0102d Mon Sep 17 00:00:00 2001 From: Rua Date: Sat, 30 Jul 2022 08:53:52 +0200 Subject: [PATCH] Add `VulkanLibrary` as first initialization step before `Instance` (#1932) * Add `VulkanLibrary` as first initialization step before `Instance` * Fix MacOS error * Fix Vulkano-utils --- examples/src/bin/basic-compute-shader.rs | 15 +- examples/src/bin/buffer-pool.rs | 19 +- examples/src/bin/clear_attachments.rs | 19 +- examples/src/bin/debug.rs | 24 +- examples/src/bin/deferred/main.rs | 19 +- examples/src/bin/dynamic-buffers.rs | 15 +- examples/src/bin/dynamic-local-size.rs | 25 +- examples/src/bin/gl-interop.rs | 36 +- examples/src/bin/image-self-copy-blit/main.rs | 19 +- examples/src/bin/image/main.rs | 19 +- .../bin/immutable-buffer-initialization.rs | 15 +- examples/src/bin/immutable-sampler/main.rs | 19 +- examples/src/bin/indirect.rs | 19 +- examples/src/bin/instancing.rs | 19 +- examples/src/bin/interactive_fractal/main.rs | 5 +- examples/src/bin/msaa-renderpass.rs | 19 +- examples/src/bin/multi-window.rs | 19 +- .../src/bin/multi_window_game_of_life/app.rs | 8 +- examples/src/bin/multiview.rs | 21 +- examples/src/bin/occlusion-query.rs | 19 +- examples/src/bin/pipeline-caching.rs | 15 +- examples/src/bin/push-constants.rs | 15 +- examples/src/bin/push-descriptors/main.rs | 19 +- examples/src/bin/runtime-shader/main.rs | 19 +- examples/src/bin/runtime_array/main.rs | 19 +- examples/src/bin/self-copy-buffer.rs | 15 +- examples/src/bin/shader-include/main.rs | 15 +- examples/src/bin/shader-types-sharing.rs | 15 +- examples/src/bin/simple-particles.rs | 19 +- examples/src/bin/specialization-constants.rs | 15 +- examples/src/bin/teapot/main.rs | 19 +- examples/src/bin/tessellation.rs | 19 +- examples/src/bin/texture_array/main.rs | 19 +- examples/src/bin/triangle-v1_3.rs | 20 +- examples/src/bin/triangle.rs | 19 +- vulkano-util/src/context.rs | 106 +++-- vulkano-util/src/renderer.rs | 17 +- vulkano-util/src/window.rs | 2 +- vulkano-win/src/winit.rs | 23 +- vulkano/src/device/extensions.rs | 27 +- vulkano/src/device/mod.rs | 21 +- vulkano/src/device/physical.rs | 32 +- vulkano/src/extensions.rs | 64 --- vulkano/src/image/mod.rs | 52 ++- vulkano/src/instance/extensions.rs | 75 +--- vulkano/src/instance/layers.rs | 164 +------ vulkano/src/instance/loader.rs | 323 -------------- vulkano/src/instance/mod.rs | 198 ++++----- vulkano/src/lib.rs | 37 +- vulkano/src/library.rs | 417 ++++++++++++++++++ vulkano/src/swapchain/mod.rs | 26 +- vulkano/src/sync/semaphore.rs | 35 +- vulkano/src/tests.rs | 11 +- 53 files changed, 1136 insertions(+), 1129 deletions(-) delete mode 100644 vulkano/src/instance/loader.rs create mode 100644 vulkano/src/library.rs diff --git a/examples/src/bin/basic-compute-shader.rs b/examples/src/bin/basic-compute-shader.rs index 1e831562..5c496241 100644 --- a/examples/src/bin/basic-compute-shader.rs +++ b/examples/src/bin/basic-compute-shader.rs @@ -24,15 +24,20 @@ use vulkano::{ instance::{Instance, InstanceCreateInfo}, pipeline::{ComputePipeline, Pipeline, PipelineBindPoint}, sync::{self, GpuFuture}, + VulkanLibrary, }; fn main() { // As with other examples, the first step is to create an instance. - let instance = Instance::new(InstanceCreateInfo { - // Enable enumerating devices that use non-conformant vulkan implementations. (ex. MoltenVK) - enumerate_portability: true, - ..Default::default() - }) + let library = VulkanLibrary::new().unwrap(); + let instance = Instance::new( + library, + InstanceCreateInfo { + // Enable enumerating devices that use non-conformant vulkan implementations. (ex. MoltenVK) + enumerate_portability: true, + ..Default::default() + }, + ) .unwrap(); // Choose which physical device to use. diff --git a/examples/src/bin/buffer-pool.rs b/examples/src/bin/buffer-pool.rs index df9b851b..17d50ca5 100644 --- a/examples/src/bin/buffer-pool.rs +++ b/examples/src/bin/buffer-pool.rs @@ -49,6 +49,7 @@ use vulkano::{ acquire_next_image, AcquireError, Swapchain, SwapchainCreateInfo, SwapchainCreationError, }, sync::{self, FlushError, GpuFuture}, + VulkanLibrary, }; use vulkano_win::VkSurfaceBuild; use winit::{ @@ -65,13 +66,17 @@ struct Vertex { impl_vertex!(Vertex, position); fn main() { - let required_extensions = vulkano_win::required_extensions(); - let instance = Instance::new(InstanceCreateInfo { - enabled_extensions: required_extensions, - // Enable enumerating devices that use non-conformant vulkan implementations. (ex. MoltenVK) - enumerate_portability: true, - ..Default::default() - }) + let library = VulkanLibrary::new().unwrap(); + let required_extensions = vulkano_win::required_extensions(&library); + let instance = Instance::new( + library, + InstanceCreateInfo { + enabled_extensions: required_extensions, + // Enable enumerating devices that use non-conformant vulkan implementations. (ex. MoltenVK) + enumerate_portability: true, + ..Default::default() + }, + ) .unwrap(); let event_loop = EventLoop::new(); diff --git a/examples/src/bin/clear_attachments.rs b/examples/src/bin/clear_attachments.rs index c568a4da..39ada44f 100644 --- a/examples/src/bin/clear_attachments.rs +++ b/examples/src/bin/clear_attachments.rs @@ -24,6 +24,7 @@ use vulkano::{ acquire_next_image, AcquireError, Swapchain, SwapchainCreateInfo, SwapchainCreationError, }, sync::{self, FlushError, GpuFuture}, + VulkanLibrary, }; use vulkano_win::VkSurfaceBuild; use winit::{ @@ -36,13 +37,17 @@ fn main() { // The start of this example is exactly the same as `triangle`. You should read the // `triangle` example if you haven't done so yet. - let required_extensions = vulkano_win::required_extensions(); - let instance = Instance::new(InstanceCreateInfo { - enabled_extensions: required_extensions, - // Enable enumerating devices that use non-conformant vulkan implementations. (ex. MoltenVK) - enumerate_portability: true, - ..Default::default() - }) + let library = VulkanLibrary::new().unwrap(); + let required_extensions = vulkano_win::required_extensions(&library); + let instance = Instance::new( + library, + InstanceCreateInfo { + enabled_extensions: required_extensions, + // Enable enumerating devices that use non-conformant vulkan implementations. (ex. MoltenVK) + enumerate_portability: true, + ..Default::default() + }, + ) .unwrap(); let event_loop = EventLoop::new(); diff --git a/examples/src/bin/debug.rs b/examples/src/bin/debug.rs index a5ef1825..a3eea319 100644 --- a/examples/src/bin/debug.rs +++ b/examples/src/bin/debug.rs @@ -20,8 +20,9 @@ use vulkano::{ DebugUtilsMessageSeverity, DebugUtilsMessageType, DebugUtilsMessenger, DebugUtilsMessengerCreateInfo, }, - layers_list, Instance, InstanceCreateInfo, InstanceExtensions, + Instance, InstanceCreateInfo, InstanceExtensions, }, + VulkanLibrary, }; fn main() { @@ -39,6 +40,8 @@ fn main() { ..InstanceExtensions::none() }; + let library = VulkanLibrary::new().unwrap(); + // You also need to specify (unless you've used the methods linked above) which debugging layers // your code should use. Each layer is a bunch of checks or messages that provide information of // some sort. @@ -50,7 +53,7 @@ fn main() { // and you should verify that list for safety - Vulkano will return an error if you specify // any layers that are not installed on this system. That code to do could look like this: println!("List of Vulkan debugging layers available to use:"); - let mut layers = layers_list().unwrap(); + let mut layers = library.layer_properties().unwrap(); while let Some(l) = layers.next() { println!("\t{}", l.name()); } @@ -63,13 +66,16 @@ fn main() { let layers = vec!["VK_LAYER_KHRONOS_validation".to_owned()]; // Important: pass the extension(s) and layer(s) when creating the vulkano instance - let instance = Instance::new(InstanceCreateInfo { - enabled_extensions: extensions, - enabled_layers: layers, - // Enable enumerating devices that use non-conformant vulkan implementations. (ex. MoltenVK) - enumerate_portability: true, - ..Default::default() - }) + let instance = Instance::new( + library, + InstanceCreateInfo { + enabled_extensions: extensions, + enabled_layers: layers, + // Enable enumerating devices that use non-conformant vulkan implementations. (ex. MoltenVK) + enumerate_portability: true, + ..Default::default() + }, + ) .expect("failed to create Vulkan instance"); /////////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/examples/src/bin/deferred/main.rs b/examples/src/bin/deferred/main.rs index 683e9df8..e80cccb1 100644 --- a/examples/src/bin/deferred/main.rs +++ b/examples/src/bin/deferred/main.rs @@ -41,6 +41,7 @@ use vulkano::{ acquire_next_image, AcquireError, Swapchain, SwapchainCreateInfo, SwapchainCreationError, }, sync::{self, FlushError, GpuFuture}, + VulkanLibrary, }; use vulkano_win::VkSurfaceBuild; use winit::{ @@ -55,13 +56,17 @@ mod triangle_draw_system; fn main() { // Basic initialization. See the triangle example if you want more details about this. - let required_extensions = vulkano_win::required_extensions(); - let instance = Instance::new(InstanceCreateInfo { - enabled_extensions: required_extensions, - // Enable enumerating devices that use non-conformant vulkan implementations. (ex. MoltenVK) - enumerate_portability: true, - ..Default::default() - }) + let library = VulkanLibrary::new().unwrap(); + let required_extensions = vulkano_win::required_extensions(&library); + let instance = Instance::new( + library, + InstanceCreateInfo { + enabled_extensions: required_extensions, + // Enable enumerating devices that use non-conformant vulkan implementations. (ex. MoltenVK) + enumerate_portability: true, + ..Default::default() + }, + ) .unwrap(); let event_loop = EventLoop::new(); diff --git a/examples/src/bin/dynamic-buffers.rs b/examples/src/bin/dynamic-buffers.rs index 36c3f84a..822499b0 100644 --- a/examples/src/bin/dynamic-buffers.rs +++ b/examples/src/bin/dynamic-buffers.rs @@ -28,14 +28,19 @@ use vulkano::{ instance::{Instance, InstanceCreateInfo}, pipeline::{ComputePipeline, Pipeline, PipelineBindPoint}, sync::{self, GpuFuture}, + VulkanLibrary, }; fn main() { - let instance = Instance::new(InstanceCreateInfo { - // Enable enumerating devices that use non-conformant vulkan implementations. (ex. MoltenVK) - enumerate_portability: true, - ..Default::default() - }) + let library = VulkanLibrary::new().unwrap(); + let instance = Instance::new( + library, + InstanceCreateInfo { + // Enable enumerating devices that use non-conformant vulkan implementations. (ex. MoltenVK) + enumerate_portability: true, + ..Default::default() + }, + ) .unwrap(); let device_extensions = DeviceExtensions { diff --git a/examples/src/bin/dynamic-local-size.rs b/examples/src/bin/dynamic-local-size.rs index b376b298..a17f309f 100644 --- a/examples/src/bin/dynamic-local-size.rs +++ b/examples/src/bin/dynamic-local-size.rs @@ -28,21 +28,26 @@ use vulkano::{ instance::{Instance, InstanceCreateInfo, InstanceExtensions}, pipeline::{ComputePipeline, Pipeline, PipelineBindPoint}, sync::{self, GpuFuture}, + VulkanLibrary, }; fn main() { - let instance = Instance::new(InstanceCreateInfo { - enabled_extensions: InstanceExtensions { - // This extension is required to obtain physical device metadata - // about the device workgroup size limits - khr_get_physical_device_properties2: true, + let library = VulkanLibrary::new().unwrap(); + let instance = Instance::new( + library, + InstanceCreateInfo { + enabled_extensions: InstanceExtensions { + // This extension is required to obtain physical device metadata + // about the device workgroup size limits + khr_get_physical_device_properties2: true, - ..InstanceExtensions::none() + ..InstanceExtensions::none() + }, + // Enable enumerating devices that use non-conformant vulkan implementations. (ex. MoltenVK) + enumerate_portability: true, + ..Default::default() }, - // Enable enumerating devices that use non-conformant vulkan implementations. (ex. MoltenVK) - enumerate_portability: true, - ..Default::default() - }) + ) .unwrap(); let device_extensions = DeviceExtensions { diff --git a/examples/src/bin/gl-interop.rs b/examples/src/bin/gl-interop.rs index 03c696bb..0621f789 100644 --- a/examples/src/bin/gl-interop.rs +++ b/examples/src/bin/gl-interop.rs @@ -46,6 +46,7 @@ mod linux { now, ExternalSemaphoreHandleTypes, FlushError, GpuFuture, PipelineStages, Semaphore, SemaphoreCreateInfo, }, + VulkanLibrary, }; use vulkano_win::VkSurfaceBuild; use winit::{ @@ -378,25 +379,28 @@ mod linux { Arc, Arc>, ) { - let required_extensions = vulkano_win::required_extensions(); + let library = VulkanLibrary::new().unwrap(); + let required_extensions = vulkano_win::required_extensions(&library); + let instance = Instance::new( + library, + InstanceCreateInfo { + enabled_extensions: InstanceExtensions { + khr_get_physical_device_properties2: true, + khr_external_memory_capabilities: true, + khr_external_semaphore_capabilities: true, + khr_external_fence_capabilities: true, + ext_debug_utils: true, - let instance = Instance::new(InstanceCreateInfo { - enabled_extensions: InstanceExtensions { - khr_get_physical_device_properties2: true, - khr_external_memory_capabilities: true, - khr_external_semaphore_capabilities: true, - khr_external_fence_capabilities: true, - ext_debug_utils: true, + ..InstanceExtensions::none() + } + .union(&required_extensions), - ..InstanceExtensions::none() - } - .union(&required_extensions), + // Enable enumerating devices that use non-conformant vulkan implementations. (ex. MoltenVK) + enumerate_portability: true, - // Enable enumerating devices that use non-conformant vulkan implementations. (ex. MoltenVK) - enumerate_portability: true, - - ..Default::default() - }) + ..Default::default() + }, + ) .unwrap(); let _debug_callback = unsafe { diff --git a/examples/src/bin/image-self-copy-blit/main.rs b/examples/src/bin/image-self-copy-blit/main.rs index 41bd3c21..96670599 100644 --- a/examples/src/bin/image-self-copy-blit/main.rs +++ b/examples/src/bin/image-self-copy-blit/main.rs @@ -43,6 +43,7 @@ use vulkano::{ acquire_next_image, AcquireError, Swapchain, SwapchainCreateInfo, SwapchainCreationError, }, sync::{self, FlushError, GpuFuture}, + VulkanLibrary, }; use vulkano_win::VkSurfaceBuild; use winit::{ @@ -55,13 +56,17 @@ fn main() { // The start of this example is exactly the same as `triangle`. You should read the // `triangle` example if you haven't done so yet. - let required_extensions = vulkano_win::required_extensions(); - let instance = Instance::new(InstanceCreateInfo { - enabled_extensions: required_extensions, - // Enable enumerating devices that use non-conformant vulkan implementations. (ex. MoltenVK) - enumerate_portability: true, - ..Default::default() - }) + let library = VulkanLibrary::new().unwrap(); + let required_extensions = vulkano_win::required_extensions(&library); + let instance = Instance::new( + library, + InstanceCreateInfo { + enabled_extensions: required_extensions, + // Enable enumerating devices that use non-conformant vulkan implementations. (ex. MoltenVK) + enumerate_portability: true, + ..Default::default() + }, + ) .unwrap(); let event_loop = EventLoop::new(); diff --git a/examples/src/bin/image/main.rs b/examples/src/bin/image/main.rs index 1b08563f..7d0e8921 100644 --- a/examples/src/bin/image/main.rs +++ b/examples/src/bin/image/main.rs @@ -41,6 +41,7 @@ use vulkano::{ acquire_next_image, AcquireError, Swapchain, SwapchainCreateInfo, SwapchainCreationError, }, sync::{self, FlushError, GpuFuture}, + VulkanLibrary, }; use vulkano_win::VkSurfaceBuild; use winit::{ @@ -53,13 +54,17 @@ fn main() { // The start of this example is exactly the same as `triangle`. You should read the // `triangle` example if you haven't done so yet. - let required_extensions = vulkano_win::required_extensions(); - let instance = Instance::new(InstanceCreateInfo { - enabled_extensions: required_extensions, - // Enable enumerating devices that use non-conformant vulkan implementations. (ex. MoltenVK) - enumerate_portability: true, - ..Default::default() - }) + let library = VulkanLibrary::new().unwrap(); + let required_extensions = vulkano_win::required_extensions(&library); + let instance = Instance::new( + library, + InstanceCreateInfo { + enabled_extensions: required_extensions, + // Enable enumerating devices that use non-conformant vulkan implementations. (ex. MoltenVK) + enumerate_portability: true, + ..Default::default() + }, + ) .unwrap(); let event_loop = EventLoop::new(); diff --git a/examples/src/bin/immutable-buffer-initialization.rs b/examples/src/bin/immutable-buffer-initialization.rs index 42456d7c..b34e9539 100644 --- a/examples/src/bin/immutable-buffer-initialization.rs +++ b/examples/src/bin/immutable-buffer-initialization.rs @@ -20,17 +20,22 @@ use vulkano::{ instance::{Instance, InstanceCreateInfo}, pipeline::{ComputePipeline, Pipeline, PipelineBindPoint}, sync::{self, GpuFuture}, + VulkanLibrary, }; fn main() { // The most part of this example is exactly the same as `basic-compute-shader`. You should read the // `basic-compute-shader` example if you haven't done so yet. - let instance = Instance::new(InstanceCreateInfo { - // Enable enumerating devices that use non-conformant vulkan implementations. (ex. MoltenVK) - enumerate_portability: true, - ..Default::default() - }) + let library = VulkanLibrary::new().unwrap(); + let instance = Instance::new( + library, + InstanceCreateInfo { + // Enable enumerating devices that use non-conformant vulkan implementations. (ex. MoltenVK) + enumerate_portability: true, + ..Default::default() + }, + ) .unwrap(); let device_extensions = DeviceExtensions { diff --git a/examples/src/bin/immutable-sampler/main.rs b/examples/src/bin/immutable-sampler/main.rs index 2b8f4544..3eb6b36f 100644 --- a/examples/src/bin/immutable-sampler/main.rs +++ b/examples/src/bin/immutable-sampler/main.rs @@ -50,6 +50,7 @@ use vulkano::{ acquire_next_image, AcquireError, Swapchain, SwapchainCreateInfo, SwapchainCreationError, }, sync::{self, FlushError, GpuFuture}, + VulkanLibrary, }; use vulkano_win::VkSurfaceBuild; use winit::{ @@ -59,13 +60,17 @@ use winit::{ }; fn main() { - let required_extensions = vulkano_win::required_extensions(); - let instance = Instance::new(InstanceCreateInfo { - enabled_extensions: required_extensions, - // Enable enumerating devices that use non-conformant vulkan implementations. (ex. MoltenVK) - enumerate_portability: true, - ..Default::default() - }) + let library = VulkanLibrary::new().unwrap(); + let required_extensions = vulkano_win::required_extensions(&library); + let instance = Instance::new( + library, + InstanceCreateInfo { + enabled_extensions: required_extensions, + // Enable enumerating devices that use non-conformant vulkan implementations. (ex. MoltenVK) + enumerate_portability: true, + ..Default::default() + }, + ) .unwrap(); let event_loop = EventLoop::new(); diff --git a/examples/src/bin/indirect.rs b/examples/src/bin/indirect.rs index 98b4f32e..77057dc7 100644 --- a/examples/src/bin/indirect.rs +++ b/examples/src/bin/indirect.rs @@ -54,6 +54,7 @@ use vulkano::{ acquire_next_image, AcquireError, Swapchain, SwapchainCreateInfo, SwapchainCreationError, }, sync::{self, FlushError, GpuFuture}, + VulkanLibrary, }; use vulkano_win::VkSurfaceBuild; use winit::{ @@ -72,13 +73,17 @@ struct Vertex { impl_vertex!(Vertex, position); fn main() { - let required_extensions = vulkano_win::required_extensions(); - let instance = Instance::new(InstanceCreateInfo { - enabled_extensions: required_extensions, - // Enable enumerating devices that use non-conformant vulkan implementations. (ex. MoltenVK) - enumerate_portability: true, - ..Default::default() - }) + let library = VulkanLibrary::new().unwrap(); + let required_extensions = vulkano_win::required_extensions(&library); + let instance = Instance::new( + library, + InstanceCreateInfo { + enabled_extensions: required_extensions, + // Enable enumerating devices that use non-conformant vulkan implementations. (ex. MoltenVK) + enumerate_portability: true, + ..Default::default() + }, + ) .unwrap(); let event_loop = EventLoop::new(); diff --git a/examples/src/bin/instancing.rs b/examples/src/bin/instancing.rs index 04c67b49..58bd3253 100644 --- a/examples/src/bin/instancing.rs +++ b/examples/src/bin/instancing.rs @@ -40,6 +40,7 @@ use vulkano::{ acquire_next_image, AcquireError, Swapchain, SwapchainCreateInfo, SwapchainCreationError, }, sync::{self, FlushError, GpuFuture}, + VulkanLibrary, }; use vulkano_win::VkSurfaceBuild; use winit::{ @@ -71,13 +72,17 @@ struct InstanceData { impl_vertex!(InstanceData, position_offset, scale); fn main() { - let required_extensions = vulkano_win::required_extensions(); - let instance = Instance::new(InstanceCreateInfo { - enabled_extensions: required_extensions, - // Enable enumerating devices that use non-conformant vulkan implementations. (ex. MoltenVK) - enumerate_portability: true, - ..Default::default() - }) + let library = VulkanLibrary::new().unwrap(); + let required_extensions = vulkano_win::required_extensions(&library); + let instance = Instance::new( + library, + InstanceCreateInfo { + enabled_extensions: required_extensions, + // Enable enumerating devices that use non-conformant vulkan implementations. (ex. MoltenVK) + enumerate_portability: true, + ..Default::default() + }, + ) .unwrap(); let event_loop = EventLoop::new(); diff --git a/examples/src/bin/interactive_fractal/main.rs b/examples/src/bin/interactive_fractal/main.rs index b4a074d4..9d6e1caf 100644 --- a/examples/src/bin/interactive_fractal/main.rs +++ b/examples/src/bin/interactive_fractal/main.rs @@ -69,7 +69,10 @@ fn main() { // Create app to hold the logic of our fractal explorer let gfx_queue = context.graphics_queue(); // We intend to eventually render on our swapchain, thus we use that format when creating the app here. - let mut app = FractalApp::new(gfx_queue, primary_window_renderer.swapchain_format()); + let mut app = FractalApp::new( + gfx_queue.clone(), + primary_window_renderer.swapchain_format(), + ); app.print_guide(); // Basic loop for our runtime diff --git a/examples/src/bin/msaa-renderpass.rs b/examples/src/bin/msaa-renderpass.rs index d1bca407..f126bef5 100644 --- a/examples/src/bin/msaa-renderpass.rs +++ b/examples/src/bin/msaa-renderpass.rs @@ -90,17 +90,22 @@ use vulkano::{ }, render_pass::{Framebuffer, FramebufferCreateInfo, Subpass}, sync::GpuFuture, + VulkanLibrary, }; fn main() { // The usual Vulkan initialization. - let required_extensions = vulkano_win::required_extensions(); - let instance = Instance::new(InstanceCreateInfo { - enabled_extensions: required_extensions, - // Enable enumerating devices that use non-conformant vulkan implementations. (ex. MoltenVK) - enumerate_portability: true, - ..Default::default() - }) + let library = VulkanLibrary::new().unwrap(); + let required_extensions = vulkano_win::required_extensions(&library); + let instance = Instance::new( + library, + InstanceCreateInfo { + enabled_extensions: required_extensions, + // Enable enumerating devices that use non-conformant vulkan implementations. (ex. MoltenVK) + enumerate_portability: true, + ..Default::default() + }, + ) .unwrap(); let device_extensions = DeviceExtensions { diff --git a/examples/src/bin/multi-window.rs b/examples/src/bin/multi-window.rs index 621d71c0..86a483a9 100644 --- a/examples/src/bin/multi-window.rs +++ b/examples/src/bin/multi-window.rs @@ -44,6 +44,7 @@ use vulkano::{ SwapchainCreationError, }, sync::{self, FlushError, GpuFuture}, + VulkanLibrary, }; use vulkano_win::VkSurfaceBuild; use winit::{ @@ -62,13 +63,17 @@ struct WindowSurface { } fn main() { - let required_extensions = vulkano_win::required_extensions(); - let instance = Instance::new(InstanceCreateInfo { - enabled_extensions: required_extensions, - // Enable enumerating devices that use non-conformant vulkan implementations. (ex. MoltenVK) - enumerate_portability: true, - ..Default::default() - }) + let library = VulkanLibrary::new().unwrap(); + let required_extensions = vulkano_win::required_extensions(&library); + let instance = Instance::new( + library, + InstanceCreateInfo { + enabled_extensions: required_extensions, + // Enable enumerating devices that use non-conformant vulkan implementations. (ex. MoltenVK) + enumerate_portability: true, + ..Default::default() + }, + ) .unwrap(); let event_loop = EventLoop::new(); diff --git a/examples/src/bin/multi_window_game_of_life/app.rs b/examples/src/bin/multi_window_game_of_life/app.rs index dff4c3d6..7eb5fa34 100644 --- a/examples/src/bin/multi_window_game_of_life/app.rs +++ b/examples/src/bin/multi_window_game_of_life/app.rs @@ -71,8 +71,8 @@ impl App { id1, RenderPipeline::new( // Use same queue.. for synchronization - self.context.graphics_queue(), - self.context.graphics_queue(), + self.context.graphics_queue().clone(), + self.context.graphics_queue().clone(), [ (WINDOW_WIDTH / SCALING) as u32, (WINDOW_HEIGHT / SCALING) as u32, @@ -86,8 +86,8 @@ impl App { self.pipelines.insert( id2, RenderPipeline::new( - self.context.graphics_queue(), - self.context.graphics_queue(), + self.context.graphics_queue().clone(), + self.context.graphics_queue().clone(), [ (WINDOW2_WIDTH / SCALING) as u32, (WINDOW2_HEIGHT / SCALING) as u32, diff --git a/examples/src/bin/multiview.rs b/examples/src/bin/multiview.rs index d39c3d60..048a253c 100644 --- a/examples/src/bin/multiview.rs +++ b/examples/src/bin/multiview.rs @@ -45,18 +45,23 @@ use vulkano::{ RenderPass, RenderPassCreateInfo, StoreOp, Subpass, SubpassDescription, }, sync::{self, GpuFuture}, + VulkanLibrary, }; fn main() { - let instance = Instance::new(InstanceCreateInfo { - enabled_extensions: InstanceExtensions { - khr_get_physical_device_properties2: true, // required to get multiview limits - ..InstanceExtensions::none() + let library = VulkanLibrary::new().unwrap(); + let instance = Instance::new( + library, + InstanceCreateInfo { + enabled_extensions: InstanceExtensions { + khr_get_physical_device_properties2: true, // required to get multiview limits + ..InstanceExtensions::none() + }, + // Enable enumerating devices that use non-conformant vulkan implementations. (ex. MoltenVK) + enumerate_portability: true, + ..Default::default() }, - // Enable enumerating devices that use non-conformant vulkan implementations. (ex. MoltenVK) - enumerate_portability: true, - ..Default::default() - }) + ) .unwrap(); let device_extensions = DeviceExtensions { diff --git a/examples/src/bin/occlusion-query.rs b/examples/src/bin/occlusion-query.rs index 7e87c9b6..9d207b0a 100644 --- a/examples/src/bin/occlusion-query.rs +++ b/examples/src/bin/occlusion-query.rs @@ -41,6 +41,7 @@ use vulkano::{ acquire_next_image, AcquireError, Swapchain, SwapchainCreateInfo, SwapchainCreationError, }, sync::{self, FlushError, GpuFuture}, + VulkanLibrary, }; use vulkano_win::VkSurfaceBuild; use winit::{ @@ -50,13 +51,17 @@ use winit::{ }; fn main() { - let required_extensions = vulkano_win::required_extensions(); - let instance = Instance::new(InstanceCreateInfo { - enabled_extensions: required_extensions, - // Enable enumerating devices that use non-conformant vulkan implementations. (ex. MoltenVK) - enumerate_portability: true, - ..Default::default() - }) + let library = VulkanLibrary::new().unwrap(); + let required_extensions = vulkano_win::required_extensions(&library); + let instance = Instance::new( + library, + InstanceCreateInfo { + enabled_extensions: required_extensions, + // Enable enumerating devices that use non-conformant vulkan implementations. (ex. MoltenVK) + enumerate_portability: true, + ..Default::default() + }, + ) .unwrap(); let event_loop = EventLoop::new(); diff --git a/examples/src/bin/pipeline-caching.rs b/examples/src/bin/pipeline-caching.rs index 6745147c..7be6a1b6 100644 --- a/examples/src/bin/pipeline-caching.rs +++ b/examples/src/bin/pipeline-caching.rs @@ -38,15 +38,20 @@ use vulkano::{ }, instance::{Instance, InstanceCreateInfo}, pipeline::{cache::PipelineCache, ComputePipeline}, + VulkanLibrary, }; fn main() { // As with other examples, the first step is to create an instance. - let instance = Instance::new(InstanceCreateInfo { - // Enable enumerating devices that use non-conformant vulkan implementations. (ex. MoltenVK) - enumerate_portability: true, - ..Default::default() - }) + let library = VulkanLibrary::new().unwrap(); + let instance = Instance::new( + library, + InstanceCreateInfo { + // Enable enumerating devices that use non-conformant vulkan implementations. (ex. MoltenVK) + enumerate_portability: true, + ..Default::default() + }, + ) .unwrap(); // Choose which physical device to use. diff --git a/examples/src/bin/push-constants.rs b/examples/src/bin/push-constants.rs index 4cdee84f..7a259971 100644 --- a/examples/src/bin/push-constants.rs +++ b/examples/src/bin/push-constants.rs @@ -23,14 +23,19 @@ use vulkano::{ instance::{Instance, InstanceCreateInfo}, pipeline::{ComputePipeline, Pipeline, PipelineBindPoint}, sync::{self, GpuFuture}, + VulkanLibrary, }; fn main() { - let instance = Instance::new(InstanceCreateInfo { - // Enable enumerating devices that use non-conformant vulkan implementations. (ex. MoltenVK) - enumerate_portability: true, - ..Default::default() - }) + let library = VulkanLibrary::new().unwrap(); + let instance = Instance::new( + library, + InstanceCreateInfo { + // Enable enumerating devices that use non-conformant vulkan implementations. (ex. MoltenVK) + enumerate_portability: true, + ..Default::default() + }, + ) .unwrap(); let device_extensions = DeviceExtensions { diff --git a/examples/src/bin/push-descriptors/main.rs b/examples/src/bin/push-descriptors/main.rs index 94b5550b..d8d800ae 100644 --- a/examples/src/bin/push-descriptors/main.rs +++ b/examples/src/bin/push-descriptors/main.rs @@ -41,6 +41,7 @@ use vulkano::{ acquire_next_image, AcquireError, Swapchain, SwapchainCreateInfo, SwapchainCreationError, }, sync::{self, FlushError, GpuFuture}, + VulkanLibrary, }; use vulkano_win::VkSurfaceBuild; use winit::{ @@ -50,13 +51,17 @@ use winit::{ }; fn main() { - let required_extensions = vulkano_win::required_extensions(); - let instance = Instance::new(InstanceCreateInfo { - enabled_extensions: required_extensions, - // Enable enumerating devices that use non-conformant vulkan implementations. (ex. MoltenVK) - enumerate_portability: true, - ..Default::default() - }) + let library = VulkanLibrary::new().unwrap(); + let required_extensions = vulkano_win::required_extensions(&library); + let instance = Instance::new( + library, + InstanceCreateInfo { + enabled_extensions: required_extensions, + // Enable enumerating devices that use non-conformant vulkan implementations. (ex. MoltenVK) + enumerate_portability: true, + ..Default::default() + }, + ) .unwrap(); let event_loop = EventLoop::new(); diff --git a/examples/src/bin/runtime-shader/main.rs b/examples/src/bin/runtime-shader/main.rs index 02659021..6be92510 100644 --- a/examples/src/bin/runtime-shader/main.rs +++ b/examples/src/bin/runtime-shader/main.rs @@ -48,6 +48,7 @@ use vulkano::{ acquire_next_image, AcquireError, Swapchain, SwapchainCreateInfo, SwapchainCreationError, }, sync::{self, FlushError, GpuFuture}, + VulkanLibrary, }; use vulkano_win::VkSurfaceBuild; use winit::{ @@ -66,13 +67,17 @@ pub struct Vertex { impl_vertex!(Vertex, position, color); fn main() { - let required_extensions = vulkano_win::required_extensions(); - let instance = Instance::new(InstanceCreateInfo { - enabled_extensions: required_extensions, - // Enable enumerating devices that use non-conformant vulkan implementations. (ex. MoltenVK) - enumerate_portability: true, - ..Default::default() - }) + let library = VulkanLibrary::new().unwrap(); + let required_extensions = vulkano_win::required_extensions(&library); + let instance = Instance::new( + library, + InstanceCreateInfo { + enabled_extensions: required_extensions, + // Enable enumerating devices that use non-conformant vulkan implementations. (ex. MoltenVK) + enumerate_portability: true, + ..Default::default() + }, + ) .unwrap(); let event_loop = EventLoop::new(); diff --git a/examples/src/bin/runtime_array/main.rs b/examples/src/bin/runtime_array/main.rs index 3349de70..e9458bda 100644 --- a/examples/src/bin/runtime_array/main.rs +++ b/examples/src/bin/runtime_array/main.rs @@ -46,6 +46,7 @@ use vulkano::{ acquire_next_image, AcquireError, Swapchain, SwapchainCreateInfo, SwapchainCreationError, }, sync::{self, FlushError, GpuFuture}, + VulkanLibrary, }; use vulkano_win::VkSurfaceBuild; use winit::{ @@ -58,13 +59,17 @@ fn main() { // The start of this example is exactly the same as `triangle`. You should read the // `triangle` example if you haven't done so yet. - let required_extensions = vulkano_win::required_extensions(); - let instance = Instance::new(InstanceCreateInfo { - enabled_extensions: required_extensions, - // Enable enumerating devices that use non-conformant vulkan implementations. (ex. MoltenVK) - enumerate_portability: true, - ..Default::default() - }) + let library = VulkanLibrary::new().unwrap(); + let required_extensions = vulkano_win::required_extensions(&library); + let instance = Instance::new( + library, + InstanceCreateInfo { + enabled_extensions: required_extensions, + // Enable enumerating devices that use non-conformant vulkan implementations. (ex. MoltenVK) + enumerate_portability: true, + ..Default::default() + }, + ) .unwrap(); let event_loop = EventLoop::new(); diff --git a/examples/src/bin/self-copy-buffer.rs b/examples/src/bin/self-copy-buffer.rs index 3223187f..a464a51b 100644 --- a/examples/src/bin/self-copy-buffer.rs +++ b/examples/src/bin/self-copy-buffer.rs @@ -23,14 +23,19 @@ use vulkano::{ instance::{Instance, InstanceCreateInfo}, pipeline::{ComputePipeline, Pipeline, PipelineBindPoint}, sync::{self, GpuFuture}, + VulkanLibrary, }; fn main() { - let instance = Instance::new(InstanceCreateInfo { - // Enable enumerating devices that use non-conformant vulkan implementations. (ex. MoltenVK) - enumerate_portability: true, - ..Default::default() - }) + let library = VulkanLibrary::new().unwrap(); + let instance = Instance::new( + library, + InstanceCreateInfo { + // Enable enumerating devices that use non-conformant vulkan implementations. (ex. MoltenVK) + enumerate_portability: true, + ..Default::default() + }, + ) .unwrap(); let device_extensions = DeviceExtensions { diff --git a/examples/src/bin/shader-include/main.rs b/examples/src/bin/shader-include/main.rs index ad5ff73d..3d60f80b 100644 --- a/examples/src/bin/shader-include/main.rs +++ b/examples/src/bin/shader-include/main.rs @@ -22,14 +22,19 @@ use vulkano::{ instance::{Instance, InstanceCreateInfo}, pipeline::{ComputePipeline, Pipeline, PipelineBindPoint}, sync::{self, GpuFuture}, + VulkanLibrary, }; fn main() { - let instance = Instance::new(InstanceCreateInfo { - // Enable enumerating devices that use non-conformant vulkan implementations. (ex. MoltenVK) - enumerate_portability: true, - ..Default::default() - }) + let library = VulkanLibrary::new().unwrap(); + let instance = Instance::new( + library, + InstanceCreateInfo { + // Enable enumerating devices that use non-conformant vulkan implementations. (ex. MoltenVK) + enumerate_portability: true, + ..Default::default() + }, + ) .unwrap(); let device_extensions = DeviceExtensions { diff --git a/examples/src/bin/shader-types-sharing.rs b/examples/src/bin/shader-types-sharing.rs index 2af7b97e..995c4c46 100644 --- a/examples/src/bin/shader-types-sharing.rs +++ b/examples/src/bin/shader-types-sharing.rs @@ -39,14 +39,19 @@ use vulkano::{ instance::{Instance, InstanceCreateInfo}, pipeline::{ComputePipeline, Pipeline, PipelineBindPoint}, sync::{self, GpuFuture}, + VulkanLibrary, }; fn main() { - let instance = Instance::new(InstanceCreateInfo { - // Enable enumerating devices that use non-conformant vulkan implementations. (ex. MoltenVK) - enumerate_portability: true, - ..Default::default() - }) + let library = VulkanLibrary::new().unwrap(); + let instance = Instance::new( + library, + InstanceCreateInfo { + // Enable enumerating devices that use non-conformant vulkan implementations. (ex. MoltenVK) + enumerate_portability: true, + ..Default::default() + }, + ) .unwrap(); let device_extensions = DeviceExtensions { diff --git a/examples/src/bin/simple-particles.rs b/examples/src/bin/simple-particles.rs index 5dae85a5..afb39a5f 100644 --- a/examples/src/bin/simple-particles.rs +++ b/examples/src/bin/simple-particles.rs @@ -40,6 +40,7 @@ use vulkano::{ render_pass::{Framebuffer, FramebufferCreateInfo, Subpass}, swapchain::{PresentMode, Swapchain, SwapchainCreateInfo}, sync::{FenceSignalFuture, GpuFuture}, + VulkanLibrary, }; use vulkano_win::VkSurfaceBuild; use winit::{ @@ -56,13 +57,17 @@ const PARTICLE_COUNT: usize = 100_000; fn main() { // The usual Vulkan initialization. // Largely the same as example `triangle.rs` until further commentation is provided. - let required_extensions = vulkano_win::required_extensions(); - let instance = Instance::new(InstanceCreateInfo { - enabled_extensions: required_extensions, - // Enable enumerating devices that use non-conformant vulkan implementations. (ex. MoltenVK) - enumerate_portability: true, - ..Default::default() - }) + let library = VulkanLibrary::new().unwrap(); + let required_extensions = vulkano_win::required_extensions(&library); + let instance = Instance::new( + library, + InstanceCreateInfo { + enabled_extensions: required_extensions, + // Enable enumerating devices that use non-conformant vulkan implementations. (ex. MoltenVK) + enumerate_portability: true, + ..Default::default() + }, + ) .unwrap(); let event_loop = EventLoop::new(); diff --git a/examples/src/bin/specialization-constants.rs b/examples/src/bin/specialization-constants.rs index b87c72e3..a31196cc 100644 --- a/examples/src/bin/specialization-constants.rs +++ b/examples/src/bin/specialization-constants.rs @@ -20,14 +20,19 @@ use vulkano::{ instance::{Instance, InstanceCreateInfo}, pipeline::{ComputePipeline, Pipeline, PipelineBindPoint}, sync::{self, GpuFuture}, + VulkanLibrary, }; fn main() { - let instance = Instance::new(InstanceCreateInfo { - // Enable enumerating devices that use non-conformant vulkan implementations. (ex. MoltenVK) - enumerate_portability: true, - ..Default::default() - }) + let library = VulkanLibrary::new().unwrap(); + let instance = Instance::new( + library, + InstanceCreateInfo { + // Enable enumerating devices that use non-conformant vulkan implementations. (ex. MoltenVK) + enumerate_portability: true, + ..Default::default() + }, + ) .unwrap(); let device_extensions = DeviceExtensions { diff --git a/examples/src/bin/teapot/main.rs b/examples/src/bin/teapot/main.rs index bf34bde0..da838f2b 100644 --- a/examples/src/bin/teapot/main.rs +++ b/examples/src/bin/teapot/main.rs @@ -38,6 +38,7 @@ use vulkano::{ acquire_next_image, AcquireError, Swapchain, SwapchainCreateInfo, SwapchainCreationError, }, sync::{self, FlushError, GpuFuture}, + VulkanLibrary, }; use vulkano_win::VkSurfaceBuild; use winit::{ @@ -50,13 +51,17 @@ fn main() { // The start of this example is exactly the same as `triangle`. You should read the // `triangle` example if you haven't done so yet. - let required_extensions = vulkano_win::required_extensions(); - let instance = Instance::new(InstanceCreateInfo { - enabled_extensions: required_extensions, - // Enable enumerating devices that use non-conformant vulkan implementations. (ex. MoltenVK) - enumerate_portability: true, - ..Default::default() - }) + let library = VulkanLibrary::new().unwrap(); + let required_extensions = vulkano_win::required_extensions(&library); + let instance = Instance::new( + library, + InstanceCreateInfo { + enabled_extensions: required_extensions, + // Enable enumerating devices that use non-conformant vulkan implementations. (ex. MoltenVK) + enumerate_portability: true, + ..Default::default() + }, + ) .unwrap(); let event_loop = EventLoop::new(); diff --git a/examples/src/bin/tessellation.rs b/examples/src/bin/tessellation.rs index 2a5fbd55..60876e11 100644 --- a/examples/src/bin/tessellation.rs +++ b/examples/src/bin/tessellation.rs @@ -47,6 +47,7 @@ use vulkano::{ acquire_next_image, AcquireError, Swapchain, SwapchainCreateInfo, SwapchainCreationError, }, sync::{self, FlushError, GpuFuture}, + VulkanLibrary, }; use vulkano_win::VkSurfaceBuild; use winit::{ @@ -151,13 +152,17 @@ mod fs { } fn main() { - let required_extensions = vulkano_win::required_extensions(); - let instance = Instance::new(InstanceCreateInfo { - enabled_extensions: required_extensions, - // Enable enumerating devices that use non-conformant vulkan implementations. (ex. MoltenVK) - enumerate_portability: true, - ..Default::default() - }) + let library = VulkanLibrary::new().unwrap(); + let required_extensions = vulkano_win::required_extensions(&library); + let instance = Instance::new( + library, + InstanceCreateInfo { + enabled_extensions: required_extensions, + // Enable enumerating devices that use non-conformant vulkan implementations. (ex. MoltenVK) + enumerate_portability: true, + ..Default::default() + }, + ) .unwrap(); let event_loop = EventLoop::new(); diff --git a/examples/src/bin/texture_array/main.rs b/examples/src/bin/texture_array/main.rs index f2aa8356..7a0437f0 100644 --- a/examples/src/bin/texture_array/main.rs +++ b/examples/src/bin/texture_array/main.rs @@ -41,6 +41,7 @@ use vulkano::{ acquire_next_image, AcquireError, Swapchain, SwapchainCreateInfo, SwapchainCreationError, }, sync::{self, FlushError, GpuFuture}, + VulkanLibrary, }; use vulkano_win::VkSurfaceBuild; use winit::{ @@ -55,13 +56,17 @@ fn main() { // And not this: // uniform sampler2D array_of_textures[42]; - let required_extensions = vulkano_win::required_extensions(); - let instance = Instance::new(InstanceCreateInfo { - enabled_extensions: required_extensions, - // Enable enumerating devices that use non-conformant vulkan implementations. (ex. MoltenVK) - enumerate_portability: true, - ..Default::default() - }) + let library = VulkanLibrary::new().unwrap(); + let required_extensions = vulkano_win::required_extensions(&library); + let instance = Instance::new( + library, + InstanceCreateInfo { + enabled_extensions: required_extensions, + // Enable enumerating devices that use non-conformant vulkan implementations. (ex. MoltenVK) + enumerate_portability: true, + ..Default::default() + }, + ) .unwrap(); let event_loop = EventLoop::new(); diff --git a/examples/src/bin/triangle-v1_3.rs b/examples/src/bin/triangle-v1_3.rs index 15b49c8f..b3e9ad0b 100644 --- a/examples/src/bin/triangle-v1_3.rs +++ b/examples/src/bin/triangle-v1_3.rs @@ -49,7 +49,7 @@ use vulkano::{ acquire_next_image, AcquireError, Swapchain, SwapchainCreateInfo, SwapchainCreationError, }, sync::{self, FlushError, GpuFuture}, - Version, + Version, VulkanLibrary, }; use vulkano_win::VkSurfaceBuild; use winit::{ @@ -66,15 +66,19 @@ fn main() { // All the window-drawing functionalities are part of non-core extensions that we need // to enable manually. To do so, we ask the `vulkano_win` crate for the list of extensions // required to draw to a window. - let required_extensions = vulkano_win::required_extensions(); + let library = VulkanLibrary::new().unwrap(); + let required_extensions = vulkano_win::required_extensions(&library); // Now creating the instance. - let instance = Instance::new(InstanceCreateInfo { - enabled_extensions: required_extensions, - // Enable enumerating devices that use non-conformant vulkan implementations. (ex. MoltenVK) - enumerate_portability: true, - ..Default::default() - }) + let instance = Instance::new( + library, + InstanceCreateInfo { + enabled_extensions: required_extensions, + // Enable enumerating devices that use non-conformant vulkan implementations. (ex. MoltenVK) + enumerate_portability: true, + ..Default::default() + }, + ) .unwrap(); // The objective of this example is to draw a triangle on a window. To do so, we first need to diff --git a/examples/src/bin/triangle.rs b/examples/src/bin/triangle.rs index 0b71121c..4a65d5d9 100644 --- a/examples/src/bin/triangle.rs +++ b/examples/src/bin/triangle.rs @@ -43,6 +43,7 @@ use vulkano::{ acquire_next_image, AcquireError, Swapchain, SwapchainCreateInfo, SwapchainCreationError, }, sync::{self, FlushError, GpuFuture}, + VulkanLibrary, }; use vulkano_win::VkSurfaceBuild; use winit::{ @@ -59,15 +60,19 @@ fn main() { // All the window-drawing functionalities are part of non-core extensions that we need // to enable manually. To do so, we ask the `vulkano_win` crate for the list of extensions // required to draw to a window. - let required_extensions = vulkano_win::required_extensions(); + let library = VulkanLibrary::new().unwrap(); + let required_extensions = vulkano_win::required_extensions(&library); // Now creating the instance. - let instance = Instance::new(InstanceCreateInfo { - enabled_extensions: required_extensions, - // Enable enumerating devices that use non-conformant vulkan implementations. (ex. MoltenVK) - enumerate_portability: true, - ..Default::default() - }) + let instance = Instance::new( + library, + InstanceCreateInfo { + enabled_extensions: required_extensions, + // Enable enumerating devices that use non-conformant vulkan implementations. (ex. MoltenVK) + enumerate_portability: true, + ..Default::default() + }, + ) .unwrap(); // The objective of this example is to draw a triangle on a window. To do so, we first need to diff --git a/vulkano-util/src/context.rs b/vulkano-util/src/context.rs index 15ba583b..dd26d8a2 100644 --- a/vulkano-util/src/context.rs +++ b/vulkano-util/src/context.rs @@ -8,26 +8,39 @@ // according to those terms. use std::sync::Arc; -use vulkano::device::physical::{PhysicalDevice, PhysicalDeviceType}; -use vulkano::device::{ - Device, DeviceCreateInfo, DeviceExtensions, Features, Queue, QueueCreateInfo, +use vulkano::{ + device::{ + physical::{PhysicalDevice, PhysicalDeviceType}, + Device, DeviceCreateInfo, DeviceExtensions, Features, Queue, QueueCreateInfo, + }, + instance::{ + debug::{DebugUtilsMessenger, DebugUtilsMessengerCreateInfo}, + Instance, InstanceCreateInfo, InstanceExtensions, + }, }; -use vulkano::instance::debug::{DebugUtilsMessenger, DebugUtilsMessengerCreateInfo}; -use vulkano::instance::{Instance, InstanceCreateInfo}; -use vulkano::Version; +use vulkano::{Version, VulkanLibrary}; /// A configuration struct to pass various creation options to create [`VulkanoContext`]. +/// +/// Instance extensions that are required for surface creation will be appended to the config when +/// creating [`VulkanoContext`]. pub struct VulkanoConfig { pub instance_create_info: InstanceCreateInfo, + /// Pass the `DebugUtilsMessengerCreateInfo` to create the debug callback /// for printing debug information at runtime. pub debug_create_info: Option, + /// Pass filter function for your physical device selection. See default for example. pub device_filter_fn: Arc bool>, + /// Pass priority order function for your physical device selection. See default for example. pub device_priority_fn: Arc u32>, + pub device_extensions: DeviceExtensions, + pub device_features: Features, + /// Print your selected device name at start. pub print_device_name: bool, } @@ -41,7 +54,7 @@ impl Default for VulkanoConfig { VulkanoConfig { instance_create_info: InstanceCreateInfo { application_version: Version::V1_2, - enabled_extensions: vulkano_win::required_extensions(), + enabled_extensions: InstanceExtensions::none(), ..Default::default() }, debug_create_info: None, @@ -65,7 +78,8 @@ impl Default for VulkanoConfig { /// A utility struct to create, access and hold alive Vulkano device, instance and queues. /// /// Vulkano context is used in the creation of your graphics or compute pipelines, images and -/// in the creation of [`VulkanoWindowRenderer`] through [`VulkanoWindows`]. +/// in the creation of [`VulkanoWindowRenderer`](crate::renderer::VulkanoWindowRenderer) through +/// [`VulkanoWindows`](crate::window::VulkanoWindows). /// /// ## Example /// @@ -98,8 +112,25 @@ impl VulkanoContext { /// /// - Panics where the underlying Vulkano struct creations fail pub fn new(mut config: VulkanoConfig) -> Self { + let library = match VulkanLibrary::new() { + Ok(x) => x, + #[cfg(target_os = "macos")] + Err(vulkano::library::LoadingError::LibraryLoadFailure(err)) => { + panic!("Failed to load Vulkan library: {}. Did you install vulkanSDK from https://vulkan.lunarg.com/sdk/home ?", err); + } + Err(err) => { + panic!("Failed to load Vulkan library: {}.", err); + } + }; + + // Append required extensions + config.instance_create_info.enabled_extensions = vulkano_win::required_extensions(&library) + .union(&config.instance_create_info.enabled_extensions); + // Create instance - let instance = create_instance(config.instance_create_info); + let instance = Instance::new(library.clone(), config.instance_create_info) + .expect("Failed to create instance"); + // Create debug callback let _debug_utils_messenger = if let Some(dbg_create_info) = config.debug_create_info.take() { @@ -110,6 +141,7 @@ impl VulkanoContext { } else { None }; + // Get prioritized device let physical_device = PhysicalDevice::enumerate(&instance) .filter(|p| (config.device_filter_fn)(p)) @@ -140,8 +172,8 @@ impl VulkanoContext { } } - /// Creates vulkano device with required queue families and required extensions. Creates a separate queue for compute - /// if possible. If not, same queue as graphics is used. + /// Creates vulkano device with required queue families and required extensions. Creates a + /// separate queue for compute if possible. If not, same queue as graphics is used. fn create_device( physical: PhysicalDevice, device_extensions: DeviceExtensions, @@ -189,17 +221,17 @@ impl VulkanoContext { (device, gfx_queue, compute_queue) } - /// Check device name + /// Returns the name of the device. pub fn device_name(&self) -> &str { &self.device.physical_device().properties().device_name } - /// Check device type + /// Returns the type of the device. pub fn device_type(&self) -> PhysicalDeviceType { self.device.physical_device().properties().device_type } - /// Check device memory count + /// Returns the maximum memory allocation of the device. pub fn max_memory(&self) -> u32 { self.device .physical_device() @@ -207,43 +239,25 @@ impl VulkanoContext { .max_memory_allocation_count as u32 } - /// Access instance - pub fn instance(&self) -> Arc { - self.instance.clone() + /// Returns the instance. + pub fn instance(&self) -> &Arc { + &self.instance } - /// Access device - pub fn device(&self) -> Arc { - self.device.clone() + /// Returns the device. + pub fn device(&self) -> &Arc { + &self.device } - /// Access rendering queue - pub fn graphics_queue(&self) -> Arc { - self.graphics_queue.clone() + /// Returns the graphics queue. + pub fn graphics_queue(&self) -> &Arc { + &self.graphics_queue } - /// Access compute queue. Depending on your device, this might be the same as graphics queue. - pub fn compute_queue(&self) -> Arc { - self.compute_queue.clone() - } -} - -/// Create instance, but remind user to install vulkan SDK on mac os if loading error is received on that platform. -fn create_instance(instance_create_info: InstanceCreateInfo) -> Arc { - #[cfg(target_os = "macos")] - { - match Instance::new(instance_create_info) { - Err(e) => match e { - vulkano::instance::InstanceCreationError::LoadingError(le) => { - Err(le).expect("Failed to create instance. Did you install vulkanSDK from https://vulkan.lunarg.com/sdk/home ?") - } - _ => Err(e).expect("Failed to create instance"), - }, - Ok(i) => i, - } - } - #[cfg(not(target_os = "macos"))] - { - Instance::new(instance_create_info).expect("Failed to create instance") + /// Returns the compute queue. + /// + /// Depending on your device, this might be the same as graphics queue. + pub fn compute_queue(&self) -> &Arc { + &self.compute_queue } } diff --git a/vulkano-util/src/renderer.rs b/vulkano-util/src/renderer.rs index db4b2774..10924468 100644 --- a/vulkano-util/src/renderer.rs +++ b/vulkano-util/src/renderer.rs @@ -66,22 +66,23 @@ impl VulkanoWindowRenderer { swapchain_create_info_modify: fn(&mut SwapchainCreateInfo), ) -> VulkanoWindowRenderer { // Create rendering surface from window - let surface = create_surface_from_winit(window, vulkano_context.instance()).unwrap(); + let surface = + create_surface_from_winit(window, vulkano_context.instance().clone()).unwrap(); // Create swap chain & frame(s) to which we'll render - let (swap_chain, final_views) = Self::create_swap_chain( - vulkano_context.device(), + let (swap_chain, final_views) = Self::create_swapchain( + vulkano_context.device().clone(), surface.clone(), descriptor, swapchain_create_info_modify, ); - let previous_frame_end = Some(sync::now(vulkano_context.device()).boxed()); + let previous_frame_end = Some(sync::now(vulkano_context.device().clone()).boxed()); VulkanoWindowRenderer { surface, - graphics_queue: vulkano_context.graphics_queue(), - compute_queue: vulkano_context.compute_queue(), + graphics_queue: vulkano_context.graphics_queue().clone(), + compute_queue: vulkano_context.compute_queue().clone(), swap_chain, final_views, additional_image_views: HashMap::default(), @@ -94,7 +95,7 @@ impl VulkanoWindowRenderer { /// Creates the swapchain and its images based on [`WindowDescriptor`]. The swapchain creation /// can be modified with the `swapchain_create_info_modify` function passed as an input. - fn create_swap_chain( + fn create_swapchain( device: Arc, surface: Arc>, window_descriptor: &WindowDescriptor, @@ -236,7 +237,7 @@ impl VulkanoWindowRenderer { } /// Begin your rendering by calling `acquire`. - /// Returns a [`GpuFuture`](vulkano::sync::future::GpuFuture) representing the time after which the swapchain image has been acquired + /// Returns a [`GpuFuture`](vulkano::sync::GpuFuture) representing the time after which the swapchain image has been acquired /// and previous frame ended. /// Execute your command buffers after calling this function and finish rendering by calling [`VulkanoWindowRenderer::present`]. pub fn acquire(&mut self) -> std::result::Result, AcquireError> { diff --git a/vulkano-util/src/window.rs b/vulkano-util/src/window.rs index 1ddc421e..ae3136ad 100644 --- a/vulkano-util/src/window.rs +++ b/vulkano-util/src/window.rs @@ -339,7 +339,7 @@ pub struct WindowDescriptor { pub cursor_visible: bool, /// Sets whether the window locks the cursor inside its borders when the window has focus. pub cursor_locked: bool, - /// Sets the [`WindowMode`](crate::WindowMode). + /// Sets the [`WindowMode`]. pub mode: WindowMode, /// Sets whether the background of the window should be transparent. pub transparent: bool, diff --git a/vulkano-win/src/winit.rs b/vulkano-win/src/winit.rs index 9082c10a..e8532c17 100644 --- a/vulkano-win/src/winit.rs +++ b/vulkano-win/src/winit.rs @@ -1,20 +1,16 @@ -use std::borrow::Borrow; -use std::error; -use std::fmt; -use std::rc::Rc; -use std::sync::Arc; - -use vulkano::instance::Instance; -use vulkano::instance::InstanceExtensions; -use vulkano::swapchain::Surface; -use vulkano::swapchain::SurfaceCreationError; +use std::{borrow::Borrow, error, fmt, rc::Rc, sync::Arc}; +use vulkano::{ + instance::{Instance, InstanceExtensions}, + swapchain::{Surface, SurfaceCreationError}, + VulkanLibrary, +}; use winit::{ error::OsError as WindowCreationError, event_loop::EventLoopWindowTarget, window::{Window, WindowBuilder}, }; -pub fn required_extensions() -> InstanceExtensions { +pub fn required_extensions(library: &VulkanLibrary) -> InstanceExtensions { let ideal = InstanceExtensions { khr_surface: true, khr_xlib_surface: true, @@ -29,10 +25,7 @@ pub fn required_extensions() -> InstanceExtensions { ..InstanceExtensions::none() }; - match InstanceExtensions::supported_by_core() { - Ok(supported) => supported.intersection(&ideal), - Err(_) => InstanceExtensions::none(), - } + library.supported_extensions().intersection(&ideal) } /// Create a surface from a Winit window or a reference to it. The surface takes `W` to prevent it diff --git a/vulkano/src/device/extensions.rs b/vulkano/src/device/extensions.rs index 831b91e2..e4419e2d 100644 --- a/vulkano/src/device/extensions.rs +++ b/vulkano/src/device/extensions.rs @@ -7,10 +7,7 @@ // notice may not be copied, modified, or distributed except // according to those terms. -use crate::device::physical::PhysicalDevice; -pub use crate::extensions::{ - ExtensionRestriction, ExtensionRestrictionError, OneOfRequirements, SupportedExtensionsError, -}; +pub use crate::extensions::{ExtensionRestriction, ExtensionRestrictionError, OneOfRequirements}; use crate::instance::InstanceExtensions; use crate::Version; use std::ffi::{CStr, CString}; @@ -19,28 +16,6 @@ use std::fmt::Formatter; // Generated by build.rs include!(concat!(env!("OUT_DIR"), "/device_extensions.rs")); -impl DeviceExtensions { - /// See the docs of supported_by_device(). - #[deprecated( - since = "0.25", - note = "Use PhysicalDevice::supported_extensions instead" - )] - pub fn supported_by_device_raw( - physical_device: PhysicalDevice, - ) -> Result { - Ok(*physical_device.supported_extensions()) - } - - /// Returns a `DeviceExtensions` object with extensions supported by the `PhysicalDevice`. - #[deprecated( - since = "0.25", - note = "Use PhysicalDevice::supported_extensions instead" - )] - pub fn supported_by_device(physical_device: PhysicalDevice) -> Self { - *physical_device.supported_extensions() - } -} - #[cfg(test)] mod tests { use crate::device::DeviceExtensions; diff --git a/vulkano/src/device/mod.rs b/vulkano/src/device/mod.rs index e9882906..79d56c59 100644 --- a/vulkano/src/device/mod.rs +++ b/vulkano/src/device/mod.rs @@ -15,16 +15,17 @@ //! Basic example: //! //! ```no_run -//! use vulkano::device::physical::PhysicalDevice; -//! use vulkano::device::{Device, DeviceCreateInfo, DeviceExtensions, Features, QueueCreateInfo}; -//! use vulkano::instance::{Instance, InstanceExtensions}; -//! use vulkano::Version; +//! use vulkano::{ +//! device::{physical::PhysicalDevice, Device, DeviceCreateInfo, DeviceExtensions, Features, QueueCreateInfo}, +//! instance::{Instance, InstanceExtensions}, +//! Version, VulkanLibrary, +//! }; //! //! // Creating the instance. See the documentation of the `instance` module. -//! let instance = match Instance::new(Default::default()) { -//! Ok(i) => i, -//! Err(err) => panic!("Couldn't build instance: {:?}", err) -//! }; +//! let library = VulkanLibrary::new() +//! .unwrap_or_else(|err| panic!("Couldn't load Vulkan library: {:?}", err)); +//! let instance = Instance::new(library, Default::default()) +//! .unwrap_or_else(|err| panic!("Couldn't create instance: {:?}", err)); //! //! // We just choose the first physical device. In a real application you would choose depending //! // on the capabilities of the physical device and the user's preferences. @@ -111,7 +112,7 @@ use crate::{ }; pub use crate::{ device::extensions::DeviceExtensions, - extensions::{ExtensionRestriction, ExtensionRestrictionError, SupportedExtensionsError}, + extensions::{ExtensionRestriction, ExtensionRestrictionError}, fns::DeviceFunctions, }; use ash::vk::Handle; @@ -447,7 +448,7 @@ impl Device { self.api_version } - /// Grants access to the Vulkan functions of the device. + /// Returns pointers to the raw Vulkan functions of the device. #[inline] pub fn fns(&self) -> &DeviceFunctions { &self.fns diff --git a/vulkano/src/device/physical.rs b/vulkano/src/device/physical.rs index 16d1ec5b..f88303a7 100644 --- a/vulkano/src/device/physical.rs +++ b/vulkano/src/device/physical.rs @@ -281,12 +281,14 @@ fn init_info2(instance: &Instance, info: &mut PhysicalDeviceInfo) { /// # Example /// /// ```no_run -/// # use vulkano::instance::Instance; -/// # use vulkano::instance::InstanceExtensions; -/// # use vulkano::Version; +/// # use vulkano::{ +/// # instance::{Instance, InstanceExtensions}, +/// # Version, VulkanLibrary, +/// # }; /// use vulkano::device::physical::PhysicalDevice; /// -/// # let instance = Instance::new(Default::default()).unwrap(); +/// # let library = VulkanLibrary::new().unwrap(); +/// # let instance = Instance::new(library, Default::default()).unwrap(); /// for physical_device in PhysicalDevice::enumerate(&instance) { /// print_infos(physical_device); /// } @@ -308,12 +310,14 @@ impl<'a> PhysicalDevice<'a> { /// # Example /// /// ```no_run - /// # use vulkano::instance::Instance; - /// # use vulkano::instance::InstanceExtensions; - /// # use vulkano::Version; + /// # use vulkano::{ + /// # instance::{Instance, InstanceExtensions}, + /// # Version, VulkanLibrary, + /// # }; /// use vulkano::device::physical::PhysicalDevice; /// - /// # let instance = Instance::new(Default::default()).unwrap(); + /// # let library = VulkanLibrary::new().unwrap(); + /// # let instance = Instance::new(library, Default::default()).unwrap(); /// for physical_device in PhysicalDevice::enumerate(&instance) { /// println!("Available device: {}", physical_device.properties().device_name); /// } @@ -340,12 +344,14 @@ impl<'a> PhysicalDevice<'a> { /// # Example /// /// ```no_run - /// use vulkano::instance::Instance; - /// use vulkano::instance::InstanceExtensions; + /// # use vulkano::{ + /// # instance::{Instance, InstanceExtensions}, + /// # Version, VulkanLibrary, + /// # }; /// use vulkano::device::physical::PhysicalDevice; - /// use vulkano::Version; /// - /// let instance = Instance::new(Default::default()).unwrap(); + /// # let library = VulkanLibrary::new().unwrap(); + /// # let instance = Instance::new(library, Default::default()).unwrap(); /// let first_physical_device = PhysicalDevice::from_index(&instance, 0).unwrap(); /// ``` #[inline] @@ -389,7 +395,7 @@ impl<'a> PhysicalDevice<'a> { /// Returns the version of Vulkan supported by this device. /// /// Unlike the `api_version` property, which is the version reported by the device directly, - /// this function returns the version the device can actually support, based on the instance's, + /// this function returns the version the device can actually support, based on the instance's /// `max_api_version`. #[inline] pub fn api_version(&self) -> Version { diff --git a/vulkano/src/extensions.rs b/vulkano/src/extensions.rs index 088d6163..81e14919 100644 --- a/vulkano/src/extensions.rs +++ b/vulkano/src/extensions.rs @@ -7,74 +7,10 @@ // notice may not be copied, modified, or distributed except // according to those terms. -use crate::instance::loader::LoadingError; -use crate::Error; -use crate::OomError; use crate::Version; use std::error; use std::fmt::{Display, Error as FmtError, Formatter}; -/// Error that can happen when loading the list of layers. -#[derive(Clone, Debug)] -pub enum SupportedExtensionsError { - /// Failed to load the Vulkan shared library. - LoadingError(LoadingError), - /// Not enough memory. - OomError(OomError), -} - -impl error::Error for SupportedExtensionsError { - #[inline] - fn source(&self) -> Option<&(dyn error::Error + 'static)> { - match *self { - SupportedExtensionsError::LoadingError(ref err) => Some(err), - SupportedExtensionsError::OomError(ref err) => Some(err), - } - } -} - -impl Display for SupportedExtensionsError { - #[inline] - fn fmt(&self, fmt: &mut Formatter) -> Result<(), FmtError> { - write!( - fmt, - "{}", - match *self { - SupportedExtensionsError::LoadingError(_) => - "failed to load the Vulkan shared library", - SupportedExtensionsError::OomError(_) => "not enough memory available", - } - ) - } -} - -impl From for SupportedExtensionsError { - #[inline] - fn from(err: OomError) -> SupportedExtensionsError { - SupportedExtensionsError::OomError(err) - } -} - -impl From for SupportedExtensionsError { - #[inline] - fn from(err: LoadingError) -> SupportedExtensionsError { - SupportedExtensionsError::LoadingError(err) - } -} - -impl From for SupportedExtensionsError { - #[inline] - fn from(err: Error) -> SupportedExtensionsError { - match err { - err @ Error::OutOfHostMemory => SupportedExtensionsError::OomError(OomError::from(err)), - err @ Error::OutOfDeviceMemory => { - SupportedExtensionsError::OomError(OomError::from(err)) - } - _ => panic!("unexpected error: {:?}", err), - } - } -} - /// An error that can happen when enabling an extension on an instance or device. #[derive(Clone, Copy, Debug)] pub struct ExtensionRestrictionError { diff --git a/vulkano/src/image/mod.rs b/vulkano/src/image/mod.rs index 56b0b890..aa803231 100644 --- a/vulkano/src/image/mod.rs +++ b/vulkano/src/image/mod.rs @@ -46,27 +46,27 @@ //! To be written. //! -pub use self::aspect::ImageAspect; -pub use self::aspect::ImageAspects; -pub use self::attachment::AttachmentImage; -pub use self::immutable::ImmutableImage; -pub use self::layout::ImageDescriptorLayouts; -pub use self::layout::ImageLayout; -pub use self::storage::StorageImage; -pub use self::swapchain::SwapchainImage; -pub use self::sys::ImageCreationError; -pub use self::traits::ImageAccess; -pub use self::traits::ImageInner; -pub use self::usage::ImageUsage; -pub use self::view::ImageViewAbstract; -use self::view::ImageViewType; -use crate::format::Format; -use crate::memory::ExternalMemoryHandleType; -use crate::memory::ExternalMemoryProperties; -use crate::DeviceSize; -use std::cmp; -use std::ops::BitAnd; -use std::ops::Range; +pub use self::{ + aspect::{ImageAspect, ImageAspects}, + attachment::AttachmentImage, + immutable::ImmutableImage, + layout::{ImageDescriptorLayouts, ImageLayout}, + storage::StorageImage, + swapchain::SwapchainImage, + sys::ImageCreationError, + traits::{ImageAccess, ImageInner}, + usage::ImageUsage, + view::{ImageViewAbstract, ImageViewType}, +}; +use crate::{ + format::Format, + memory::{ExternalMemoryHandleType, ExternalMemoryProperties}, + DeviceSize, +}; +use std::{ + cmp, + ops::{BitAnd, Range}, +}; mod aspect; pub mod attachment; // TODO: make private @@ -176,9 +176,13 @@ impl SampleCounts { /// should check the intersection of the supported sample counts because they don't have to /// match. You could similarily apply this to the stencil counts. /// ```no_run - /// # use vulkano::instance::Instance; - /// # use vulkano::device::physical::PhysicalDevice; - /// # let instance = Instance::new(Default::default()).unwrap(); + /// # use vulkano::{ + /// # instance::Instance, + /// # device::physical::PhysicalDevice, + /// # VulkanLibrary, + /// # }; + /// # let library = VulkanLibrary::new().unwrap(); + /// # let instance = Instance::new(library, Default::default()).unwrap(); /// # let physical_device = PhysicalDevice::from_index(&instance, 0).unwrap(); /// let properties = physical_device.properties(); /// let color_counts = properties.framebuffer_color_sample_counts; diff --git a/vulkano/src/instance/extensions.rs b/vulkano/src/instance/extensions.rs index 42b68047..efbd38c4 100644 --- a/vulkano/src/instance/extensions.rs +++ b/vulkano/src/instance/extensions.rs @@ -7,91 +7,18 @@ // notice may not be copied, modified, or distributed except // according to those terms. -use super::{loader, LoadingError}; -use crate::{check_errors, Success}; pub use crate::{ - extensions::{ - ExtensionRestriction, ExtensionRestrictionError, OneOfRequirements, - SupportedExtensionsError, - }, + extensions::{ExtensionRestriction, ExtensionRestrictionError, OneOfRequirements}, Version, }; use std::{ ffi::{CStr, CString}, fmt::Formatter, - ptr, }; // Generated by build.rs include!(concat!(env!("OUT_DIR"), "/instance_extensions.rs")); -impl InstanceExtensions { - /// See the docs of supported_by_core(). - pub fn supported_by_core_raw() -> Result { - InstanceExtensions::supported_by_core_raw_with_loader(loader::auto_loader()?) - } - - /// Returns an `InstanceExtensions` object with extensions supported by the core driver. - pub fn supported_by_core() -> Result { - match InstanceExtensions::supported_by_core_raw() { - Ok(l) => Ok(l), - Err(SupportedExtensionsError::LoadingError(e)) => Err(e), - Err(SupportedExtensionsError::OomError(e)) => panic!("{:?}", e), - } - } - - /// Same as `supported_by_core`, but allows specifying a loader. - pub fn supported_by_core_with_loader( - ptrs: &loader::FunctionPointers, - ) -> Result - where - L: loader::Loader, - { - match InstanceExtensions::supported_by_core_raw_with_loader(ptrs) { - Ok(l) => Ok(l), - Err(SupportedExtensionsError::LoadingError(e)) => Err(e), - Err(SupportedExtensionsError::OomError(e)) => panic!("{:?}", e), - } - } - - /// See the docs of supported_by_core(). - pub fn supported_by_core_raw_with_loader( - ptrs: &loader::FunctionPointers, - ) -> Result - where - L: loader::Loader, - { - let fns = ptrs.fns(); - - let extension_properties = unsafe { - loop { - let mut count = 0; - check_errors((fns.v1_0.enumerate_instance_extension_properties)( - ptr::null(), - &mut count, - ptr::null_mut(), - ))?; - - let mut properties = Vec::with_capacity(count as usize); - let result = check_errors((fns.v1_0.enumerate_instance_extension_properties)( - ptr::null(), - &mut count, - properties.as_mut_ptr(), - ))?; - - if !matches!(result, Success::Incomplete) { - properties.set_len(count as usize); - break properties; - } - } - }; - - Ok(Self::from(extension_properties.iter().map( - |property| unsafe { CStr::from_ptr(property.extension_name.as_ptr()) }, - ))) - } -} - #[cfg(test)] mod tests { use crate::instance::InstanceExtensions; diff --git a/vulkano/src/instance/layers.rs b/vulkano/src/instance/layers.rs index 905b8ec1..c1d2bde7 100644 --- a/vulkano/src/instance/layers.rs +++ b/vulkano/src/instance/layers.rs @@ -7,83 +7,13 @@ // notice may not be copied, modified, or distributed except // according to those terms. -use crate::check_errors; -use crate::instance::loader; -use crate::instance::loader::LoadingError; -use crate::Error; -use crate::OomError; -use crate::Success; use crate::Version; -use std::error; use std::ffi::CStr; -use std::fmt; -use std::ptr; - -/// Queries the list of layers that are available when creating an instance. -/// -/// On success, this function returns an iterator that produces -/// [`LayerProperties`](crate::instance::LayerProperties) objects. In order to enable a layer, you need -/// to pass its name (returned by `LayerProperties::name()`) when creating the -/// [`Instance`](crate::instance::Instance). -/// -/// This function returns an error if it failed to load the Vulkan library. -/// -/// > **Note**: It is possible that one of the layers enumerated here is no longer available when -/// > you create the `Instance`. This will lead to an error when calling `Instance::new`. The -/// > author isn't aware of any situation where this would happen, but it is theoretically possible -/// > according to the specifications. -/// -/// # Example -/// -/// ```no_run -/// use vulkano::instance; -/// -/// for layer in instance::layers_list().unwrap() { -/// println!("Available layer: {}", layer.name()); -/// } -/// ``` -pub fn layers_list() -> Result, LayersListError> { - layers_list_from_loader(loader::auto_loader()?) -} - -/// Same as `layers_list()`, but allows specifying a loader. -pub fn layers_list_from_loader( - ptrs: &loader::FunctionPointers, -) -> Result, LayersListError> -where - L: loader::Loader, -{ - let fns = ptrs.fns(); - - let layer_properties = unsafe { - loop { - let mut count = 0; - check_errors((fns.v1_0.enumerate_instance_layer_properties)( - &mut count, - ptr::null_mut(), - ))?; - - let mut properties = Vec::with_capacity(count as usize); - let result = check_errors({ - (fns.v1_0.enumerate_instance_layer_properties)(&mut count, properties.as_mut_ptr()) - })?; - - if !matches!(result, Success::Incomplete) { - properties.set_len(count as usize); - break properties; - } - } - }; - - Ok(layer_properties - .into_iter() - .map(|p| LayerProperties { props: p })) -} /// Properties of a layer. #[derive(Clone)] pub struct LayerProperties { - props: ash::vk::LayerProperties, + pub(crate) props: ash::vk::LayerProperties, } impl LayerProperties { @@ -95,9 +25,11 @@ impl LayerProperties { /// # Example /// /// ```no_run - /// use vulkano::instance; + /// use vulkano::VulkanLibrary; /// - /// for layer in instance::layers_list().unwrap() { + /// let library = VulkanLibrary::new().unwrap(); + /// + /// for layer in library.layer_properties().unwrap() { /// println!("Layer name: {}", layer.name()); /// } /// ``` @@ -117,9 +49,11 @@ impl LayerProperties { /// # Example /// /// ```no_run - /// use vulkano::instance; + /// use vulkano::VulkanLibrary; /// - /// for layer in instance::layers_list().unwrap() { + /// let library = VulkanLibrary::new().unwrap(); + /// + /// for layer in library.layer_properties().unwrap() { /// println!("Layer description: {}", layer.description()); /// } /// ``` @@ -137,10 +71,11 @@ impl LayerProperties { /// # Example /// /// ```no_run - /// use vulkano::instance; - /// use vulkano::instance::Version; + /// use vulkano::{Version, VulkanLibrary}; /// - /// for layer in instance::layers_list().unwrap() { + /// let library = VulkanLibrary::new().unwrap(); + /// + /// for layer in library.layer_properties().unwrap() { /// if layer.vulkan_version() >= Version::major_minor(2, 0) { /// println!("Layer {} requires Vulkan 2.0", layer.name()); /// } @@ -158,9 +93,11 @@ impl LayerProperties { /// # Example /// /// ```no_run - /// use vulkano::instance; + /// use vulkano::VulkanLibrary; /// - /// for layer in instance::layers_list().unwrap() { + /// let library = VulkanLibrary::new().unwrap(); + /// + /// for layer in library.layer_properties().unwrap() { /// println!("Layer {} - Version: {}", layer.name(), layer.implementation_version()); /// } /// ``` @@ -170,71 +107,18 @@ impl LayerProperties { } } -/// Error that can happen when loading the list of layers. -#[derive(Clone, Debug)] -pub enum LayersListError { - /// Failed to load the Vulkan shared library. - LoadingError(LoadingError), - /// Not enough memory. - OomError(OomError), -} - -impl error::Error for LayersListError { - #[inline] - fn source(&self) -> Option<&(dyn error::Error + 'static)> { - match *self { - LayersListError::LoadingError(ref err) => Some(err), - LayersListError::OomError(ref err) => Some(err), - } - } -} - -impl fmt::Display for LayersListError { - #[inline] - fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> { - write!( - fmt, - "{}", - match *self { - LayersListError::LoadingError(_) => "failed to load the Vulkan shared library", - LayersListError::OomError(_) => "not enough memory available", - } - ) - } -} - -impl From for LayersListError { - #[inline] - fn from(err: OomError) -> LayersListError { - LayersListError::OomError(err) - } -} - -impl From for LayersListError { - #[inline] - fn from(err: LoadingError) -> LayersListError { - LayersListError::LoadingError(err) - } -} - -impl From for LayersListError { - #[inline] - fn from(err: Error) -> LayersListError { - match err { - err @ Error::OutOfHostMemory => LayersListError::OomError(OomError::from(err)), - err @ Error::OutOfDeviceMemory => LayersListError::OomError(OomError::from(err)), - _ => panic!("unexpected error: {:?}", err), - } - } -} - #[cfg(test)] mod tests { - use crate::instance; + use crate::VulkanLibrary; #[test] fn layers_list() { - let mut list = match instance::layers_list() { + let library = match VulkanLibrary::new() { + Ok(x) => x, + Err(_) => return, + }; + + let mut list = match library.layer_properties() { Ok(l) => l, Err(_) => return, }; diff --git a/vulkano/src/instance/loader.rs b/vulkano/src/instance/loader.rs deleted file mode 100644 index 55b5647e..00000000 --- a/vulkano/src/instance/loader.rs +++ /dev/null @@ -1,323 +0,0 @@ -// Copyright (c) 2016 The vulkano developers -// Licensed under the Apache License, Version 2.0 -// or the MIT -// license , -// at your option. All files in the project carrying such -// notice may not be copied, modified, or distributed except -// according to those terms. - -//! Vulkan implementation loading system. -//! -//! Before vulkano can do anything, it first needs to find an implementation of Vulkan. A Vulkan -//! implementation is defined as a single `vkGetInstanceProcAddr` function, which can be accessed -//! through the `Loader` trait. -//! -//! This module provides various implementations of the `Loader` trait. -//! -//! Once you have a struct that implements `Loader`, you can create a `FunctionPointers` struct -//! from it and use this `FunctionPointers` struct to build an `Instance`. -//! -//! By default vulkano will use the `auto_loader()` function, which tries to automatically load -//! a Vulkan implementation from the system. - -use crate::check_errors; -pub use crate::fns::EntryFunctions; -use crate::OomError; -use crate::SafeDeref; -use crate::Version; -use lazy_static::lazy_static; -use shared_library; -use std::error; -use std::ffi::CStr; -use std::fmt; -use std::mem; -use std::ops::Deref; -use std::os::raw::c_char; -use std::os::raw::c_void; -use std::path::Path; - -/// Implemented on objects that grant access to a Vulkan implementation. -pub unsafe trait Loader: Send + Sync { - /// Calls the `vkGetInstanceProcAddr` function. The parameters are the same. - /// - /// The returned function must stay valid for as long as `self` is alive. - fn get_instance_proc_addr( - &self, - instance: ash::vk::Instance, - name: *const c_char, - ) -> *const c_void; -} - -unsafe impl Loader for T -where - T: SafeDeref + Send + Sync, - T::Target: Loader, -{ - #[inline] - fn get_instance_proc_addr( - &self, - instance: ash::vk::Instance, - name: *const c_char, - ) -> *const c_void { - (**self).get_instance_proc_addr(instance, name) - } -} - -impl fmt::Debug for dyn Loader { - #[inline] - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - Ok(()) - } -} - -/// Implementation of `Loader` that loads Vulkan from a dynamic library. -pub struct DynamicLibraryLoader { - vk_lib: shared_library::dynamic_library::DynamicLibrary, - get_proc_addr: - extern "system" fn(instance: ash::vk::Instance, pName: *const c_char) -> *const c_void, -} - -impl DynamicLibraryLoader { - /// Tries to load the dynamic library at the given path, and tries to - /// load `vkGetInstanceProcAddr` in it. - /// - /// # Safety - /// - /// - The dynamic library must be a valid Vulkan implementation. - /// - pub unsafe fn new

(path: P) -> Result - where - P: AsRef, - { - let vk_lib = shared_library::dynamic_library::DynamicLibrary::open(Some(path.as_ref())) - .map_err(LoadingError::LibraryLoadFailure)?; - - let get_proc_addr = { - let ptr: *mut c_void = vk_lib - .symbol("vkGetInstanceProcAddr") - .map_err(|_| LoadingError::MissingEntryPoint("vkGetInstanceProcAddr".to_owned()))?; - mem::transmute(ptr) - }; - - Ok(DynamicLibraryLoader { - vk_lib, - get_proc_addr, - }) - } -} - -unsafe impl Loader for DynamicLibraryLoader { - #[inline] - fn get_instance_proc_addr( - &self, - instance: ash::vk::Instance, - name: *const c_char, - ) -> *const c_void { - (self.get_proc_addr)(instance, name) - } -} - -/// Wraps around a loader and contains function pointers. -#[derive(Debug)] -pub struct FunctionPointers { - loader: L, - fns: EntryFunctions, -} - -impl FunctionPointers { - /// Loads some global function pointer from the loader. - pub fn new(loader: L) -> FunctionPointers - where - L: Loader, - { - let fns = EntryFunctions::load(|name| unsafe { - mem::transmute(loader.get_instance_proc_addr(ash::vk::Instance::null(), name.as_ptr())) - }); - - FunctionPointers { loader, fns } - } - - /// Returns the collection of Vulkan entry points from the Vulkan loader. - #[inline] - pub fn fns(&self) -> &EntryFunctions { - &self.fns - } - - /// Returns the highest Vulkan version that is supported for instances. - pub fn api_version(&self) -> Result - where - L: Loader, - { - // Per the Vulkan spec: - // If the vkGetInstanceProcAddr returns NULL for vkEnumerateInstanceVersion, it is a - // Vulkan 1.0 implementation. Otherwise, the application can call vkEnumerateInstanceVersion - // to determine the version of Vulkan. - unsafe { - let name = CStr::from_bytes_with_nul_unchecked(b"vkEnumerateInstanceVersion\0"); - let func = self.get_instance_proc_addr(ash::vk::Instance::null(), name.as_ptr()); - - if func.is_null() { - Ok(Version { - major: 1, - minor: 0, - patch: 0, - }) - } else { - type Pfn = extern "system" fn(pApiVersion: *mut u32) -> ash::vk::Result; - let func: Pfn = mem::transmute(func); - let mut api_version = 0; - check_errors(func(&mut api_version))?; - Ok(Version::from(api_version)) - } - } - } - - /// Calls `get_instance_proc_addr` on the underlying loader. - #[inline] - pub fn get_instance_proc_addr( - &self, - instance: ash::vk::Instance, - name: *const c_char, - ) -> *const c_void - where - L: Loader, - { - self.loader.get_instance_proc_addr(instance, name) - } -} - -/// Expression that returns a loader that assumes that Vulkan is linked to the executable you're -/// compiling. -/// -/// If you use this macro, you must linked to a library that provides the `vkGetInstanceProcAddr` -/// symbol. -/// -/// This is provided as a macro and not as a regular function, because the macro contains an -/// `extern {}` block. -// TODO: should this be unsafe? -#[macro_export] -macro_rules! statically_linked_vulkan_loader { - () => {{ - extern "C" { - fn vkGetInstanceProcAddr( - instance: ash::vk::Instance, - pName: *const c_char, - ) -> ash::vk::PFN_vkVoidFunction; - } - - struct StaticallyLinkedVulkanLoader; - unsafe impl Loader for StaticallyLinkedVulkanLoader { - fn get_instance_proc_addr( - &self, - instance: ash::vk::Instance, - name: *const c_char, - ) -> extern "system" fn() -> () { - unsafe { vkGetInstanceProcAddr(instance, name) } - } - } - - StaticallyLinkedVulkanLoader - }}; -} - -/// Returns the default `FunctionPointers` for this system. -/// -/// This function tries to auto-guess where to find the Vulkan implementation, and loads it in a -/// `lazy_static!`. The content of the lazy_static is then returned, or an error if we failed to -/// load Vulkan. -pub fn auto_loader() -> Result<&'static FunctionPointers>, LoadingError> { - #[cfg(target_os = "ios")] - #[allow(non_snake_case)] - fn def_loader_impl() -> Result, LoadingError> { - let loader = statically_linked_vulkan_loader!(); - Ok(Box::new(loader)) - } - - #[cfg(not(target_os = "ios"))] - fn def_loader_impl() -> Result, LoadingError> { - #[cfg(windows)] - fn get_path() -> &'static Path { - Path::new("vulkan-1.dll") - } - #[cfg(all(unix, not(target_os = "android"), not(target_os = "macos")))] - fn get_path() -> &'static Path { - Path::new("libvulkan.so.1") - } - #[cfg(target_os = "macos")] - fn get_path() -> &'static Path { - Path::new("libvulkan.1.dylib") - } - #[cfg(target_os = "android")] - fn get_path() -> &'static Path { - Path::new("libvulkan.so") - } - - let loader = unsafe { DynamicLibraryLoader::new(get_path())? }; - - Ok(Box::new(loader)) - } - - lazy_static! { - static ref DEFAULT_LOADER: Result>, LoadingError> = - def_loader_impl().map(FunctionPointers::new); - } - - match DEFAULT_LOADER.deref() { - &Ok(ref ptr) => Ok(ptr), - &Err(ref err) => Err(err.clone()), - } -} - -/// Error that can happen when loading the Vulkan loader. -#[derive(Debug, Clone)] -pub enum LoadingError { - /// Failed to load the Vulkan shared library. - LibraryLoadFailure(String), // TODO: meh for error type, but this needs changes in shared_library - - /// One of the entry points required to be supported by the Vulkan implementation is missing. - MissingEntryPoint(String), -} - -impl error::Error for LoadingError { - /*#[inline] - fn source(&self) -> Option<&(dyn error::Error + 'static)> { - match *self { - LoadingError::LibraryLoadFailure(ref err) => Some(err), - _ => None - } - }*/ -} - -impl fmt::Display for LoadingError { - #[inline] - fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> { - write!( - fmt, - "{}", - match *self { - LoadingError::LibraryLoadFailure(_) => "failed to load the Vulkan shared library", - LoadingError::MissingEntryPoint(_) => { - "one of the entry points required to be supported by the Vulkan implementation \ - is missing" - } - } - ) - } -} - -#[cfg(test)] -mod tests { - use crate::instance::loader::DynamicLibraryLoader; - use crate::instance::loader::LoadingError; - - #[test] - fn dl_open_error() { - unsafe { - match DynamicLibraryLoader::new("_non_existing_library.void") { - Err(LoadingError::LibraryLoadFailure(_)) => (), - _ => panic!(), - } - } - } -} diff --git a/vulkano/src/instance/mod.rs b/vulkano/src/instance/mod.rs index 67f65f7b..7ee112dd 100644 --- a/vulkano/src/instance/mod.rs +++ b/vulkano/src/instance/mod.rs @@ -9,31 +9,34 @@ //! API entry point. //! -//! The first thing to do before you start using Vulkan is to create an `Instance` object. +//! The first thing to do after loading the Vulkan library is to create an `Instance` object. //! //! For example: //! //! ```no_run -//! use vulkano::instance::Instance; -//! use vulkano::instance::InstanceExtensions; -//! use vulkano::Version; -//! -//! let instance = match Instance::new(Default::default()) { -//! Ok(i) => i, -//! Err(err) => panic!("Couldn't build instance: {:?}", err) +//! use vulkano::{ +//! instance::{Instance, InstanceExtensions}, +//! Version, VulkanLibrary, //! }; +//! +//! let library = VulkanLibrary::new() +//! .unwrap_or_else(|err| panic!("Couldn't load Vulkan library: {:?}", err)); +//! let instance = Instance::new(library, Default::default()) +//! .unwrap_or_else(|err| panic!("Couldn't create instance: {:?}", err)); //! ``` //! //! Creating an instance initializes everything and allows you to enumerate physical devices, //! ie. all the Vulkan implementations that are available on the system. //! //! ```no_run -//! # use vulkano::instance::Instance; -//! # use vulkano::instance::InstanceExtensions; -//! # use vulkano::Version; +//! # use vulkano::{ +//! # instance::{Instance, InstanceExtensions}, +//! # Version, VulkanLibrary, +//! # }; //! use vulkano::device::physical::PhysicalDevice; //! -//! # let instance = Instance::new(Default::default()).unwrap(); +//! # let library = VulkanLibrary::new().unwrap(); +//! # let instance = Instance::new(library, Default::default()).unwrap(); //! for physical_device in PhysicalDevice::enumerate(&instance) { //! println!("Available device: {}", physical_device.properties().device_name); //! } @@ -51,23 +54,16 @@ //! Once you have chosen a physical device, you can create a `Device` object from it. See the //! `device` module for more info. -use self::{ - debug::{DebugUtilsMessengerCreateInfo, UserCallback}, - loader::{FunctionPointers, Loader}, -}; -pub use self::{ - extensions::InstanceExtensions, - layers::{layers_list, LayerProperties, LayersListError}, - loader::LoadingError, -}; +use self::debug::{DebugUtilsMessengerCreateInfo, UserCallback}; +pub use self::{extensions::InstanceExtensions, layers::LayerProperties}; use crate::{ check_errors, device::physical::{init_physical_devices, PhysicalDeviceInfo}, instance::debug::{trampoline, DebugUtilsMessageSeverity, DebugUtilsMessageType}, - Error, OomError, VulkanObject, + Error, OomError, VulkanLibrary, VulkanObject, }; pub use crate::{ - extensions::{ExtensionRestriction, ExtensionRestrictionError, SupportedExtensionsError}, + extensions::{ExtensionRestriction, ExtensionRestrictionError}, fns::InstanceFunctions, version::Version, }; @@ -78,7 +74,6 @@ use std::{ fmt, hash::{Hash, Hasher}, mem::MaybeUninit, - ops::Deref, panic::{RefUnwindSafe, UnwindSafe}, ptr, sync::Arc, @@ -87,7 +82,6 @@ use std::{ pub mod debug; pub(crate) mod extensions; mod layers; -pub mod loader; /// An instance of a Vulkan context. This is the main object that should be created by an /// application before everything else. @@ -103,10 +97,16 @@ pub mod loader; /// ```no_run /// # #[macro_use] extern crate vulkano; /// # fn main() { -/// use vulkano::instance::{Instance, InstanceCreateInfo, InstanceExtensions}; -/// use vulkano::Version; +/// use vulkano::{ +/// instance::{Instance, InstanceCreateInfo, InstanceExtensions}, +/// Version, VulkanLibrary, +/// }; /// -/// let _instance = Instance::new(InstanceCreateInfo::application_from_cargo_toml()).unwrap(); +/// let library = VulkanLibrary::new().unwrap(); +/// let _instance = Instance::new( +/// library, +/// InstanceCreateInfo::application_from_cargo_toml(), +/// ).unwrap(); /// # } /// ``` /// @@ -117,7 +117,7 @@ pub mod loader; /// to use when used on a particular instance or device. It is possible for the instance and the /// device to support different versions. The supported version for an instance can be queried /// before creation with -/// [`FunctionPointers::api_version`](crate::instance::loader::FunctionPointers::api_version), +/// [`VulkanLibrary::api_version`](crate::VulkanLibrary::api_version), /// while for a device it can be retrieved with /// [`PhysicalDevice::api_version`](crate::device::physical::PhysicalDevice::api_version). /// @@ -157,8 +157,13 @@ pub mod loader; /// succeed on anything else than an Android-running device. /// /// ```no_run -/// use vulkano::instance::{Instance, InstanceCreateInfo, InstanceExtensions}; -/// use vulkano::Version; +/// use vulkano::{ +/// instance::{Instance, InstanceCreateInfo, InstanceExtensions}, +/// Version, VulkanLibrary, +/// }; +/// +/// let library = VulkanLibrary::new() +/// .unwrap_or_else(|err| panic!("Couldn't load Vulkan library: {:?}", err)); /// /// let extensions = InstanceExtensions { /// khr_surface: true, @@ -166,20 +171,22 @@ pub mod loader; /// .. InstanceExtensions::none() /// }; /// -/// let instance = match Instance::new(InstanceCreateInfo { -/// enabled_extensions: extensions, -/// ..Default::default() -/// }) { -/// Ok(i) => i, -/// Err(err) => panic!("Couldn't build instance: {:?}", err) -/// }; +/// let instance = Instance::new( +/// library, +/// InstanceCreateInfo { +/// enabled_extensions: extensions, +/// ..Default::default() +/// }, +/// ) +/// .unwrap_or_else(|err| panic!("Couldn't create instance: {:?}", err)); /// ``` /// /// # Layers /// /// When creating an `Instance`, you have the possibility to pass a list of **layers** that will /// be activated on the newly-created instance. The list of available layers can be retrieved by -/// calling [the `layers_list` function](crate::instance::layers_list). +/// calling the [`layer_properties`](crate::VulkanLibrary::layer_properties) method of +/// `VulkanLibrary`. /// /// A layer is a component that will hook and potentially modify the Vulkan function calls. /// For example, activating a layer could add a frames-per-second counter on the screen, or it @@ -200,24 +207,27 @@ pub mod loader; /// ## Example /// /// ``` -/// # use std::sync::Arc; -/// # use std::error::Error; -/// # use vulkano::instance; -/// # use vulkano::instance::Instance; -/// # use vulkano::instance::InstanceCreateInfo; -/// # use vulkano::instance::InstanceExtensions; -/// # use vulkano::Version; +/// # use std::{sync::Arc, error::Error}; +/// # use vulkano::{ +/// # instance::{Instance, InstanceCreateInfo, InstanceExtensions}, +/// # Version, VulkanLibrary, +/// # }; /// # fn test() -> Result, Box> { +/// let library = VulkanLibrary::new()?; +/// /// // For the sake of the example, we activate all the layers that /// // contain the word "foo" in their description. -/// let layers: Vec<_> = instance::layers_list()? +/// let layers: Vec<_> = library.layer_properties()? /// .filter(|l| l.description().contains("foo")) /// .collect(); /// -/// let instance = Instance::new(InstanceCreateInfo { -/// enabled_layers: layers.iter().map(|l| l.name().to_owned()).collect(), -/// ..Default::default() -/// })?; +/// let instance = Instance::new( +/// library, +/// InstanceCreateInfo { +/// enabled_layers: layers.iter().map(|l| l.name().to_owned()).collect(), +/// ..Default::default() +/// }, +/// )?; /// # Ok(instance) /// # } /// ``` @@ -230,7 +240,7 @@ pub struct Instance { api_version: Version, enabled_extensions: InstanceExtensions, enabled_layers: Vec, - function_pointers: OwnedOrRef>>, + library: Arc, max_api_version: Version, user_callbacks: Vec>, } @@ -247,8 +257,11 @@ impl Instance { /// - Panics if any version numbers in `create_info` contain a field too large to be converted /// into a Vulkan version number. /// - Panics if `create_info.max_api_version` is not at least `V1_0`. - pub fn new(create_info: InstanceCreateInfo) -> Result, InstanceCreationError> { - unsafe { Self::with_debug_utils_messengers(create_info, []) } + pub fn new( + library: Arc, + create_info: InstanceCreateInfo, + ) -> Result, InstanceCreationError> { + unsafe { Self::with_debug_utils_messengers(library, create_info, []) } } /// Creates a new `Instance` with debug messengers to use during the creation and destruction @@ -271,6 +284,7 @@ impl Instance { /// - The `user_callback` of each element of `debug_utils_messengers` must not make any calls /// to the Vulkan API. pub unsafe fn with_debug_utils_messengers( + library: Arc, create_info: InstanceCreateInfo, debug_utils_messengers: impl IntoIterator, ) -> Result, InstanceCreationError> { @@ -281,20 +295,13 @@ impl Instance { enabled_layers, engine_name, engine_version, - function_pointers, max_api_version, enumerate_portability, _ne: _, } = create_info; - let function_pointers = if let Some(function_pointers) = function_pointers { - OwnedOrRef::Owned(function_pointers) - } else { - OwnedOrRef::Ref(loader::auto_loader()?) - }; - let (api_version, max_api_version) = { - let api_version = function_pointers.api_version()?; + let api_version = library.api_version(); let max_api_version = if let Some(max_api_version) = max_api_version { max_api_version } else if api_version < Version::V1_1 { @@ -308,8 +315,7 @@ impl Instance { // VUID-VkApplicationInfo-apiVersion-04010 assert!(max_api_version >= Version::V1_0); - let supported_extensions = - InstanceExtensions::supported_by_core_with_loader(&function_pointers)?; + let supported_extensions = library.supported_extensions(); let mut flags = ash::vk::InstanceCreateFlags::empty(); if enumerate_portability && supported_extensions.khr_portability_enumeration { @@ -422,7 +428,7 @@ impl Instance { // Creating the Vulkan instance. let handle = { let mut output = MaybeUninit::uninit(); - let fns = function_pointers.fns(); + let fns = library.fns(); check_errors((fns.v1_0.create_instance)( &create_info, ptr::null(), @@ -433,9 +439,7 @@ impl Instance { // Loading the function pointers of the newly-created instance. let fns = { - InstanceFunctions::load(|name| { - function_pointers.get_instance_proc_addr(handle, name.as_ptr()) - }) + InstanceFunctions::load(|name| library.get_instance_proc_addr(handle, name.as_ptr())) }; let mut instance = Instance { @@ -446,7 +450,7 @@ impl Instance { api_version, enabled_extensions, enabled_layers, - function_pointers, + library, max_api_version, user_callbacks, }; @@ -457,10 +461,16 @@ impl Instance { Ok(Arc::new(instance)) } + /// Returns the Vulkan library used to create this instance. + #[inline] + pub fn library(&self) -> &Arc { + &self.library + } + /// Returns the Vulkan version supported by the instance. /// /// This is the lower of the - /// [driver's supported version](crate::instance::loader::FunctionPointers::api_version) and + /// [driver's supported version](crate::VulkanLibrary::api_version) and /// [`max_api_version`](Instance::max_api_version). #[inline] pub fn api_version(&self) -> Version { @@ -473,7 +483,7 @@ impl Instance { self.max_api_version } - /// Grants access to the Vulkan functions of the instance. + /// Returns pointers to the raw Vulkan functions of the instance. #[inline] pub fn fns(&self) -> &InstanceFunctions { &self.fns @@ -537,7 +547,7 @@ impl fmt::Debug for Instance { api_version, enabled_extensions, enabled_layers, - function_pointers, + library: function_pointers, max_api_version, user_callbacks: _, } = self; @@ -587,12 +597,6 @@ pub struct InstanceCreateInfo { /// The default value is zero. pub engine_version: Version, - /// Function pointers loaded from a custom loader. - /// - /// You can use this if you want to load the Vulkan API explicitly, rather than using Vulkano's - /// default. - pub function_pointers: Option>>, - /// The highest Vulkan API version that the application will use with the instance. /// /// Usually, you will want to leave this at the default. @@ -629,7 +633,6 @@ impl Default for InstanceCreateInfo { enabled_layers: Vec::new(), engine_name: None, engine_version: Version::major_minor(0, 0), - function_pointers: None, max_api_version: None, enumerate_portability: false, _ne: crate::NonExhaustive(()), @@ -662,20 +665,24 @@ impl InstanceCreateInfo { /// Error that can happen when creating an instance. #[derive(Clone, Debug)] pub enum InstanceCreationError { - /// Failed to load the Vulkan shared library. - LoadingError(LoadingError), /// Not enough memory. OomError(OomError), + /// Failed to initialize for an implementation-specific reason. InitializationFailed, + /// One of the requested layers is missing. LayerNotPresent, + /// One of the requested extensions is not supported by the implementation. ExtensionNotPresent, + /// The version requested is not supported by the implementation. IncompatibleDriver, + /// A restriction for an extension was not met. ExtensionRestrictionNotMet(ExtensionRestrictionError), + ExtensionNotEnabled { extension: &'static str, reason: &'static str, @@ -686,7 +693,6 @@ impl error::Error for InstanceCreationError { #[inline] fn source(&self) -> Option<&(dyn error::Error + 'static)> { match *self { - Self::LoadingError(ref err) => Some(err), Self::OomError(ref err) => Some(err), _ => None, } @@ -697,9 +703,6 @@ impl fmt::Display for InstanceCreationError { #[inline] fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> { match *self { - Self::LoadingError(_) => { - write!(fmt, "failed to load the Vulkan shared library") - } Self::OomError(_) => write!(fmt, "not enough memory available"), Self::InitializationFailed => write!(fmt, "initialization failed"), Self::LayerNotPresent => write!(fmt, "layer not present"), @@ -722,13 +725,6 @@ impl From for InstanceCreationError { } } -impl From for InstanceCreationError { - #[inline] - fn from(err: LoadingError) -> Self { - Self::LoadingError(err) - } -} - impl From for InstanceCreationError { #[inline] fn from(err: ExtensionRestrictionError) -> Self { @@ -751,24 +747,6 @@ impl From for InstanceCreationError { } } -// Same as Cow but less annoying. -#[derive(Debug)] -enum OwnedOrRef { - Owned(T), - Ref(&'static T), -} - -impl Deref for OwnedOrRef { - type Target = T; - #[inline] - fn deref(&self) -> &T { - match *self { - OwnedOrRef::Owned(ref v) => v, - OwnedOrRef::Ref(v) => v, - } - } -} - #[cfg(test)] mod tests { use crate::device::physical::PhysicalDevice; diff --git a/vulkano/src/lib.rs b/vulkano/src/lib.rs index 8af0050a..3f53d597 100644 --- a/vulkano/src/lib.rs +++ b/vulkano/src/lib.rs @@ -12,11 +12,14 @@ //! //! # Brief summary of Vulkan //! -//! - The [`Instance`](crate::instance::Instance) object is the API entry point. It is the -//! first object you must create before starting to use Vulkan. +//! - The [`VulkanLibrary`](crate::VulkanLibrary) represents a Vulkan library on the system. +//! It must be loaded before you can do anything with Vulkan. //! -//! - The [`PhysicalDevice`](crate::device::physical::PhysicalDevice) object represents an -//! implementation of Vulkan available on the system (eg. a graphics card, a software +//! - The [`Instance`](crate::instance::Instance) object is the API entry point, and represents +//! an initialised Vulkan library. This is the first Vulkan object that you create. +//! +//! - The [`PhysicalDevice`](crate::device::physical::PhysicalDevice) object represents a +//! Vulkan-capable device that is available on the system (eg. a graphics card, a software //! implementation, etc.). Physical devices can be enumerated from an instance with //! [`PhysicalDevice::enumerate`](crate::device::physical::PhysicalDevice::enumerate). //! @@ -30,28 +33,28 @@ //! usually used to store information about vertices, lights, etc. or arbitrary data, while //! images are used to store textures or multi-dimensional data. //! -//! - In order to show something on the screen, you need a [`Swapchain`](crate::swapchain). +//! - In order to show something on the screen, you need a +//! [`Surface` and a `Swapchain`](crate::swapchain). //! A `Swapchain` contains special `Image`s that correspond to the content of the window or the //! monitor. When you *present* a swapchain, the content of one of these special images is shown //! on the screen. //! -//! - In order to ask the GPU to do something, you must create a +//! - For graphical operations, [`RenderPass`es and `Framebuffer`s](crate::render_pass) +//! describe which images the device must draw upon. +//! +//! - In order to be able to perform operations on the device, you need to have created a +//! [pipeline object](crate::pipeline) that describes the operation you want. These objects are usually +//! created during your program's initialization. `Shader`s are programs that the GPU will +//! execute as part of a pipeline. [*Descriptor sets*](crate::descriptor_set) can be used to access +//! the content of buffers or images from within shaders. +//! +//! - To tell the GPU to do something, you must create a //! [*command buffer*](crate::command_buffer). A command buffer contains a list of commands //! that the GPU must perform. This can include copies between buffers and images, compute //! operations, or graphics operations. For the work to start, the command buffer must then be //! submitted to a [`Queue`](crate::device::Queue), which is obtained when you create the //! `Device`. //! -//! - In order to be able to add a compute operation or a graphics operation to a command buffer, -//! you need to have created a [`ComputePipeline` or a `GraphicsPipeline` -//! object](crate::pipeline) that describes the operation you want. These objects are usually -//! created during your program's initialization. `Shader`s are programs that the GPU will -//! execute as part of a pipeline. [*Descriptor sets*](crate::descriptor_set) can be used to access -//! the content of buffers or images from within shaders. -//! -//! - For graphical operations, [`RenderPass`es and `Framebuffer`s](crate::render_pass) -//! describe on which images the implementation must draw upon. -//! //! - Once you have built a *command buffer* that contains a list of commands, submitting it to the //! GPU will return an object that implements [the `GpuFuture` trait](crate::sync::GpuFuture). //! `GpuFuture`s allow you to chain multiple submissions together and are essential to performing @@ -64,6 +67,7 @@ pub use ash::vk::Handle; pub use half; +pub use library::VulkanLibrary; use std::{ error, fmt, ops::Deref, @@ -86,6 +90,7 @@ pub mod render_pass; mod fns; pub mod image; pub mod instance; +pub mod library; pub mod memory; pub mod pipeline; pub mod query; diff --git a/vulkano/src/library.rs b/vulkano/src/library.rs new file mode 100644 index 00000000..4617c149 --- /dev/null +++ b/vulkano/src/library.rs @@ -0,0 +1,417 @@ +// Copyright (c) 2016 The vulkano developers +// Licensed under the Apache License, Version 2.0 +// or the MIT +// license , +// at your option. All files in the project carrying such +// notice may not be copied, modified, or distributed except +// according to those terms. + +//! Vulkan library loading system. +//! +//! Before Vulkano can do anything, it first needs to find a library containing an implementation +//! of Vulkan. A Vulkan implementation is defined as a single `vkGetInstanceProcAddr` function, +//! which can be accessed through the `Loader` trait. +//! +//! This module provides various implementations of the `Loader` trait. +//! +//! Once you have a type that implements `Loader`, you can create a `VulkanLibrary` +//! from it and use this `VulkanLibrary` struct to build an `Instance`. + +pub use crate::fns::EntryFunctions; +use crate::{ + check_errors, + instance::{InstanceExtensions, LayerProperties}, + Error, OomError, SafeDeref, Success, Version, +}; +use shared_library; +use std::{ + error, + ffi::{c_void, CStr}, + fmt, + mem::transmute, + os::raw::c_char, + path::Path, + ptr, + sync::Arc, +}; + +/// A loaded library containing a valid Vulkan implementation. +#[derive(Debug)] +pub struct VulkanLibrary { + loader: Box, + fns: EntryFunctions, + + api_version: Version, + supported_extensions: InstanceExtensions, +} + +impl VulkanLibrary { + /// Loads the default Vulkan library for this system. + pub fn new() -> Result, LoadingError> { + #[cfg(target_os = "ios")] + #[allow(non_snake_case)] + fn def_loader_impl() -> Result, LoadingError> { + let loader = statically_linked_vulkan_loader!(); + Ok(Box::new(loader)) + } + + #[cfg(not(target_os = "ios"))] + fn def_loader_impl() -> Result, LoadingError> { + #[cfg(windows)] + fn get_path() -> &'static Path { + Path::new("vulkan-1.dll") + } + #[cfg(all(unix, not(target_os = "android"), not(target_os = "macos")))] + fn get_path() -> &'static Path { + Path::new("libvulkan.so.1") + } + #[cfg(target_os = "macos")] + fn get_path() -> &'static Path { + Path::new("libvulkan.1.dylib") + } + #[cfg(target_os = "android")] + fn get_path() -> &'static Path { + Path::new("libvulkan.so") + } + + let loader = unsafe { DynamicLibraryLoader::new(get_path())? }; + + Ok(Box::new(loader)) + } + + def_loader_impl().and_then(VulkanLibrary::with_loader) + } + + /// Loads a custom Vulkan library. + pub fn with_loader(loader: L) -> Result, LoadingError> + where + L: Loader + 'static, + { + let fns = EntryFunctions::load(|name| unsafe { + transmute(loader.get_instance_proc_addr(ash::vk::Instance::null(), name.as_ptr())) + }); + + // Per the Vulkan spec: + // If the vkGetInstanceProcAddr returns NULL for vkEnumerateInstanceVersion, it is a + // Vulkan 1.0 implementation. Otherwise, the application can call vkEnumerateInstanceVersion + // to determine the version of Vulkan. + let api_version = unsafe { + let name = CStr::from_bytes_with_nul_unchecked(b"vkEnumerateInstanceVersion\0"); + let func = loader.get_instance_proc_addr(ash::vk::Instance::null(), name.as_ptr()); + + if func.is_null() { + Version { + major: 1, + minor: 0, + patch: 0, + } + } else { + type Pfn = extern "system" fn(pApiVersion: *mut u32) -> ash::vk::Result; + let func: Pfn = transmute(func); + let mut api_version = 0; + check_errors(func(&mut api_version))?; + Version::from(api_version) + } + }; + + let supported_extensions = unsafe { + let extension_properties = loop { + let mut count = 0; + check_errors((fns.v1_0.enumerate_instance_extension_properties)( + ptr::null(), + &mut count, + ptr::null_mut(), + ))?; + + let mut properties = Vec::with_capacity(count as usize); + let result = check_errors((fns.v1_0.enumerate_instance_extension_properties)( + ptr::null(), + &mut count, + properties.as_mut_ptr(), + ))?; + + if !matches!(result, Success::Incomplete) { + properties.set_len(count as usize); + break properties; + } + }; + + InstanceExtensions::from( + extension_properties + .iter() + .map(|property| CStr::from_ptr(property.extension_name.as_ptr())), + ) + }; + + Ok(Arc::new(VulkanLibrary { + loader: Box::new(loader), + fns, + api_version, + supported_extensions, + })) + } + + /// Returns pointers to the raw global Vulkan functions of the library. + #[inline] + pub fn fns(&self) -> &EntryFunctions { + &self.fns + } + + /// Returns the highest Vulkan version that is supported for instances. + pub fn api_version(&self) -> Version { + self.api_version + } + + /// Returns the extensions that are supported by this Vulkan library. + #[inline] + pub fn supported_extensions(&self) -> &InstanceExtensions { + &self.supported_extensions + } + + /// Returns the list of layers that are available when creating an instance. + /// + /// On success, this function returns an iterator that produces + /// [`LayerProperties`](crate::instance::LayerProperties) objects. In order to enable a layer, + /// you need to pass its name (returned by `LayerProperties::name()`) when creating the + /// [`Instance`](crate::instance::Instance). + /// + /// > **Note**: The available layers may change between successive calls to this function, so + /// > each call may return different results. It is possible that one of the layers enumerated + /// > here is no longer available when you create the `Instance`. This will lead to an error + /// > when calling `Instance::new`. + /// + /// # Example + /// + /// ```no_run + /// use vulkano::VulkanLibrary; + /// + /// let library = VulkanLibrary::new().unwrap(); + /// + /// for layer in library.layer_properties().unwrap() { + /// println!("Available layer: {}", layer.name()); + /// } + /// ``` + pub fn layer_properties( + &self, + ) -> Result, OomError> { + let fns = self.fns(); + + let layer_properties = unsafe { + loop { + let mut count = 0; + check_errors((fns.v1_0.enumerate_instance_layer_properties)( + &mut count, + ptr::null_mut(), + ))?; + + let mut properties = Vec::with_capacity(count as usize); + let result = check_errors({ + (fns.v1_0.enumerate_instance_layer_properties)( + &mut count, + properties.as_mut_ptr(), + ) + })?; + + if !matches!(result, Success::Incomplete) { + properties.set_len(count as usize); + break properties; + } + } + }; + + Ok(layer_properties + .into_iter() + .map(|p| LayerProperties { props: p })) + } + + /// Calls `get_instance_proc_addr` on the underlying loader. + #[inline] + pub fn get_instance_proc_addr( + &self, + instance: ash::vk::Instance, + name: *const c_char, + ) -> *const c_void { + self.loader.get_instance_proc_addr(instance, name) + } +} + +/// Implemented on objects that grant access to a Vulkan implementation. +pub unsafe trait Loader: Send + Sync { + /// Calls the `vkGetInstanceProcAddr` function. The parameters are the same. + /// + /// The returned function must stay valid for as long as `self` is alive. + fn get_instance_proc_addr( + &self, + instance: ash::vk::Instance, + name: *const c_char, + ) -> *const c_void; +} + +unsafe impl Loader for T +where + T: SafeDeref + Send + Sync, + T::Target: Loader, +{ + #[inline] + fn get_instance_proc_addr( + &self, + instance: ash::vk::Instance, + name: *const c_char, + ) -> *const c_void { + (**self).get_instance_proc_addr(instance, name) + } +} + +impl fmt::Debug for dyn Loader { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + Ok(()) + } +} + +/// Implementation of `Loader` that loads Vulkan from a dynamic library. +pub struct DynamicLibraryLoader { + vk_lib: shared_library::dynamic_library::DynamicLibrary, + get_proc_addr: + extern "system" fn(instance: ash::vk::Instance, pName: *const c_char) -> *const c_void, +} + +impl DynamicLibraryLoader { + /// Tries to load the dynamic library at the given path, and tries to + /// load `vkGetInstanceProcAddr` in it. + /// + /// # Safety + /// + /// - The dynamic library must be a valid Vulkan implementation. + /// + pub unsafe fn new

(path: P) -> Result + where + P: AsRef, + { + let vk_lib = shared_library::dynamic_library::DynamicLibrary::open(Some(path.as_ref())) + .map_err(LoadingError::LibraryLoadFailure)?; + + let get_proc_addr = { + let ptr: *mut c_void = vk_lib + .symbol("vkGetInstanceProcAddr") + .map_err(|_| LoadingError::MissingEntryPoint("vkGetInstanceProcAddr".to_owned()))?; + transmute(ptr) + }; + + Ok(DynamicLibraryLoader { + vk_lib, + get_proc_addr, + }) + } +} + +unsafe impl Loader for DynamicLibraryLoader { + #[inline] + fn get_instance_proc_addr( + &self, + instance: ash::vk::Instance, + name: *const c_char, + ) -> *const c_void { + (self.get_proc_addr)(instance, name) + } +} + +/// Expression that returns a loader that assumes that Vulkan is linked to the executable you're +/// compiling. +/// +/// If you use this macro, you must linked to a library that provides the `vkGetInstanceProcAddr` +/// symbol. +/// +/// This is provided as a macro and not as a regular function, because the macro contains an +/// `extern {}` block. +// TODO: should this be unsafe? +#[macro_export] +macro_rules! statically_linked_vulkan_loader { + () => {{ + extern "C" { + fn vkGetInstanceProcAddr( + instance: ash::vk::Instance, + pName: *const c_char, + ) -> ash::vk::PFN_vkVoidFunction; + } + + struct StaticallyLinkedVulkanLoader; + unsafe impl Loader for StaticallyLinkedVulkanLoader { + fn get_instance_proc_addr( + &self, + instance: ash::vk::Instance, + name: *const c_char, + ) -> extern "system" fn() -> () { + unsafe { vkGetInstanceProcAddr(instance, name) } + } + } + + StaticallyLinkedVulkanLoader + }}; +} + +/// Error that can happen when loading a Vulkan library. +#[derive(Debug, Clone)] +pub enum LoadingError { + /// Failed to load the Vulkan shared library. + LibraryLoadFailure(String), // TODO: meh for error type, but this needs changes in shared_library + + /// One of the entry points required to be supported by the Vulkan implementation is missing. + MissingEntryPoint(String), + + /// Not enough memory. + OomError(OomError), +} + +impl error::Error for LoadingError { + #[inline] + fn source(&self) -> Option<&(dyn error::Error + 'static)> { + match *self { + //Self::LibraryLoadFailure(ref err) => Some(err), + Self::OomError(ref err) => Some(err), + _ => None, + } + } +} + +impl fmt::Display for LoadingError { + #[inline] + fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> { + write!( + fmt, + "{}", + match *self { + Self::LibraryLoadFailure(_) => "failed to load the Vulkan shared library", + Self::MissingEntryPoint(_) => "one of the entry points required to be supported by the Vulkan implementation is missing", + Self::OomError(_) => "not enough memory available", + } + ) + } +} + +impl From for LoadingError { + #[inline] + fn from(err: Error) -> Self { + match err { + err @ Error::OutOfHostMemory => Self::OomError(OomError::from(err)), + err @ Error::OutOfDeviceMemory => Self::OomError(OomError::from(err)), + _ => panic!("unexpected error: {:?}", err), + } + } +} + +#[cfg(test)] +mod tests { + use super::{DynamicLibraryLoader, LoadingError}; + + #[test] + fn dl_open_error() { + unsafe { + match DynamicLibraryLoader::new("_non_existing_library.void") { + Err(LoadingError::LibraryLoadFailure(_)) => (), + _ => panic!(), + } + } + } +} diff --git a/vulkano/src/swapchain/mod.rs b/vulkano/src/swapchain/mod.rs index 9eab939f..14265feb 100644 --- a/vulkano/src/swapchain/mod.rs +++ b/vulkano/src/swapchain/mod.rs @@ -55,24 +55,30 @@ //! //! ```no_run //! use std::ptr; -//! use vulkano::instance::{Instance, InstanceCreateInfo, InstanceExtensions}; -//! use vulkano::swapchain::Surface; -//! use vulkano::Version; +//! use vulkano::{ +//! instance::{Instance, InstanceCreateInfo, InstanceExtensions}, +//! swapchain::Surface, +//! Version, VulkanLibrary, +//! }; //! //! let instance = { +//! let library = VulkanLibrary::new() +//! .unwrap_or_else(|err| panic!("Couldn't load Vulkan library: {:?}", err)); +//! //! let extensions = InstanceExtensions { //! khr_surface: true, //! khr_win32_surface: true, // If you don't enable this, `from_hwnd` will fail. //! .. InstanceExtensions::none() //! }; //! -//! match Instance::new(InstanceCreateInfo { -//! enabled_extensions: extensions, -//! ..Default::default() -//! }) { -//! Ok(i) => i, -//! Err(err) => panic!("Couldn't build instance: {:?}", err) -//! } +//! Instance::new( +//! library, +//! InstanceCreateInfo { +//! enabled_extensions: extensions, +//! ..Default::default() +//! }, +//! ) +//! .unwrap_or_else(|err| panic!("Couldn't create instance: {:?}", err)) //! }; //! //! # use std::sync::Arc; diff --git a/vulkano/src/sync/semaphore.rs b/vulkano/src/sync/semaphore.rs index 0014baef..b8749a2c 100644 --- a/vulkano/src/sync/semaphore.rs +++ b/vulkano/src/sync/semaphore.rs @@ -524,11 +524,14 @@ impl From for SemaphoreExportError { #[cfg(test)] mod tests { - use crate::device::physical::PhysicalDevice; - use crate::device::{Device, DeviceCreateInfo, DeviceExtensions, QueueCreateInfo}; - use crate::instance::{Instance, InstanceCreateInfo, InstanceExtensions}; - use crate::sync::{ExternalSemaphoreHandleTypes, Semaphore, SemaphoreCreateInfo}; - use crate::VulkanObject; + use crate::{ + device::{ + physical::PhysicalDevice, Device, DeviceCreateInfo, DeviceExtensions, QueueCreateInfo, + }, + instance::{Instance, InstanceCreateInfo, InstanceExtensions}, + sync::{ExternalSemaphoreHandleTypes, Semaphore, SemaphoreCreateInfo}, + VulkanLibrary, VulkanObject, + }; #[test] fn semaphore_create() { @@ -555,14 +558,22 @@ mod tests { #[test] fn semaphore_export() { - let instance = match Instance::new(InstanceCreateInfo { - enabled_extensions: InstanceExtensions { - khr_get_physical_device_properties2: true, - khr_external_semaphore_capabilities: true, - ..InstanceExtensions::none() + let library = match VulkanLibrary::new() { + Ok(x) => x, + Err(_) => return, + }; + + let instance = match Instance::new( + library, + InstanceCreateInfo { + enabled_extensions: InstanceExtensions { + khr_get_physical_device_properties2: true, + khr_external_semaphore_capabilities: true, + ..InstanceExtensions::none() + }, + ..Default::default() }, - ..Default::default() - }) { + ) { Ok(x) => x, Err(_) => return, }; diff --git a/vulkano/src/tests.rs b/vulkano/src/tests.rs index ae3ef770..ff947c83 100644 --- a/vulkano/src/tests.rs +++ b/vulkano/src/tests.rs @@ -12,10 +12,15 @@ /// Creates an instance or returns if initialization fails. macro_rules! instance { () => {{ - use crate::instance::Instance; + use crate::{instance::Instance, VulkanLibrary}; - match Instance::new(Default::default()) { - Ok(i) => i, + let library = match VulkanLibrary::new() { + Ok(x) => x, + Err(_) => return, + }; + + match Instance::new(library, Default::default()) { + Ok(x) => x, Err(_) => return, } }};