Browse Source

Vk: a non-error-prone way to retrieve queues after device creation.

I wonder why this couldn't be done this way in the Vulkan API directly.
pull/234/head
Vladimír Vondruš 6 years ago
parent
commit
f75cc9330c
  1. 2
      doc/vulkan-mapping.dox
  2. 1
      src/Magnum/Vk/CMakeLists.txt
  3. 60
      src/Magnum/Vk/Device.cpp
  4. 23
      src/Magnum/Vk/Device.h
  5. 11
      src/Magnum/Vk/Implementation/DeviceState.cpp
  6. 3
      src/Magnum/Vk/Implementation/DeviceState.h
  7. 88
      src/Magnum/Vk/Queue.h
  8. 136
      src/Magnum/Vk/Test/DeviceVkTest.cpp
  9. 1
      src/Magnum/Vk/Vk.h

2
doc/vulkan-mapping.dox

@ -194,7 +194,7 @@ Vulkan function | Matching API
@fn_vk{GetDeviceGroupPeerMemoryFeatures} @m_class{m-label m-flat m-success} **KHR, 1.1** | |
@fn_vk{GetDeviceMemoryCommitment} | |
@fn_vk{GetDeviceProcAddr} | @ref Device constructor
@fn_vk{GetDeviceQueue}, \n @fn_vk{GetDeviceQueue2} @m_class{m-label m-flat m-success} **1.1** | |
@fn_vk{GetDeviceQueue}, \n @fn_vk{GetDeviceQueue2} @m_class{m-label m-flat m-success} **1.1** | @ref Device constructor
@fn_vk{GetEventStatus} | |
@fn_vk{GetFenceStatus} | |
@fn_vk{GetImageMemoryRequirements}, \n @fn_vk{GetImageMemoryRequirements2} @m_class{m-label m-flat m-success} **KHR, 1.1** | |

1
src/Magnum/Vk/CMakeLists.txt

@ -54,6 +54,7 @@ set(MagnumVk_HEADERS
Instance.h
Integration.h
LayerProperties.h
Queue.h
Result.h
TypeTraits.h
Version.h

60
src/Magnum/Vk/Device.cpp

@ -40,6 +40,7 @@
#include "Magnum/Vk/DeviceProperties.h"
#include "Magnum/Vk/Extensions.h"
#include "Magnum/Vk/ExtensionProperties.h"
#include "Magnum/Vk/Queue.h"
#include "Magnum/Vk/Result.h"
#include "Magnum/Vk/Version.h"
#include "Magnum/Vk/Implementation/Arguments.h"
@ -57,6 +58,7 @@ struct DeviceCreateInfo::State {
Containers::Array<Containers::StringView> disabledExtensions;
Containers::Array<VkDeviceQueueCreateInfo> queues;
Containers::StaticArray<32, Float> queuePriorities;
Containers::StaticArray<32, Queue*> queueOutput;
std::size_t nextQueuePriority = 0;
bool quietLog = false;
@ -182,8 +184,9 @@ DeviceCreateInfo& DeviceCreateInfo::addEnabledExtensions(const std::initializer_
return addEnabledExtensions(Containers::arrayView(extensions));
}
DeviceCreateInfo& DeviceCreateInfo::addQueues(UnsignedInt family, Containers::ArrayView<const Float> priorities) {
DeviceCreateInfo& DeviceCreateInfo::addQueues(const UnsignedInt family, const Containers::ArrayView<const Float> priorities, const Containers::ArrayView<const Containers::Reference<Queue>> output) {
CORRADE_ASSERT(!priorities.empty(), "Vk::DeviceCreateInfo::addQueues(): at least one queue priority has to be specified", *this);
CORRADE_ASSERT(output.size() == priorities.size(), "Vk::DeviceCreateInfo::addQueues(): expected" << priorities.size() << "outuput queue references but got" << output.size(), *this);
/* This can happen in case we used the NoInit or VkDeviceCreateInfo
constructor */
@ -195,19 +198,22 @@ DeviceCreateInfo& DeviceCreateInfo::addQueues(UnsignedInt family, Containers::Ar
info.queueCount = priorities.size();
info.pQueuePriorities = _state->queuePriorities + _state->nextQueuePriority;
/* Copy the passed queue priorities to an internal storage that never
reallocates. If this blows up, see the definition of queuePriorities for
details. We can't easily reallocate if this grows too big as all
pointers would need to be patched, so there's a static limit. */
/* Copy the passed queue priorities and output queue references to an
internal storage that never reallocates. If this blows up, see the
definition of queuePriorities for details. We can't easily reallocate if
this grows too big as all pointers would need to be patched, so there's
a static limit. */
CORRADE_INTERNAL_ASSERT(_state->nextQueuePriority + priorities.size() <= _state->queuePriorities.size());
Utility::copy(priorities, _state->queuePriorities.suffix(_state->nextQueuePriority).prefix(priorities.size()));
for(std::size_t i = 0; i != priorities.size(); ++i)
_state->queueOutput[_state->nextQueuePriority + i] = &*output[i];
_state->nextQueuePriority += priorities.size();
return addQueues(info);
}
DeviceCreateInfo& DeviceCreateInfo::addQueues(UnsignedInt family, std::initializer_list<Float> priorities) {
return addQueues(family, Containers::arrayView(priorities));
DeviceCreateInfo& DeviceCreateInfo::addQueues(const UnsignedInt family, const std::initializer_list<Float> priorities, const std::initializer_list<Containers::Reference<Queue>> output) {
return addQueues(family, Containers::arrayView(priorities), Containers::arrayView(output));
}
DeviceCreateInfo& DeviceCreateInfo::addQueues(const VkDeviceQueueCreateInfo& info) {
@ -266,6 +272,38 @@ Device::Device(Instance& instance, const DeviceCreateInfo& info):
initializeExtensions<const char*>({info->ppEnabledExtensionNames, info->enabledExtensionCount});
initialize(instance, version);
/* Extension-dependent state is initialized, now we can retrieve the queues
from the device and save them to the outputs specified in addQueues().
Each of those calls added one or more entries into _state->queueOutput,
maintain an offset into it. */
UnsignedInt queueOutputIndex = 0;
for(const VkDeviceQueueCreateInfo& createInfo: info._state->queues) {
/* If the info structure doesn't point into our priority array, it
means it was added with the addQueues(VkDeviceQueueCreateInfo)
overload. For that we didn't remember any output, thus skip it */
if(createInfo.pQueuePriorities < info._state->queuePriorities.begin() ||
createInfo.pQueuePriorities >= info._state->queuePriorities.end())
continue;
for(UnsignedInt i = 0; i != createInfo.queueCount; ++i) {
VkDeviceQueueInfo2 requestInfo{};
requestInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_INFO_2;
requestInfo.queueFamilyIndex = createInfo.queueFamilyIndex;
/* According to the spec we can request each family only once,
which means here we don't need to remember the per-family index
across multiple VkDeviceQueueCreateInfos, making the
implementation a bit simpler. */
requestInfo.queueIndex = i;
/* Retrieve the queue handle, create a new Queue object in desired
output location, and increment the output location for the next
queue */
VkQueue queue;
_state->getDeviceQueueImplementation(*this, requestInfo, queue);
*info._state->queueOutput[queueOutputIndex++] = Queue::wrap(*this, queue);
}
}
}
Device::Device(NoCreateT): _handle{}, _functionPointers{} {}
@ -332,4 +370,12 @@ void Device::populateGlobalFunctionPointers() {
flextVkDevice = _functionPointers;
}
void Device::getQueueImplementation11(Device& self, const VkDeviceQueueInfo2& info, VkQueue& queue) {
return self->GetDeviceQueue2(self, &info, &queue);
}
void Device::getQueueImplementationDefault(Device& self, const VkDeviceQueueInfo2& info, VkQueue& queue) {
return self->GetDeviceQueue(self, info.queueFamilyIndex, info.queueIndex, &queue);
}
}}

23
src/Magnum/Vk/Device.h

@ -32,6 +32,7 @@
#include <cstddef>
#include <Corrade/Containers/Pointer.h>
#include <Corrade/Containers/Reference.h>
#include "Magnum/Tags.h"
#include "Magnum/Math/BoolVector.h"
@ -169,18 +170,20 @@ class MAGNUM_VK_EXPORT DeviceCreateInfo {
/**
* @brief Add queues
* @param family Family index, smaller than
* @param[in] family Family index, smaller than
* @ref DeviceProperties::queueFamilyCount()
* @param priorities Queue priorities. Size of the array implies how
* many queues to add and has to be at least one.
* @param[in] priorities Queue priorities. Size of the array implies
* how many queues to add and has to be at least one.
* @param[out] output Where to save resulting queues once the
* device is created. Has to have the same sizes as @p priorities.
* @return Reference to self (for method chaining)
*
* At least one queue has to be added.
* @see @ref DeviceProperties::pickQueueFamily()
*/
DeviceCreateInfo& addQueues(UnsignedInt family, Containers::ArrayView<const Float> priorities);
DeviceCreateInfo& addQueues(UnsignedInt family, Containers::ArrayView<const Float> priorities, Containers::ArrayView<const Containers::Reference<Queue>> output);
/** @overload */
DeviceCreateInfo& addQueues(UnsignedInt family, std::initializer_list<Float> priorities);
DeviceCreateInfo& addQueues(UnsignedInt family, std::initializer_list<Float> priorities, std::initializer_list<Containers::Reference<Queue>> output);
/**
* @brief Add queues using raw info
@ -255,7 +258,10 @@ class MAGNUM_VK_EXPORT Device {
* @param instance Vulkan instance to create the device on
* @param info Device creation info
*
* @see @fn_vk_keyword{CreateDevice}
* After creating the device requests device queues added via
* @ref DeviceCreateInfo::addQueues(UnsignedInt, Containers::ArrayView<const Float>, Containers::ArrayView<const Containers::Reference<Queue>>), populating the @ref Queue references.
* @see @fn_vk_keyword{CreateDevice}, @fn_vk_keyword{GetDeviceQueue2},
* @fn_vk_keyword{GetDeviceQueue}
*/
explicit Device(Instance& instance, const DeviceCreateInfo& info);
@ -374,9 +380,14 @@ class MAGNUM_VK_EXPORT Device {
Implementation::DeviceState& state() { return *_state; }
private:
friend Implementation::DeviceState;
template<class T> MAGNUM_VK_LOCAL void initializeExtensions(Containers::ArrayView<const T> enabledExtensions);
MAGNUM_VK_LOCAL void initialize(Instance& instance, Version version);
MAGNUM_VK_LOCAL static void getQueueImplementationDefault(Device& self, const VkDeviceQueueInfo2& info, VkQueue& queue);
MAGNUM_VK_LOCAL static void getQueueImplementation11(Device& self, const VkDeviceQueueInfo2& info, VkQueue& queue);
VkDevice _handle;
HandleFlags _flags;
Version _version;

11
src/Magnum/Vk/Implementation/DeviceState.cpp

@ -25,8 +25,17 @@
#include "DeviceState.h"
#include "Magnum/Vk/Device.h"
#include "Magnum/Vk/Version.h"
namespace Magnum { namespace Vk { namespace Implementation {
DeviceState::DeviceState(Device&) {}
DeviceState::DeviceState(Device& device) {
if(device.isVersionSupported(Version::Vk11)) {
getDeviceQueueImplementation = &Device::getQueueImplementation11;
} else {
getDeviceQueueImplementation = &Device::getQueueImplementationDefault;
}
}
}}}

3
src/Magnum/Vk/Implementation/DeviceState.h

@ -32,9 +32,10 @@ namespace Magnum { namespace Vk { namespace Implementation {
struct DeviceState {
explicit DeviceState(Device& instance);
void(*getDeviceQueueImplementation)(Device&, const VkDeviceQueueInfo2&, VkQueue&);
};
}}}
#endif

88
src/Magnum/Vk/Queue.h

@ -0,0 +1,88 @@
#ifndef Magnum_Vk_Queue_h
#define Magnum_Vk_Queue_h
/*
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.
*/
/** @file
* @brief Class @ref Magnum::Vk::Queue
* @m_since_latest
*/
#include "Magnum/Tags.h"
#include "Magnum/Vk/Vk.h"
#include "Magnum/Vk/Vulkan.h"
#include "Magnum/Vk/visibility.h"
namespace Magnum { namespace Vk {
/**
@brief Queue
@m_since_latest
Wraps a @type_vk_keyword{Queue}.
@see @ref DeviceCreateInfo::addQueues()
*/
class MAGNUM_VK_EXPORT Queue {
public:
/**
* @brief Wrap existing Vulkan queue
* @param device Vulkan device
* @param handle The @type_vk{Queue} handle
*
* The @p handle is expected to be originating from @p device. Unlike
* with other handle types, the @type_vk{Queue} handles don't have to
* be destroyed at the end, so there's no equivalent of e.g.
* @ref Device::release() or @ref Device::handleFlags().
*/
static Queue wrap(Device& device, VkQueue handle) {
Queue out{NoCreate};
out._device = &device;
out._handle = handle;
return out;
}
/**
* @brief Construct without creating the instance
*
* This is the expected way to create a queue that's later populated
* on @ref Device creation through @ref DeviceCreateInfo::addQueues().
*/
explicit Queue(NoCreateT): _device{}, _handle{} {}
/** @brief Underlying @type_vk{Queue} handle */
VkQueue handle() { return _handle; }
/** @overload */
operator VkQueue() { return _handle; }
private:
/* Can't be a reference because of the NoCreate constructor */
Device* _device;
VkQueue _handle;
};
}}
#endif

136
src/Magnum/Vk/Test/DeviceVkTest.cpp

@ -37,6 +37,7 @@
#include "Magnum/Vk/Handle.h"
#include "Magnum/Vk/Instance.h"
#include "Magnum/Vk/LayerProperties.h"
#include "Magnum/Vk/Queue.h"
#include "Magnum/Vk/Result.h"
#include "Magnum/Vk/Version.h"
@ -53,11 +54,14 @@ struct DeviceVkTest: TestSuite::Tester {
void createInfoExtensions();
void createInfoCopiedStrings();
void createInfoNoQueuePriorities();
void createInfoWrongQueueOutputCount();
void construct();
void constructExtensions();
void constructExtensionsCommandLineDisable();
void constructExtensionsCommandLineEnable();
void constructMultipleQueues();
void constructRawQueue();
void constructMove();
void constructUnknownExtension();
void constructNoQueue();
@ -125,6 +129,7 @@ DeviceVkTest::DeviceVkTest(): _instance{InstanceCreateInfo{arguments().first, ar
&DeviceVkTest::createInfoExtensions,
&DeviceVkTest::createInfoCopiedStrings,
&DeviceVkTest::createInfoNoQueuePriorities,
&DeviceVkTest::createInfoWrongQueueOutputCount,
&DeviceVkTest::construct,
&DeviceVkTest::constructExtensions});
@ -133,7 +138,10 @@ DeviceVkTest::DeviceVkTest(): _instance{InstanceCreateInfo{arguments().first, ar
&DeviceVkTest::constructExtensionsCommandLineEnable},
Containers::arraySize(ConstructCommandLineData));
addTests({&DeviceVkTest::constructMove,
addTests({&DeviceVkTest::constructMultipleQueues,
&DeviceVkTest::constructRawQueue,
&DeviceVkTest::constructMove,
&DeviceVkTest::constructUnknownExtension,
&DeviceVkTest::constructNoQueue,
@ -220,18 +228,31 @@ void DeviceVkTest::createInfoNoQueuePriorities() {
std::ostringstream out;
Error redirectError{&out};
DeviceCreateInfo{_instance}.addQueues(0, {});
DeviceCreateInfo{_instance}.addQueues(0, {}, {});
CORRADE_COMPARE(out.str(), "Vk::DeviceCreateInfo::addQueues(): at least one queue priority has to be specified\n");
}
void DeviceVkTest::createInfoWrongQueueOutputCount() {
#ifdef CORRADE_NO_ASSERT
CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions");
#endif
std::ostringstream out;
Error redirectError{&out};
Queue a{NoCreate}, b{NoCreate};
DeviceCreateInfo{_instance}.addQueues(0, {0.0f, 1.0f, 0.3f}, {a, b});
CORRADE_COMPARE(out.str(), "Vk::DeviceCreateInfo::addQueues(): expected 3 outuput queue references but got 2\n");
}
void DeviceVkTest::construct() {
if(std::getenv("MAGNUM_VULKAN_VERSION"))
CORRADE_SKIP("Can't test with the MAGNUM_VULKAN_VERSION environment variable set");
{
DeviceProperties deviceProperties = pickDevice(_instance);
Queue queue{NoCreate};
Device device{_instance, DeviceCreateInfo{deviceProperties}
.addQueues(0, {0.0f})
.addQueues(0, {0.0f}, {queue})
};
CORRADE_VERIFY(device.handle());
/* Device function pointers should be populated */
@ -245,6 +266,9 @@ void DeviceVkTest::construct() {
CORRADE_VERIFY(!device.isExtensionEnabled<Extensions::EXT::debug_marker>());
/* ... and thus also no function pointers loaded */
CORRADE_VERIFY(!device->CmdDebugMarkerInsertEXT);
/* The queue should be also filled in */
CORRADE_VERIFY(queue.handle());
}
/* Shouldn't crash or anything */
@ -273,8 +297,9 @@ void DeviceVkTest::constructExtensions() {
if(!extensions.isSupported<Extensions::KHR::maintenance1>())
CORRADE_SKIP("VK_KHR_maintenance1 not supported, can't test");
Queue queue{NoCreate};
Device device{instance, DeviceCreateInfo{deviceProperties}
.addQueues(0, {0.0f})
.addQueues(0, {0.0f}, {queue})
.addEnabledExtensions({
Extensions::EXT::debug_marker::string(),
"VK_KHR_maintenance1"_s
@ -320,8 +345,9 @@ void DeviceVkTest::constructExtensionsCommandLineDisable() {
std::ostringstream out;
Debug redirectOutput{&out};
Queue queue{NoCreate};
Device device{instance, DeviceCreateInfo{deviceProperties, DeviceCreateInfo::Flag::NoImplicitExtensions}
.addQueues(0, {0.0f})
.addQueues(0, {0.0f}, {queue})
.addEnabledExtensions<
Extensions::EXT::debug_marker,
Extensions::KHR::maintenance1
@ -375,8 +401,9 @@ void DeviceVkTest::constructExtensionsCommandLineEnable() {
std::ostringstream out;
Debug redirectOutput{&out};
Queue queue{NoCreate};
Device device{instance, DeviceCreateInfo{instance, DeviceCreateInfo::Flag::NoImplicitExtensions}
.addQueues(0, {0.0f})
.addQueues(0, {0.0f}, {queue})
/* Nothing enabled by the application */
};
CORRADE_VERIFY(device.handle());
@ -397,14 +424,97 @@ void DeviceVkTest::constructExtensionsCommandLineEnable() {
CORRADE_COMPARE(!!device->TrimCommandPoolKHR, data.maintenance1Enabled);
}
void DeviceVkTest::constructMultipleQueues() {
/* Find a GPU that has at least two queue families and at least four
queues in one family */
Containers::Array<DeviceProperties> deviceProperties = enumerateDevices(_instance);
DeviceProperties* deviceWithMultipleQueues = nullptr;
UnsignedInt largeFamily = ~UnsignedInt{};
for(DeviceProperties& i: deviceProperties) {
if(i.queueFamilyCount() < 2) continue;
for(UnsignedInt family = 0; family != i.queueFamilyCount(); ++family) {
if(i.queueFamilySize(family) < 4) continue;
largeFamily = family;
break;
}
deviceWithMultipleQueues = &i;
break;
}
if(!deviceWithMultipleQueues || largeFamily == ~UnsignedInt{})
CORRADE_SKIP("No device with at least two queue families and at least four queues in one family found, can't test");
const UnsignedInt otherFamily = largeFamily == 0 ? 1 : 0;
constexpr Float zero = 0.0f;
VkDeviceQueueCreateInfo rawQueueInfo{};
rawQueueInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
rawQueueInfo.pQueuePriorities = &zero;
rawQueueInfo.queueFamilyIndex = otherFamily;
rawQueueInfo.queueCount = 1;
Queue a{NoCreate}, b{NoCreate}, c{NoCreate};
Device device{_instance, DeviceCreateInfo{*deviceWithMultipleQueues}
/* Request a raw queue in the middle of it all to test we skip it when
populating the outputs, and correctly offset the next IDs. According
to the spec we can request each family only once, which makes the
implementation and testing slightly simpler. */
.addQueues(rawQueueInfo)
/* Request multiple queues in a single family to test we correctly loop
over these as well */
.addQueues(largeFamily, {0.5f, 0.75f, 1.0f}, {a, b, c})};
/* All queues should be found and different */
CORRADE_VERIFY(a.handle());
CORRADE_VERIFY(b.handle());
CORRADE_VERIFY(c.handle());
CORRADE_VERIFY(a.handle() != b.handle());
CORRADE_VERIFY(a.handle() != c.handle());
CORRADE_VERIFY(b.handle() != c.handle());
/* Fetching the same queue again should give the same handle */
VkQueue aAgain;
device->GetDeviceQueue(device, largeFamily, 0, &aAgain);
CORRADE_COMPARE(aAgain, a.handle());
/* Fetch the raw queue, should be different from everything else as well */
VkQueue rawQueue;
device->GetDeviceQueue(device, otherFamily, 0, &rawQueue);
CORRADE_VERIFY(rawQueue);
CORRADE_VERIFY(rawQueue != a.handle());
CORRADE_VERIFY(rawQueue != b.handle());
CORRADE_VERIFY(rawQueue != c.handle());
}
void DeviceVkTest::constructRawQueue() {
/* Testing a subset of constructQueues() again because not all drivers
have multiple queues and we want to have the coverage */
constexpr Float zero = 0.0f;
VkDeviceQueueCreateInfo rawQueueInfo{};
rawQueueInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
rawQueueInfo.pQueuePriorities = &zero;
rawQueueInfo.queueFamilyIndex = 0;
rawQueueInfo.queueCount = 1;
Device device{_instance, DeviceCreateInfo{_instance}
.addQueues(rawQueueInfo)};
/* Fetch the raw queue */
VkQueue rawQueue;
device->GetDeviceQueue(device, 0, 0, &rawQueue);
CORRADE_VERIFY(rawQueue);
}
void DeviceVkTest::constructMove() {
DeviceProperties deviceProperties = pickDevice(_instance);
ExtensionProperties extensions = deviceProperties.enumerateExtensionProperties();
if(!extensions.isSupported<Extensions::KHR::maintenance1>())
CORRADE_SKIP("VK_KHR_maintenance1 not supported, can't test");
Queue queue{NoCreate};
Device a{_instance, DeviceCreateInfo{deviceProperties}
.addQueues(0, {0.0f})
.addQueues(0, {0.0f}, {queue})
.addEnabledExtensions<Extensions::KHR::maintenance1>()
};
VkDevice handle = a.handle();
@ -444,8 +554,9 @@ void DeviceVkTest::constructUnknownExtension() {
std::ostringstream out;
Error redirectError{&out};
Queue queue{NoCreate};
Device device{_instance, DeviceCreateInfo{_instance}
.addQueues(0, {0.0f})
.addQueues(0, {0.0f}, {queue})
.addEnabledExtensions({"VK_this_doesnt_exist"_s})};
CORRADE_COMPARE(out.str(), "TODO");
}
@ -487,15 +598,19 @@ void DeviceVkTest::wrap() {
CORRADE_SKIP("VK_KHR_maintenance1 not supported, can't test");
VkDevice device;
Queue queue{NoCreate};
CORRADE_COMPARE(Result(instance->CreateDevice(deviceProperties,
DeviceCreateInfo{instance}
.addQueues(0, {0.0f})
.addQueues(0, {0.0f}, {queue})
.addEnabledExtensions<
Extensions::EXT::debug_marker,
Extensions::KHR::maintenance1
>(),
nullptr, &device)), Result::Success);
CORRADE_VERIFY(device);
/* Populating the queue handle is done only from Device itself, so it won't
happen here -- would need to call vkGetDeviceQueue[2] directly */
CORRADE_VERIFY(!queue.handle());
{
/* Wrapping should load the basic function pointers */
@ -532,8 +647,9 @@ void DeviceVkTest::wrap() {
void DeviceVkTest::populateGlobalFunctionPointers() {
vkDestroyDevice = nullptr;
Queue queue{NoCreate};
Device device{_instance, DeviceCreateInfo{_instance}
.addQueues(0, {0.0f})
.addQueues(0, {0.0f}, {queue})
};
CORRADE_VERIFY(!vkDestroyDevice);
device.populateGlobalFunctionPointers();

1
src/Magnum/Vk/Vk.h

@ -49,6 +49,7 @@ class InstanceCreateInfo;
class InstanceExtension;
class InstanceExtensionProperties;
class LayerProperties;
class Queue;
enum class QueueFlag: UnsignedInt;
typedef Containers::EnumSet<QueueFlag> QueueFlags;
enum class Result: Int;

Loading…
Cancel
Save