Browse Source

Vk: start writing some actual docs.

Because I put this on hold for two months and almost forgot what design
guidelines I wanted to follow and how the heck is the whole thing used.
pull/234/head
Vladimír Vondruš 6 years ago
parent
commit
a62e2b8f09
  1. 1
      doc/features.dox
  2. 203
      doc/snippets/MagnumVk.cpp
  3. 102
      doc/vulkan-wrapping.dox
  4. 3
      src/Magnum/Vk/CommandBuffer.h
  5. 18
      src/Magnum/Vk/CommandPool.h
  6. 109
      src/Magnum/Vk/Device.h
  7. 15
      src/Magnum/Vk/DeviceProperties.h
  8. 8
      src/Magnum/Vk/ExtensionProperties.h
  9. 145
      src/Magnum/Vk/Instance.h
  10. 4
      src/Magnum/Vk/LayerProperties.h

1
doc/features.dox

@ -39,6 +39,7 @@ necessary to read through everything, pick only what you need.
- @subpage plugins --- @copybrief plugins - @subpage plugins --- @copybrief plugins
- @subpage file-formats --- @copybrief file-formats - @subpage file-formats --- @copybrief file-formats
- @subpage opengl-wrapping --- @copybrief opengl-wrapping - @subpage opengl-wrapping --- @copybrief opengl-wrapping
- @subpage vulkan-wrapping --- @copybrief vulkan-wrapping
- @subpage shaders --- @copybrief shaders - @subpage shaders --- @copybrief shaders
- @subpage scenegraph --- @copybrief scenegraph - @subpage scenegraph --- @copybrief scenegraph
- @subpage debug-tools --- @copybrief debug-tools - @subpage debug-tools --- @copybrief debug-tools

203
doc/snippets/MagnumVk.cpp

@ -27,10 +27,16 @@
#include "Magnum/Magnum.h" #include "Magnum/Magnum.h"
#include "Magnum/Math/Color.h" #include "Magnum/Math/Color.h"
#include "Magnum/Vk/CommandBuffer.h"
#include "Magnum/Vk/CommandPool.h"
#include "Magnum/Vk/Device.h" #include "Magnum/Vk/Device.h"
#include "Magnum/Vk/DeviceProperties.h"
#include "Magnum/Vk/Extensions.h" #include "Magnum/Vk/Extensions.h"
#include "Magnum/Vk/ExtensionProperties.h"
#include "Magnum/Vk/Instance.h" #include "Magnum/Vk/Instance.h"
#include "Magnum/Vk/Integration.h" #include "Magnum/Vk/Integration.h"
#include "Magnum/Vk/LayerProperties.h"
#include "Magnum/Vk/Queue.h"
#include "MagnumExternal/Vulkan/flextVkGlobal.h" #include "MagnumExternal/Vulkan/flextVkGlobal.h"
using namespace Magnum; using namespace Magnum;
@ -38,65 +44,215 @@ using namespace Magnum;
#define DOXYGEN_IGNORE(...) __VA_ARGS__ #define DOXYGEN_IGNORE(...) __VA_ARGS__
int main() { int main() {
{ {
Vk::Device device{NoCreate}; /* [wrapping-extending-create-info] */
/* [Device-isExtensionEnabled] */ Vk::InstanceCreateInfo info{DOXYGEN_IGNORE()};
if(device.isExtensionEnabled<Vk::Extensions::EXT::index_type_uint8>()) {
// keep mesh indices 8bit /* Add a custom validation features setup */
} else { VkValidationFeaturesEXT validationFeatures{};
// convert them to 16bit validationFeatures.sType = VK_STRUCTURE_TYPE_VALIDATION_FEATURES_EXT;
validationFeatures.enabledValidationFeatureCount = 1;
constexpr auto bestPractices = VK_VALIDATION_FEATURE_ENABLE_BEST_PRACTICES_EXT;
validationFeatures.pEnabledValidationFeatures = &bestPractices;
CORRADE_INTERNAL_ASSERT(!info->pNext); // or find the end of the pNext chain
info->pNext = &validationFeatures;
/* [wrapping-extending-create-info] */
} }
/* [Device-isExtensionEnabled] */
{
Vk::Instance instance;
/* [CommandPool-usage] */
Vk::DeviceProperties props = DOXYGEN_IGNORE(pickDevice(instance));
Vk::Device device{DOXYGEN_IGNORE(NoCreate)};
Vk::CommandPool graphicsCommandPool{device, Vk::CommandPoolCreateInfo{
props.pickQueueFamily(Vk::QueueFlag::Graphics)
}};
/* [CommandPool-usage] */
/* [CommandPool-usage-allocate] */
Vk::CommandBuffer commandBuffer = graphicsCommandPool.allocate();
// fill the buffer, submit …
/* [CommandPool-usage-allocate] */
}
{
Vk::Instance instance;
/* [Device-usage-pick] */
Vk::DeviceProperties props = Vk::pickDevice(instance);
/* [Device-usage-pick] */
/* [Device-usage-construct-queue] */
Vk::Queue queue{NoCreate};
Vk::Device device{instance, Vk::DeviceCreateInfo{props}
.addQueues(props.pickQueueFamily(Vk::QueueFlag::Graphics), {0.0f}, {queue})
};
/* [Device-usage-construct-queue] */
} }
{ {
Vk::Instance instance;
Vk::DeviceProperties props{NoCreate};
using namespace Containers::Literals;
/* [Device-usage-extensions] */
Vk::Device device{instance, Vk::DeviceCreateInfo{props}
DOXYGEN_IGNORE()
.addEnabledExtensions< // predefined extensions
Vk::Extensions::EXT::index_type_uint8,
Vk::Extensions::KHR::device_group>()
.addEnabledExtensions({"VK_NV_mesh_shader"_s}) // can be plain strings too
};
/* [Device-usage-extensions] */
}
{
Vk::Instance instance;
Vk::DeviceProperties props{NoCreate};
using namespace Containers::Literals;
/* [Device-usage-check-supported] */
Vk::ExtensionProperties extensions = props.enumerateExtensionProperties();
Vk::DeviceCreateInfo info{props};
if(extensions.isSupported<Vk::Extensions::EXT::index_type_uint8>())
info.addEnabledExtensions<Vk::Extensions::EXT::index_type_uint8>();
if(extensions.isSupported("VK_NV_mesh_shader"_s))
info.addEnabledExtensions({"VK_NV_mesh_shader"_s});
DOXYGEN_IGNORE()
/* [Device-usage-check-supported] */
}
{
Vk::Instance instance;
VkQueryPool pool{};
/* [Device-function-pointers] */
Vk::Device device{DOXYGEN_IGNORE(instance, Vk::DeviceCreateInfo{Vk::pickDevice(instance)})};
// ...
device->ResetQueryPoolEXT(device, DOXYGEN_IGNORE(pool, 0, 0));
/* [Device-function-pointers] */
}
{
VkQueryPool pool{};
/* Header included again inside a function, but it's fine as the guards will /* Header included again inside a function, but it's fine as the guards will
make it empty */ make it empty */
/* [Device-global-function-pointers] */ /* [Device-global-function-pointers] */
#include <MagnumExternal/Vulkan/flextVkGlobal.h> #include <MagnumExternal/Vulkan/flextVkGlobal.h>
// … DOXYGEN_IGNORE()
Vk::Device device{DOXYGEN_IGNORE(NoCreate)}; Vk::Device device{DOXYGEN_IGNORE(NoCreate)};
device.populateGlobalFunctionPointers(); device.populateGlobalFunctionPointers();
VkCommandPool commandPool; DOXYGEN_IGNORE()
VkCommandPoolCreateInfo info{}; vkResetQueryPoolEXT(device, DOXYGEN_IGNORE(pool, 0, 0));
// …
vkCreateCommandPool(device, &info, nullptr, &commandPool);
/* [Device-global-function-pointers] */ /* [Device-global-function-pointers] */
} }
{ {
Vk::Instance instance; Vk::Device device{NoCreate};
/* [Instance-isExtensionEnabled] */ /* [Device-isExtensionEnabled] */
if(instance.isExtensionEnabled<Vk::Extensions::EXT::debug_utils>()) { if(device.isExtensionEnabled<Vk::Extensions::EXT::index_type_uint8>()) {
// use the fancy debugging APIs // keep mesh indices 8bit
} else if(instance.isExtensionEnabled<Vk::Extensions::EXT::debug_report>()) {
// use the non-fancy and deprecated debugging APIs
} else { } else {
// well, tough luck // convert them to 16bit
} }
/* [Instance-isExtensionEnabled] */ /* [Device-isExtensionEnabled] */
} }
{ {
int argc{};
const char** argv{};
/* [Instance-usage] */
using namespace Containers::Literals;
Vk::Instance instance{Vk::InstanceCreateInfo{argc, argv}
.setApplicationInfo("My Vulkan Application"_s, Vk::version(1, 2, 3))
};
/* [Instance-usage] */
}
{
int argc{};
const char** argv{};
using namespace Containers::Literals;
/* [Instance-usage-layers-extensions] */
Vk::Instance instance{Vk::InstanceCreateInfo{argc, argv}
DOXYGEN_IGNORE()
.addEnabledLayers({"VK_LAYER_KHRONOS_validation"_s})
.addEnabledExtensions< // predefined extensions
Vk::Extensions::EXT::debug_report,
Vk::Extensions::KHR::external_fence_capabilities>()
.addEnabledExtensions({"VK_KHR_xcb_surface"_s}) // can be plain strings too
};
/* [Instance-usage-layers-extensions] */
}
{
int argc{};
const char** argv{};
using namespace Containers::Literals;
/* [Instance-usage-check-supported] */
/* Query layer and extension support */
Vk::LayerProperties layers = Vk::enumerateLayerProperties();
Vk::InstanceExtensionProperties extensions =
/* ... including extensions exposed only by the extra layers */
Vk::enumerateInstanceExtensionProperties(layers.names());
/* Enable only those that are supported */
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<Vk::Extensions::EXT::debug_report>())
info.addEnabledExtensions<Vk::Extensions::EXT::debug_report>();
DOXYGEN_IGNORE()
Vk::Instance instance{info};
/* [Instance-usage-check-supported] */
}
{
/* [Instance-function-pointers] */
Vk::Instance instance{DOXYGEN_IGNORE()};
VkPhysicalDeviceGroupPropertiesKHR properties[10];
UnsignedInt count = Containers::arraySize(properties);
instance->EnumeratePhysicalDeviceGroupsKHR(instance, &count, properties);
/* [Instance-function-pointers] */
}
{
Vk::Instance instance;
/* Header included again inside a function, but it's fine as the guards will /* Header included again inside a function, but it's fine as the guards will
make it empty */ make it empty */
/* [Instance-global-function-pointers] */ /* [Instance-global-function-pointers] */
#include <MagnumExternal/Vulkan/flextVkGlobal.h> #include <MagnumExternal/Vulkan/flextVkGlobal.h>
// … DOXYGEN_IGNORE()
Vk::Instance instance;
instance.populateGlobalFunctionPointers(); instance.populateGlobalFunctionPointers();
VkPhysicalDeviceGroupProperties properties[10]; VkPhysicalDeviceGroupPropertiesKHR properties[10];
UnsignedInt count = Containers::arraySize(properties); UnsignedInt count = Containers::arraySize(properties);
vkEnumeratePhysicalDeviceGroupsKHR(instance, &count, properties); vkEnumeratePhysicalDeviceGroupsKHR(instance, &count, properties);
/* [Instance-global-function-pointers] */ /* [Instance-global-function-pointers] */
} }
{
Vk::Instance instance;
/* [Instance-isExtensionEnabled] */
if(instance.isExtensionEnabled<Vk::Extensions::EXT::debug_utils>()) {
// use the fancy debugging APIs
} else if(instance.isExtensionEnabled<Vk::Extensions::EXT::debug_report>()) {
// use the non-fancy and deprecated debugging APIs
} else {
// well, tough luck
}
/* [Instance-isExtensionEnabled] */
}
{ {
/* [Integration] */ /* [Integration] */
VkOffset2D a{64, 32}; VkOffset2D a{64, 32};
@ -108,4 +264,5 @@ VkClearColorValue c = VkClearColorValue(0xff9391_srgbf);
static_cast<void>(b); static_cast<void>(b);
static_cast<void>(c); static_cast<void>(c);
} }
} }

102
doc/vulkan-wrapping.dox

@ -0,0 +1,102 @@
/*
This file is part of Magnum.
Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019,
2020 Vladimír Vondruš <mosra@centrum.cz>
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/
namespace Magnum {
/** @page vulkan-wrapping Vulkan wrapping layer
@brief Overview of the base Vulkan wrapper API
@tableofcontents
@m_footernavigation
The @ref Magnum::Vk library is a thin but high-level abstraction of the
[Vulkan](https://www.khronos.org/vulkan/) GPU API, providing sane defaults with
ability to opt-in for greater control and performance.
@section vulkan-wrapping-instance-device Instance and device wrappers
Compared to OpenGL, which has a concept of "current context", Vulkan doesn't
have any implicit globals. The @ref Vk library follows that, with each object
carrying a reference to a corresponding instance or device along. This was
chosen as a reasonable tradeoff between requiring an explicit instance/device
parameter in each API (which would be too error-prone and annoying to use) and
having an implicit thread-local instance/device (which would repeat the
well-known pain points of OpenGL).
Vulkan API entrypoints aren't global either because each instance and device
can have a different set of enabled layers and extensions, and thus different
instance- and device-local function pointers. While the Vulkan specification
allows device-level functions to be queried on an instance and thus use the
same function pointers on a variety of devices, such workflow implies
additional dispatch overhead, and thus isn't recommended. Magnum instead
stores instance- and device-level function pointers locally in each
@ref Vk::Instance and @ref Vk::Device to avoid this overhead --- these are then
accessible through @ref Vk::Instance::operator->() "operator->()" on both:
@snippet MagnumVk.cpp Instance-function-pointers
For convenience and for easier interaction with 3rd party code, such pointers
can be made global by calling @ref Vk::Instance::populateGlobalFunctionPointers()
and @ref Vk::Device::populateGlobalFunctionPointers(), after which you can use
the `vk*` functions as usual. However, all implications coming from these being
tied to a particular instance/device still apply:
@snippet MagnumVk.cpp Instance-global-function-pointers
@section vulkan-wrapping-create-info CreateInfo structure wrappers
In most cases, a`Vk::*CreateInfo` instance has all required fields set to valid
values upon construction, with everything else optional. One exception to this
rule is for example @ref Vk::DeviceCreateInfo, where the user is expected to
call @ref Vk::DeviceCreateInfo::addQueues() "addQueues()".
@section vulkan-wrapping-raw Common interfaces for interaction with raw Vulkan code
Each wrapped Vulkan object has a @ref Vk::Instance::handle() "handle()" getter,
giving back the underlying Vulkan handle such as @type_vk{Instance}. In
addition it's also implicitly convertible to that handle type, which means you
can pass it as-is to raw Vulkan APIs. You can also use
@ref Vk::Instance::release() "release()" to release its ownership and continue
to use it as a regular handle. Conversely, any Vulkan handle can be wrapped
into a first-class Magnum object using a corresponding
@ref Vk::Instance::wrap() "wrap()" function.
Similarly, all @ref Vk::InstanceCreateInfo "Vk::*CreateInfo" wrapper classes
are convertible to a `Vk*CreateInfo` pointer in order to be easily passable
directly to Vulkan APIs. You can create them from an existing
`Vk*CreateInfo` instances as well, and use
@ref Vk::InstanceCreateInfo::operator->() "operator->()" to access the wrapped
structure to supply additional parameters not exposed by Magnum. However take
care to not clash with values and pointers already set:
@snippet MagnumVk.cpp wrapping-extending-create-info
To completely mitigate the overhead from instantiating wrapper `*CreateInfo`
classes, each of them can also be constructed using the @ref NoInit tag, which
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.
*/
}

3
src/Magnum/Vk/CommandBuffer.h

@ -71,7 +71,8 @@ CORRADE_ENUMSET_OPERATORS(CommandBufferResetFlags)
@brief Command buffer @brief Command buffer
@m_since_latest @m_since_latest
Wraps a @type_vk_keyword{CommandBuffer}. Wraps a @type_vk_keyword{CommandBuffer}. A command buffer instance is usually
allocated from a @ref CommandPool, see its documentation for usage information.
*/ */
class MAGNUM_VK_EXPORT CommandBuffer { class MAGNUM_VK_EXPORT CommandBuffer {
public: public:

18
src/Magnum/Vk/CommandPool.h

@ -177,7 +177,23 @@ CORRADE_ENUMSET_OPERATORS(CommandPoolResetFlags)
@brief Command pool @brief Command pool
@m_since_latest @m_since_latest
Wraps a @type_vk_keyword{CommandPool}. Wraps a @type_vk_keyword{CommandPool} and handles allocation of
@ref CommandBuffer "CommandBuffer"s.
@section Vk-CommandPool-usage Usage
A @ref CommandPoolCreateInfo doesn't need many inputs --- the only required is
queue family index coming from @ref DeviceProperties of the device it's created
on:
@snippet MagnumVk.cpp CommandPool-usage
After that, you can allocate command buffers as follows. The command buffers
are freed at the end of their instance lifetime, you can also put all allocated
buffers back to initial state by calling @ref reset(), or alternatively reset
each buffer separately using @ref CommandBuffer::reset().
@snippet MagnumVk.cpp CommandPool-usage-allocate
*/ */
class MAGNUM_VK_EXPORT CommandPool { class MAGNUM_VK_EXPORT CommandPool {
public: public:

109
src/Magnum/Vk/Device.h

@ -53,8 +53,8 @@ namespace Implementation {
@brief Device creation info @brief Device creation info
@m_since_latest @m_since_latest
Wraps a @type_vk_keyword{DeviceCreateInfo}. Wraps a @type_vk_keyword{DeviceCreateInfo}. See @ref Device for usage
@see @ref Device information.
*/ */
class MAGNUM_VK_EXPORT DeviceCreateInfo { class MAGNUM_VK_EXPORT DeviceCreateInfo {
public: public:
@ -213,8 +213,99 @@ CORRADE_ENUMSET_OPERATORS(DeviceCreateInfo::Flags)
@brief Device @brief Device
@m_since_latest @m_since_latest
Wraps a @type_vk_keyword{Device} and stores all device-specific function Wraps a @type_vk_keyword{Device} and stores device-specific Vulkan function
pointers. pointers.
@section Vk-Device-usage Usage
With an @ref Instance ready, a device has to be picked first. Commonly it's
done by calling @ref pickDevice() and letting the library choose. This
selection is affected by the `--magnum-device`
@ref Vk-Device-command-line "command-line option", giving the end users an
ability to pick a particular device, choose a discrete or integrated GPU or
even a software implementation. If the application needs something specific,
you can use @ref enumerateDevices() instead, pick a device from the list
manually, provide the users with a list to choose from etc.
@snippet MagnumVk.cpp Device-usage-pick
After a device is picked, a @ref Device can be created using
@ref DeviceCreateInfo. At the very least you'll need to set up queues, as every
Vulkan device needs at least one. That's done by creating an empty @ref Queue
instance and then referencing it from @ref DeviceCreateInfo::addQueues(). After
the device is constructed, the queue gets populated and is ready to be used.
@snippet MagnumVk.cpp Device-usage-construct-queue
In the above snippet, we requested a graphics queue --- the
@ref DeviceProperties instance we made earlier acts as knowledge base for a
particular device, providing info about available queues, extensions, features,
memory heaps and implementation limits --- and we used a convenience API to
pick the first available graphics queue. As with device picking, you can
also iterate through all @ref DeviceProperties::queueFamilyCount() and choose
one manually.
Same as with @ref Instance, the above won't enable any additional extensions
except for what the engine itself needs or what's supplied on the command line. Use @ref DeviceCreateInfo::addEnabledExtensions() to enable them, you can use
both string names as well as predefined *device* extensions from the
@ref Extensions namespace. Later on, presence of predefined extensions can be
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:
@snippet MagnumVk.cpp Device-usage-check-supported
With both @ref Instance and @ref Device created, you can proceed to setting up
a @ref CommandPool.
@section Vk-Device-command-line Command-line options
The @ref Device inherits a subset of the
@ref Vk-Instance-command-line "Instance command-line options", in particular
the following. If the @ref Instance didn't get `argc` / `argv` passed, only the
environment variables are used.
- `--magnum-disable-extensions LIST` --- Vulkan instance or device extensions
to disable, meaning @ref DeviceCreateInfo::addEnabledExtensions() will skip
them (environment: `MAGNUM_DISABLE_EXTENSIONS`)
- `--magnum-enable-extensions LIST` --- Vulkan device extensions to enable in
addition to @ref DeviceCreateInfo defaults and what the application
requests (environment: `MAGNUM_ENABLE_EXTENSIONS`)
- `--magnum-vulkan-version X.Y` --- force @ref Device Vulkan version instead
of using what the device reports as supported, affecting what entrypoints
and extensions get used (environment: `MAGNUM_VULKAN_VERSION`)
- `--magnum-log default|quiet|verbose` --- console logging (environment:
`MAGNUM_LOG`) (default: `default`)
- `--magnum-device ID|integrated|discrete|virtual|cpu` --- device ID or kind
to pick in @ref pickDevice(); if a device is selected through
@ref enumerateDevices() or any other way, this option has no effect
(environment: `MAGNUM_DEVICE`)
@section Vk-Device-raw Interaction with raw Vulkan code
In addition to the common properties explained in @ref vulkan-wrapping-raw,
the @ref Device contains device-level Vulkan function pointers, accessible
through @ref operator->():
@snippet MagnumVk.cpp Device-function-pointers
These functions are by default not accessible globally (and neither there is a
global "current instance"), which is done in order to avoid multiple
independent instances affecting each other. Sometimes it is however desirable
to have global function pointers --- for example when a 3rd party code needs to
operate on the same instance, or when writing quick prototype code --- and then
it's possible to populate those using @ref populateGlobalFunctionPointers().
Compared to the above, the same custom code would then look like this:
@snippet MagnumVk.cpp Device-global-function-pointers
Similarly you can use @ref Instance::populateGlobalFunctionPointers() to
populate instance-level global function pointers.
*/ */
class MAGNUM_VK_EXPORT Device { class MAGNUM_VK_EXPORT Device {
public: public:
@ -235,6 +326,11 @@ class MAGNUM_VK_EXPORT Device {
* things. If @p enabledExtensions is empty, the device will behave as * things. If @p enabledExtensions is empty, the device will behave as
* if no extensions were enabled. * if no extensions were enabled.
* *
* Note that this function retrieves all device-specific Vulkan
* function pointers, which is a relatively costly operation. It's thus
* not recommended to call this function repeatedly for creating
* short-lived device instances, even though it's technically correct.
*
* Unlike a device created using a constructor, the Vulkan device is by * Unlike a device created using a constructor, the Vulkan device is by
* default not deleted on destruction, use @p flags for different * default not deleted on destruction, use @p flags for different
* behavior. * behavior.
@ -352,12 +448,9 @@ class MAGNUM_VK_EXPORT Device {
* @brief Populate global device-level function pointers to be used with third-party code * @brief Populate global device-level function pointers to be used with third-party code
* *
* Populates device-level global function pointers so third-party * Populates device-level global function pointers so third-party
* code is able to call global device-level `vk*` functions: * code is able to call global device-level `vk*` functions. See
* * @ref Vk-Device-raw for more information.
* @snippet MagnumVk.cpp Device-global-function-pointers
* *
* Use @ref Instance::populateGlobalFunctionPointers() to populate
* instance-level global function pointers.
* @attention This operation is changing global state. You need to * @attention This operation is changing global state. You need to
* ensure that this function is not called simultaenously from * ensure that this function is not called simultaenously from
* multiple threads and code using those function points is * multiple threads and code using those function points is

15
src/Magnum/Vk/DeviceProperties.h

@ -135,7 +135,11 @@ MAGNUM_VK_EXPORT Debug& operator<<(Debug& debug, QueueFlags value);
Wraps a @type_vk_keyword{PhysicalDevice} along with its (lazy-populated) Wraps a @type_vk_keyword{PhysicalDevice} along with its (lazy-populated)
properties such as @type_vk_keyword{PhysicalDeviceProperties2} and properties such as @type_vk_keyword{PhysicalDeviceProperties2} and
@type_vk_keyword{GetPhysicalDeviceQueueFamilyProperties2}. @type_vk_keyword{GetPhysicalDeviceQueueFamilyProperties2}.
@see @ref enumerateDevices()
See the @ref Vk-Device-usage "Device class docs" for an example of using this
class for enumerating available devices and picking one of them.
@see @ref pickDevice(), @ref enumerateDevices()
*/ */
class MAGNUM_VK_EXPORT DeviceProperties { class MAGNUM_VK_EXPORT DeviceProperties {
public: public:
@ -339,6 +343,9 @@ class MAGNUM_VK_EXPORT DeviceProperties {
@brief Enumerate physical devices @brief Enumerate physical devices
@m_since_latest @m_since_latest
Returns a list of all devices present on the system. See @ref pickDevice() for
an alternative that pick just a single appropriate device. See @ref Device for
general usage information.
@see @fn_vk_keyword{EnumeratePhysicalDevices} @see @fn_vk_keyword{EnumeratePhysicalDevices}
*/ */
MAGNUM_VK_EXPORT Containers::Array<DeviceProperties> enumerateDevices(Instance& instance); MAGNUM_VK_EXPORT Containers::Array<DeviceProperties> enumerateDevices(Instance& instance);
@ -348,9 +355,9 @@ MAGNUM_VK_EXPORT Containers::Array<DeviceProperties> enumerateDevices(Instance&
@m_since_latest @m_since_latest
Calls @ref enumerateDevices() and selects a device based on preferences Calls @ref enumerateDevices() and selects a device based on preferences
specified through command-line parameters or the environment. If a device is specified through the `--magnum-device` @ref Vk-Instance-command-line "command-line option".
not found, exits. See @ref tryPickDevice() for an alternative that doesn't exit If a device is not found, exits. See @ref tryPickDevice() for an alternative
on failure. that doesn't exit on failure. See @ref Device for general usage information.
*/ */
MAGNUM_VK_EXPORT DeviceProperties pickDevice(Instance& instance); MAGNUM_VK_EXPORT DeviceProperties pickDevice(Instance& instance);

8
src/Magnum/Vk/ExtensionProperties.h

@ -47,7 +47,13 @@ namespace Magnum { namespace Vk {
Provides a searchable container of Vulkan device extensions enumerated with Provides a searchable container of Vulkan device extensions enumerated with
@ref DeviceProperties::enumerateExtensionProperties(). @ref DeviceProperties::enumerateExtensionProperties().
@see @ref InstanceExtensionProperties, @type_vk_keyword{ExtensionProperties}
See the @ref Vk-Device-usage "Device class docs" for an example of using this
class for checking available extensions before enabling them on a device. See
@ref Vk-Instance-usage "Instance class docs" for the same but using
@ref InstanceExtensionProperties.
@see @type_vk_keyword{ExtensionProperties}
*/ */
class MAGNUM_VK_EXPORT ExtensionProperties { class MAGNUM_VK_EXPORT ExtensionProperties {
public: public:

145
src/Magnum/Vk/Instance.h

@ -52,8 +52,7 @@ namespace Implementation {
@m_since_latest @m_since_latest
Wraps a @type_vk_keyword{InstanceCreateInfo} and Wraps a @type_vk_keyword{InstanceCreateInfo} and
@type_vk_keyword{ApplicationInfo}. @type_vk_keyword{ApplicationInfo}. See @ref Instance for usage information.
@see @ref Instance
*/ */
class MAGNUM_VK_EXPORT InstanceCreateInfo { class MAGNUM_VK_EXPORT InstanceCreateInfo {
public: public:
@ -156,6 +155,10 @@ class MAGNUM_VK_EXPORT InstanceCreateInfo {
* *
* Use the @ref version() helper to create the @p version value. The * Use the @ref version() helper to create the @p version value. The
* name is @cpp nullptr @ce by default. * name is @cpp nullptr @ce by default.
*
* The function makes copies of string views that are not owning or
* null-terminated, use the @link Containers::Literals::operator""_s() @endlink
* literal to prevent that where possible.
*/ */
InstanceCreateInfo& setApplicationInfo(Containers::StringView name, Version version); InstanceCreateInfo& setApplicationInfo(Containers::StringView name, Version version);
@ -164,7 +167,10 @@ class MAGNUM_VK_EXPORT InstanceCreateInfo {
* @return Reference to self (for method chaining) * @return Reference to self (for method chaining)
* *
* All listed layers are expected be supported, use * All listed layers are expected be supported, use
* @ref LayerProperties::isSupported() to check for their presence. * @ref LayerProperties::isSupported() to check for their presence. If
* a particular layer is listed among `--magnum-disable-layers` in
* @ref Vk-Instance-command-line "command-line options", it's not
* added.
* *
* The function makes copies of string views that are not owning or * The function makes copies of string views that are not owning or
* null-terminated, use the @link Containers::Literals::operator""_s() @endlink * null-terminated, use the @link Containers::Literals::operator""_s() @endlink
@ -181,7 +187,10 @@ class MAGNUM_VK_EXPORT InstanceCreateInfo {
* All listed extensions are expected to be supported either globally * All listed extensions are expected to be supported either globally
* or in at least one of the enabled layers, use * or in at least one of the enabled layers, use
* @ref InstanceExtensionProperties::isSupported() to check for their * @ref InstanceExtensionProperties::isSupported() to check for their
* presence. * presence. If a particular extension is listed among
* `--magnum-disable-extensions` in
* @ref Vk-Instance-command-line "command-line options", it's not
* added.
* *
* The function makes copies of string views that are not owning or * The function makes copies of string views that are not owning or
* null-terminated, use the @link Containers::Literals::operator""_s() @endlink * null-terminated, use the @link Containers::Literals::operator""_s() @endlink
@ -228,7 +237,121 @@ CORRADE_ENUMSET_OPERATORS(InstanceCreateInfo::Flags)
Wraps a @type_vk_keyword{Instance} and stores instance-specific Vulkan function Wraps a @type_vk_keyword{Instance} and stores instance-specific Vulkan function
pointers. pointers.
@see @ref vulkan-wrapping
@section Vk-Instance-usage Usage
While an @ref Instance can be default-constructed without much fuss, it's
recommended to pass a @ref InstanceCreateInfo with at least the `argc` / `argv`
pair, which allows you to use various `--magnum-*`
@ref Vk-Instance-command-line "command-line options" listed below. Setting
application info may be beneficial for the driver, but it's not required
either.
@snippet MagnumVk.cpp Instance-usage
<b></b>
@m_class{m-note m-success}
@par
The above code uses the @link Containers::Literals::operator""_s() @endlink
literal, which lets the library know that given string is global and
null-terminated. Such strings then don't need to be copied internally to
keep them in scope until they're consumed by Vulkan APIs. The same is
recommended to do for extension and layer names where possible.
The above won't enable any additional layers or extensions except for what the
engine itself needs or what's supplied on the command line. Use
@ref InstanceCreateInfo::addEnabledLayers() and
@ref InstanceCreateInfo::addEnabledExtensions() to enable them, you can use
both string names as well as predefined *instance* extensions from the
@ref Extensions namespace. Later on, presence of predefined extensions can be
checked with @ref isExtensionEnabled().
@snippet MagnumVk.cpp Instance-usage-layers-extensions
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:
@snippet MagnumVk.cpp Instance-usage-check-supported
Next step after creating a Vulkan instance is picking and creating a
@ref Device.
@section Vk-Instance-command-line Command-line options
The @ref Instance is configurable through command-line options that are passed
through the @ref InstanceCreateInfo `argc` / `argv` parameters. If those are
not passed, only the environment variables are used. A subset of these options
is reused by a subsequently created @ref Device as well.
@code{.sh}
<application> [--magnum-help]
[--magnum-disable-layers LIST]
[--magnum-disable-extensions LIST]
[--magnum-enable-layers LIST]
[--magnum-enable-instance-extensions LIST]
[--magnum-enable-extensions LIST]
[--magnum-vulkan-version X.Y]
[--magnum-log default|quiet|verbose]
[--magnum-device ID|integrated|discrete|virtual|cpu] ...
@endcode
Arguments:
- `...` --- main application arguments (see `-h` or `--help` for details)
- `--magnum-help` --- display this help message and exit
- `--magnum-disable-layers LIST` --- Vulkan layers to disable, meaning
@ref InstanceCreateInfo::addEnabledLayers() will skip them (environment:
`MAGNUM_DISABLE_LAYERS`)
- `--magnum-disable-extensions LIST` --- Vulkan instance or device extensions
to disable, meaning @ref InstanceCreateInfo::addEnabledExtensions() and
@ref DeviceCreateInfo::addEnabledExtensions() will skip them (environment:
`MAGNUM_DISABLE_EXTENSIONS`)
- `--magnum-enable-layers LIST` --- Vulkan layers to enable in addition to
@ref InstanceCreateInfo defaults and what the application requests
(environment: `MAGNUM_ENABLE_LAYERS`)
- `--magnum-enable-instance-extensions LIST` --- Vulkan instance extensions
to enable in addition to @ref InstanceCreateInfo defaults and what the
application requests (environment: `MAGNUM_ENABLE_INSTANCE_EXTENSIONS`)
- `--magnum-enable-extensions LIST` --- Vulkan device extensions to enable in
addition to @ref DeviceCreateInfo defaults and what the application
requests (environment: `MAGNUM_ENABLE_EXTENSIONS`)
- `--magnum-vulkan-version X.Y` --- force @ref Instance and @ref Device
Vulkan version instead of using what the instance / device reports as
supported, affecting what entrypoints and extensions get used (environment:
`MAGNUM_VULKAN_VERSION`)
- `--magnum-log default|quiet|verbose` --- console logging (environment:
`MAGNUM_LOG`) (default: `default`)
- `--magnum-device ID|integrated|discrete|virtual|cpu` --- device ID or kind
to pick in @ref pickDevice(); if a device is selected through
@ref enumerateDevices() or any other way, this option has no effect
(environment: `MAGNUM_DEVICE`)
@section Vk-Instance-raw Interaction with raw Vulkan code
In addition to the common properties explained in @ref vulkan-wrapping-raw, the
@ref Instance contains instance-level Vulkan function pointers, accessible
through @ref operator->():
@snippet MagnumVk.cpp Instance-function-pointers
These functions are by default not accessible globally (and neither there is a
global "current instance"), which is done in order to avoid multiple
independent instances affecting each other. Sometimes it is however desirable
to have global function pointers --- for example when a 3rd party code needs to
operate on the same instance, or when writing quick prototype code --- and then
it's possible to populate those using @ref populateGlobalFunctionPointers().
Compared to the above, the same custom code would then look like this:
@snippet MagnumVk.cpp Instance-global-function-pointers
Similarly you can use @ref Device::populateGlobalFunctionPointers() to populate
device-level global function pointers.
*/ */
class MAGNUM_VK_EXPORT Instance { class MAGNUM_VK_EXPORT Instance {
public: public:
@ -248,6 +371,11 @@ class MAGNUM_VK_EXPORT Instance {
* things. If @p enabledExtensions empty, the instance will behave as * things. If @p enabledExtensions empty, the instance will behave as
* if no extensions were enabled. * if no extensions were enabled.
* *
* Note that this function retrieves all instance-specific Vulkan
* function pointers, which is a relatively costly operation. It's thus
* not recommended to call this function repeatedly for creating
* short-lived instances, even though it's technically correct.
*
* Unlike an instance created using a constructor, the Vulkan instance * Unlike an instance created using a constructor, the Vulkan instance
* is by default not deleted on destruction, use @p flags for different * is by default not deleted on destruction, use @p flags for different
* behavior. * behavior.
@ -360,12 +488,9 @@ class MAGNUM_VK_EXPORT Instance {
* @brief Populate global instance-level function pointers to be used with third-party code * @brief Populate global instance-level function pointers to be used with third-party code
* *
* Populates instance-level global function pointers so third-party * Populates instance-level global function pointers so third-party
* code is able to call global instance-level `vk*` functions: * code is able to call global instance-level `vk*` functions. See
* * @ref Vk-Instance-raw for more information.
* @snippet MagnumVk.cpp Instance-global-function-pointers
* *
* Use @ref Device::populateGlobalFunctionPointers() to populate
* device-level global function pointers.
* @attention This operation is changing global state. You need to * @attention This operation is changing global state. You need to
* ensure that this function is not called simultaenously from * ensure that this function is not called simultaenously from
* multiple threads and code using those function points is * multiple threads and code using those function points is

4
src/Magnum/Vk/LayerProperties.h

@ -50,6 +50,10 @@ layers are [deprecated since Vulkan 1.0.13](https://github.com/KhronosGroup/Vulk
and the assumption is that no drivers currently use rely on these anymore. See and the assumption is that no drivers currently use rely on these anymore. See
[§ 37.3.1](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/html/chap38.html#extendingvulkan-layers-devicelayerdeprecation) [§ 37.3.1](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/html/chap38.html#extendingvulkan-layers-devicelayerdeprecation)
for more information. for more information.
See the @ref Vk-Instance-usage "Instance class docs" for an example of using
this class for checking available layers before enabling them on an instance.
@see @ref ExtensionProperties, @ref enumerateInstanceExtensionProperties(), @see @ref ExtensionProperties, @ref enumerateInstanceExtensionProperties(),
@type_vk_keyword{LayerProperties} @type_vk_keyword{LayerProperties}
*/ */

Loading…
Cancel
Save