diff --git a/doc/snippets/MagnumVk.cpp b/doc/snippets/MagnumVk.cpp index a40746b40..5ee24d059 100644 --- a/doc/snippets/MagnumVk.cpp +++ b/doc/snippets/MagnumVk.cpp @@ -63,6 +63,58 @@ info->pNext = &validationFeatures; /* [wrapping-extending-create-info] */ } +{ +using namespace Containers::Literals; +int argc{}; +char** argv{}; +/* [wrapping-optimizing-properties-instance] */ +Vk::LayerProperties layers = DOXYGEN_IGNORE(Vk::enumerateLayerProperties()); +Vk::InstanceExtensionProperties extensions = DOXYGEN_IGNORE(Vk::enumerateInstanceExtensionProperties(layers.names())); + +/* Pass the layer and extension properties for use by InstanceCreateInfo */ +Vk::InstanceCreateInfo info{argc, argv, &layers, &extensions}; +if(layers.isSupported("VK_LAYER_KHRONOS_validation"_s)) + info.addEnabledLayers({"VK_LAYER_KHRONOS_validation"_s}); +if(extensions.isSupported()) + info.addEnabledExtensions(); +DOXYGEN_IGNORE() + +Vk::Instance instance{info}; +/* [wrapping-optimizing-properties-instance] */ +} + +{ +Vk::Instance instance{NoCreate}; +Vk::Queue queue{NoCreate}; +/* [wrapping-optimizing-properties-device-single-expression] */ +Vk::Device device{instance, Vk::DeviceCreateInfo{Vk::pickDevice(instance)} + .addQueues(DOXYGEN_IGNORE(Vk::QueueFlag::Graphics, {0.0f}, {queue})) + DOXYGEN_IGNORE() +}; +/* [wrapping-optimizing-properties-device-single-expression] */ +} + +{ +using namespace Containers::Literals; +Vk::Instance instance{NoCreate}; +/* [wrapping-optimizing-properties-device-move] */ +Vk::DeviceProperties properties = Vk::pickDevice(instance); +Vk::ExtensionProperties extensions = properties.enumerateExtensionProperties(); + +/* Move the device properties to the info structure, pass extension properties + to allow reuse as well */ +Vk::DeviceCreateInfo info{std::move(properties), &extensions}; +if(extensions.isSupported()) + info.addEnabledExtensions(); +if(extensions.isSupported("VK_NV_mesh_shader"_s)) + info.addEnabledExtensions({"VK_NV_mesh_shader"_s}); +DOXYGEN_IGNORE() + +/* Finally, be sure to move the info structure to the device as well */ +Vk::Device device{instance, std::move(info)}; +/* [wrapping-optimizing-properties-device-move] */ +} + { /* [CommandPool-usage] */ Vk::Device device{DOXYGEN_IGNORE(NoCreate)}; @@ -207,7 +259,7 @@ Vk::InstanceExtensionProperties extensions = Vk::enumerateInstanceExtensionProperties(layers.names()); /* Enable only those that are supported */ -Vk::InstanceCreateInfo info{argc, argv, &layers, &extensions}; +Vk::InstanceCreateInfo info{argc, argv}; if(layers.isSupported("VK_LAYER_KHRONOS_validation"_s)) info.addEnabledLayers({"VK_LAYER_KHRONOS_validation"_s}); if(extensions.isSupported()) diff --git a/doc/vulkan-wrapping.dox b/doc/vulkan-wrapping.dox index 6649bcefa..0e77dc44e 100644 --- a/doc/vulkan-wrapping.dox +++ b/doc/vulkan-wrapping.dox @@ -98,5 +98,39 @@ will skip all initialization and leave the contents unspecified to be filled later. Note that at that point you have the full responsibility to correctly set up all members. +@section vulkan-wrapping-optimizing-properties Optimizing instance and device property retrieval + +Retrieving layer and extension info as well as device properties involves +allocations, string operations, sorting and other potentially expensive work +both on the application side and in the driver. While the +@ref Vk::LayerProperties, @ref Vk::InstanceExtensionProperties / +@ref Vk::ExtensionProperties and @ref Vk::DeviceProperties APIs are made in a +way to optimize subsequent queries as much as possible, care should be taken to +avoid constructing and initializing them more times than necessary. + +For @ref Vk::Instance creation, the @ref Vk::InstanceCreateInfo constructor is +able to take pointers to existing @ref Vk::LayerProperties and +@ref Vk::InstanceExtensionProperties instances and reuse them to query +availability of implicitly enabled layers and extensions. If they're not +passed, the class may (but also might not) create its own instances internally: + +@snippet MagnumVk.cpp wrapping-optimizing-properties-instance + +For @ref Vk::Device creation, the @ref Vk::DeviceProperties should ideally be +* *moved* all the way to the @ref Vk::Device constructor, at which point it's +made available through @ref Vk::Device::properties() to any code that needs it. +If you have @ref Vk::pickDevice(), @ref Vk::DeviceCreateInfo and +@ref Vk::Device constructor all in a single expression, the optimal operation +is done implicitly: + +@snippet MagnumVk.cpp wrapping-optimizing-properties-device-single-expression + +However, if you instantiate @ref Vk::DeviceProperties and/or +@ref Vk::DeviceCreateInfo separately, you have to @cpp std::move() @ce them to +achieve the desired effect. An existing @ref Vk::ExtensionProperties instance +can be also passed to @ref Vk::DeviceCreateInfo to allow reuse: + +@snippet MagnumVk.cpp wrapping-optimizing-properties-device-move + */ } diff --git a/src/Magnum/Vk/Device.h b/src/Magnum/Vk/Device.h index 2a8c92ffe..3dadf4562 100644 --- a/src/Magnum/Vk/Device.h +++ b/src/Magnum/Vk/Device.h @@ -317,15 +317,15 @@ checked with @ref isExtensionEnabled(). @snippet MagnumVk.cpp Device-usage-extensions Usually you'll be first checking for extension availability instead, which is -again accessible through the @ref DeviceProperties instance. Similarly to -@ref Instance, as the extension list is used internally as well, pass it in the -constructor to avoid querying them again internally: +again accessible through the @ref DeviceProperties instance: @snippet MagnumVk.cpp Device-usage-check-supported With both @ref Instance and @ref Device created, you can proceed to setting up a @ref CommandPool. +@see @ref vulkan-wrapping-optimizing-properties + @section Vk-Device-command-line Command-line options The @ref Device inherits a subset of the diff --git a/src/Magnum/Vk/Instance.h b/src/Magnum/Vk/Instance.h index 1fb0208a1..89cfc2d7c 100644 --- a/src/Magnum/Vk/Instance.h +++ b/src/Magnum/Vk/Instance.h @@ -282,15 +282,15 @@ checked with @ref isExtensionEnabled(). However, with the above approach, if any layer or extension isn't available, the instance creation will abort. The recommended workflow is thus first checking layer and extension availability using @ref enumerateLayerProperties() -and @ref enumerateInstanceExtensionProperties(). The @ref InstanceCreateInfo -class uses these properties internally as well, pass them in the constructor -to avoid querying those again internally: +and @ref enumerateInstanceExtensionProperties(): @snippet MagnumVk.cpp Instance-usage-check-supported Next step after creating a Vulkan instance is picking and creating a @ref Device. +@see @ref vulkan-wrapping-optimizing-properties + @section Vk-Instance-command-line Command-line options The @ref Instance is configurable through command-line options that are passed