Browse Source

Vk: it's inevitable, DeviceProperties are going to stay forever.

I have more and more cases where I need to query device properties later
down the road (memory capabilities, device name, ...) and leaving all
this up to the user / making this impossible to do in the library
internals is complicating everything too much.

Since there's a shitton of device properties with a new bag of props
coming with every other new extension, I expect the queries to get quite
involved / complicated over time (chaining 100s structs and such), so
let's design this upfront in a way that can avoid reqpeatedly querying
the same thing just because we needlessly discarded a fully populated
instance before.

It also means the users don't need to drag their own DeviceProperties
instance along anymore and can just let the Device take care of that.

Unfortunately the only nice way to make this work with DeviceCreateInfo
method chaining is to add & and && overloads for each. But it's quite
easy to test that all of them work and properly return a r-value
reference so it shouldn't be too much of a maintenance nightmare.
pull/234/head
Vladimír Vondruš 6 years ago
parent
commit
63acbc7a22
  1. 3
      doc/snippets/MagnumVk.cpp
  2. 78
      src/Magnum/Vk/Device.cpp
  3. 96
      src/Magnum/Vk/Device.h
  4. 58
      src/Magnum/Vk/Test/DeviceVkTest.cpp

3
doc/snippets/MagnumVk.cpp

@ -63,11 +63,10 @@ info->pNext = &validationFeatures;
{ {
Vk::Instance instance; Vk::Instance instance;
/* [CommandPool-usage] */ /* [CommandPool-usage] */
Vk::DeviceProperties props = DOXYGEN_IGNORE(pickDevice(instance));
Vk::Device device{DOXYGEN_IGNORE(NoCreate)}; Vk::Device device{DOXYGEN_IGNORE(NoCreate)};
Vk::CommandPool graphicsCommandPool{device, Vk::CommandPoolCreateInfo{ Vk::CommandPool graphicsCommandPool{device, Vk::CommandPoolCreateInfo{
props.pickQueueFamily(Vk::QueueFlag::Graphics) device.properties().pickQueueFamily(Vk::QueueFlag::Graphics)
}}; }};
/* [CommandPool-usage] */ /* [CommandPool-usage] */

78
src/Magnum/Vk/Device.cpp

@ -63,6 +63,11 @@ struct DeviceCreateInfo::State {
std::size_t nextQueuePriority = 0; std::size_t nextQueuePriority = 0;
bool quietLog = false; bool quietLog = false;
Version version = Version::None; Version version = Version::None;
/* Gets populated in the DeviceCreateInfo constructor that takes a
DeviceProperties&&, in which case it's then moved to the newly created
Device instance. If not populated, the Device instance gets nothing and
it'll gets populated on first access to Device::properties(). */
DeviceProperties properties{NoCreate};
}; };
DeviceCreateInfo::DeviceCreateInfo(DeviceProperties& deviceProperties, const ExtensionProperties* extensionProperties, const Flags flags): _physicalDevice{deviceProperties}, _info{}, _state{Containers::InPlaceInit} { DeviceCreateInfo::DeviceCreateInfo(DeviceProperties& deviceProperties, const ExtensionProperties* extensionProperties, const Flags flags): _physicalDevice{deviceProperties}, _info{}, _state{Containers::InPlaceInit} {
@ -119,6 +124,10 @@ DeviceCreateInfo::DeviceCreateInfo(DeviceProperties& deviceProperties, const Ext
} }
} }
DeviceCreateInfo::DeviceCreateInfo(DeviceProperties&& deviceProperties, const ExtensionProperties* extensionProperties, const Flags flags): DeviceCreateInfo{deviceProperties, extensionProperties, flags} {
_state->properties = std::move(deviceProperties);
}
DeviceCreateInfo::DeviceCreateInfo(NoInitT) noexcept {} DeviceCreateInfo::DeviceCreateInfo(NoInitT) noexcept {}
DeviceCreateInfo::DeviceCreateInfo(VkPhysicalDevice physicalDevice, const VkDeviceCreateInfo& info): _physicalDevice{physicalDevice}, DeviceCreateInfo::DeviceCreateInfo(VkPhysicalDevice physicalDevice, const VkDeviceCreateInfo& info): _physicalDevice{physicalDevice},
@ -128,7 +137,7 @@ DeviceCreateInfo::DeviceCreateInfo(VkPhysicalDevice physicalDevice, const VkDevi
DeviceCreateInfo::~DeviceCreateInfo() = default; DeviceCreateInfo::~DeviceCreateInfo() = default;
DeviceCreateInfo& DeviceCreateInfo::addEnabledExtensions(const Containers::ArrayView<const Containers::StringView> extensions) { DeviceCreateInfo& DeviceCreateInfo::addEnabledExtensions(const Containers::ArrayView<const Containers::StringView> extensions) & {
if(extensions.empty()) return *this; if(extensions.empty()) return *this;
/* This can happen in case we used the NoInit or VkDeviceCreateInfo /* This can happen in case we used the NoInit or VkDeviceCreateInfo
constructor */ constructor */
@ -160,11 +169,21 @@ DeviceCreateInfo& DeviceCreateInfo::addEnabledExtensions(const Containers::Array
return *this; return *this;
} }
DeviceCreateInfo& DeviceCreateInfo::addEnabledExtensions(const std::initializer_list<Containers::StringView> extensions) { DeviceCreateInfo&& DeviceCreateInfo::addEnabledExtensions(const Containers::ArrayView<const Containers::StringView> extensions) && {
addEnabledExtensions(extensions);
return std::move(*this);
}
DeviceCreateInfo& DeviceCreateInfo::addEnabledExtensions(const std::initializer_list<Containers::StringView> extensions) & {
return addEnabledExtensions(Containers::arrayView(extensions)); return addEnabledExtensions(Containers::arrayView(extensions));
} }
DeviceCreateInfo& DeviceCreateInfo::addEnabledExtensions(const Containers::ArrayView<const Extension> extensions) { DeviceCreateInfo&& DeviceCreateInfo::addEnabledExtensions(const std::initializer_list<Containers::StringView> extensions) && {
addEnabledExtensions(extensions);
return std::move(*this);
}
DeviceCreateInfo& DeviceCreateInfo::addEnabledExtensions(const Containers::ArrayView<const Extension> extensions) & {
if(extensions.empty()) return *this; if(extensions.empty()) return *this;
/* This can happen in case we used the NoInit or VkDeviceCreateInfo /* This can happen in case we used the NoInit or VkDeviceCreateInfo
constructor */ constructor */
@ -185,11 +204,21 @@ DeviceCreateInfo& DeviceCreateInfo::addEnabledExtensions(const Containers::Array
return *this; return *this;
} }
DeviceCreateInfo& DeviceCreateInfo::addEnabledExtensions(const std::initializer_list<Extension> extensions) { DeviceCreateInfo&& DeviceCreateInfo::addEnabledExtensions(const Containers::ArrayView<const Extension> extensions) && {
addEnabledExtensions(extensions);
return std::move(*this);
}
DeviceCreateInfo& DeviceCreateInfo::addEnabledExtensions(const std::initializer_list<Extension> extensions) & {
return addEnabledExtensions(Containers::arrayView(extensions)); return addEnabledExtensions(Containers::arrayView(extensions));
} }
DeviceCreateInfo& DeviceCreateInfo::addQueues(const UnsignedInt family, const Containers::ArrayView<const Float> priorities, const Containers::ArrayView<const Containers::Reference<Queue>> output) { DeviceCreateInfo&& DeviceCreateInfo::addEnabledExtensions(const std::initializer_list<Extension> extensions) && {
addEnabledExtensions(extensions);
return std::move(*this);
}
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(!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); CORRADE_ASSERT(output.size() == priorities.size(), "Vk::DeviceCreateInfo::addQueues(): expected" << priorities.size() << "outuput queue references but got" << output.size(), *this);
@ -217,11 +246,21 @@ DeviceCreateInfo& DeviceCreateInfo::addQueues(const UnsignedInt family, const Co
return addQueues(info); return addQueues(info);
} }
DeviceCreateInfo& DeviceCreateInfo::addQueues(const UnsignedInt family, const std::initializer_list<Float> priorities, const std::initializer_list<Containers::Reference<Queue>> output) { DeviceCreateInfo&& DeviceCreateInfo::addQueues(const UnsignedInt family, const Containers::ArrayView<const Float> priorities, const Containers::ArrayView<const Containers::Reference<Queue>> output) && {
addQueues(family, priorities, output);
return std::move(*this);
}
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)); return addQueues(family, Containers::arrayView(priorities), Containers::arrayView(output));
} }
DeviceCreateInfo& DeviceCreateInfo::addQueues(const VkDeviceQueueCreateInfo& info) { DeviceCreateInfo&& DeviceCreateInfo::addQueues(const UnsignedInt family, const std::initializer_list<Float> priorities, const std::initializer_list<Containers::Reference<Queue>> output) && {
addQueues(family, priorities, output);
return std::move(*this);
}
DeviceCreateInfo& DeviceCreateInfo::addQueues(const VkDeviceQueueCreateInfo& info) & {
/* This can happen in case we used the NoInit or VkDeviceCreateInfo /* This can happen in case we used the NoInit or VkDeviceCreateInfo
constructor */ constructor */
if(!_state) _state.emplace(); if(!_state) _state.emplace();
@ -236,6 +275,11 @@ DeviceCreateInfo& DeviceCreateInfo::addQueues(const VkDeviceQueueCreateInfo& inf
return *this; return *this;
} }
DeviceCreateInfo&& DeviceCreateInfo::addQueues(const VkDeviceQueueCreateInfo& info) && {
addQueues(info);
return std::move(*this);
}
Device Device::wrap(Instance& instance, const VkDevice handle, const Version version, const Containers::ArrayView<const Containers::StringView> enabledExtensions, const HandleFlags flags) { Device Device::wrap(Instance& instance, const VkDevice handle, const Version version, const Containers::ArrayView<const Containers::StringView> enabledExtensions, const HandleFlags flags) {
/* Compared to the constructor nothing is printed here as it would be just /* Compared to the constructor nothing is printed here as it would be just
repeating what was passed to the constructor */ repeating what was passed to the constructor */
@ -251,7 +295,11 @@ Device Device::wrap(Instance& instance, const VkDevice handle, const Version ver
return wrap(instance, handle, version, Containers::arrayView(enabledExtensions), flags); return wrap(instance, handle, version, Containers::arrayView(enabledExtensions), flags);
} }
Device::Device(Instance& instance, const DeviceCreateInfo& info): Device::Device(Instance& instance, const DeviceCreateInfo& info): Device{instance, info, DeviceProperties{NoCreate}} {}
Device::Device(Instance& instance, DeviceCreateInfo&& info): Device{instance, info, std::move(info._state->properties)} {}
Device::Device(Instance& instance, const DeviceCreateInfo& info, DeviceProperties&& properties):
#ifdef CORRADE_GRACEFUL_ASSERT #ifdef CORRADE_GRACEFUL_ASSERT
_handle{}, /* Otherwise the destructor dies if we hit the queue assert */ _handle{}, /* Otherwise the destructor dies if we hit the queue assert */
#endif #endif
@ -260,7 +308,16 @@ Device::Device(Instance& instance, const DeviceCreateInfo& info):
CORRADE_ASSERT(info._info.queueCreateInfoCount, CORRADE_ASSERT(info._info.queueCreateInfoCount,
"Vk::Device: needs to be created with at least one queue", ); "Vk::Device: needs to be created with at least one queue", );
const Version version = info._state->version != Version::None ? info._state->version : DeviceProperties::wrap(instance, info._physicalDevice).apiVersion(); /* If the passed properties are populated, use them. Otherwise create a new
instance as we'd have no other way to remember the VkPhysicalDevice
handle otherwise */
if(properties.handle())
_properties.emplace(std::move(properties));
else
_properties.emplace(DeviceProperties::wrap(instance, info._physicalDevice));
const Version version = info._state->version != Version::None ?
info._state->version : _properties->apiVersion();
/* Print all enabled extensions if we're not told to be quiet */ /* Print all enabled extensions if we're not told to be quiet */
if(!info._state || !info._state->quietLog) { if(!info._state || !info._state->quietLog) {
@ -315,7 +372,7 @@ Device::Device(NoCreateT): _handle{}, _functionPointers{} {}
Device::Device(Device&& other) noexcept: _handle{other._handle}, Device::Device(Device&& other) noexcept: _handle{other._handle},
_flags{other._flags}, _version{other._version}, _flags{other._flags}, _version{other._version},
_extensionStatus{other._extensionStatus}, _state{std::move(other._state)}, _extensionStatus{other._extensionStatus}, _properties{std::move(other._properties)}, _state{std::move(other._state)},
/* Can't use {} with GCC 4.8 here because it tries to initialize the first /* Can't use {} with GCC 4.8 here because it tries to initialize the first
member instead of doing a copy */ member instead of doing a copy */
_functionPointers(other._functionPointers) _functionPointers(other._functionPointers)
@ -335,6 +392,7 @@ Device& Device::operator=(Device&& other) noexcept {
swap(other._flags, _flags); swap(other._flags, _flags);
swap(other._version, _version); swap(other._version, _version);
swap(other._extensionStatus, _extensionStatus); swap(other._extensionStatus, _extensionStatus);
swap(other._properties, _properties);
swap(other._state, _state); swap(other._state, _state);
swap(other._functionPointers, _functionPointers); swap(other._functionPointers, _functionPointers);
return *this; return *this;

96
src/Magnum/Vk/Device.h

@ -95,7 +95,8 @@ class MAGNUM_VK_EXPORT DeviceCreateInfo {
* @param extensionProperties Existing @ref ExtensionProperties * @param extensionProperties Existing @ref ExtensionProperties
* instance for querying available Vulkan extensions. If * instance for querying available Vulkan extensions. If
* @cpp nullptr @ce, a new instance may be created internally if * @cpp nullptr @ce, a new instance may be created internally if
* needed. * needed. If a r-value is passed, the instance is later available
* through @ref Device::properties().
* @param flags Device creation flags * @param flags Device creation flags
* *
* The following @type_vk{DeviceCreateInfo} fields are pre-filled in * The following @type_vk{DeviceCreateInfo} fields are pre-filled in
@ -107,12 +108,22 @@ class MAGNUM_VK_EXPORT DeviceCreateInfo {
*/ */
explicit DeviceCreateInfo(DeviceProperties& deviceProperties, const ExtensionProperties* extensionProperties, Flags flags = {}); explicit DeviceCreateInfo(DeviceProperties& deviceProperties, const ExtensionProperties* extensionProperties, Flags flags = {});
/** @overload */
explicit DeviceCreateInfo(DeviceProperties&& deviceProperties, const ExtensionProperties* extensionProperties, Flags flags = {}): DeviceCreateInfo{deviceProperties, extensionProperties, flags} {}
/** @overload */ /** @overload */
explicit DeviceCreateInfo(DeviceProperties& deviceProperties, Flags flags = {}): DeviceCreateInfo{deviceProperties, nullptr, flags} {} explicit DeviceCreateInfo(DeviceProperties& deviceProperties, Flags flags = {}): DeviceCreateInfo{deviceProperties, nullptr, flags} {}
/**
* @brief Construct with allowing to reuse already populated device properties
*
* Compared to @ref DeviceCreateInfo(DeviceProperties&, const ExtensionProperties*, Flags),
* if the @ref Device is subsequently constructed via
* @ref Device::Device(Instance&, DeviceCreateInfo&&), the
* @p deviceProperties instance gets directly transferred to the
* device, meaning @ref Device::properties() and any APIs relying on it
* can reuse what was possibly already queried without having to repeat
* the potentially complex queries second time.
*/
explicit DeviceCreateInfo(DeviceProperties&& deviceProperties, const ExtensionProperties* extensionProperties, Flags flags = {});
/** @overload */ /** @overload */
explicit DeviceCreateInfo(DeviceProperties&& deviceProperties, Flags flags = {}): DeviceCreateInfo{std::move(deviceProperties), nullptr, flags} {} explicit DeviceCreateInfo(DeviceProperties&& deviceProperties, Flags flags = {}): DeviceCreateInfo{std::move(deviceProperties), nullptr, flags} {}
@ -135,6 +146,18 @@ class MAGNUM_VK_EXPORT DeviceCreateInfo {
~DeviceCreateInfo(); ~DeviceCreateInfo();
/* All the && overloads below are there in order to allow code like
Device device{instance, DeviceCreateInfo{pickDevice(instance)}
.addQueues(...)
.addEnabledExtensions(...)
...
};
to work and correctly move the DeviceProperties to the Device.
When adding new APIs, expand DeviceVkTest::createInfoRvalue() to
verify everything still works. */
/** /**
* @brief Add enabled device extensions * @brief Add enabled device extensions
* @return Reference to self (for method chaining) * @return Reference to self (for method chaining)
@ -147,17 +170,30 @@ class MAGNUM_VK_EXPORT DeviceCreateInfo {
* null-terminated, use the @link Containers::Literals::operator""_s() @endlink * null-terminated, use the @link Containers::Literals::operator""_s() @endlink
* literal to prevent that where possible. * literal to prevent that where possible.
*/ */
DeviceCreateInfo& addEnabledExtensions(Containers::ArrayView<const Containers::StringView> extensions); DeviceCreateInfo& addEnabledExtensions(Containers::ArrayView<const Containers::StringView> extensions) &;
/** @overload */
DeviceCreateInfo&& addEnabledExtensions(Containers::ArrayView<const Containers::StringView> extensions) &&;
/** @overload */
DeviceCreateInfo& addEnabledExtensions(std::initializer_list<Containers::StringView> extension) &;
/** @overload */ /** @overload */
DeviceCreateInfo& addEnabledExtensions(std::initializer_list<Containers::StringView> extension); DeviceCreateInfo&& addEnabledExtensions(std::initializer_list<Containers::StringView> extension) &&;
/** @overload */ /** @overload */
DeviceCreateInfo& addEnabledExtensions(Containers::ArrayView<const Extension> extensions); DeviceCreateInfo& addEnabledExtensions(Containers::ArrayView<const Extension> extensions) &;
/** @overload */ /** @overload */
DeviceCreateInfo& addEnabledExtensions(std::initializer_list<Extension> extension); DeviceCreateInfo&& addEnabledExtensions(Containers::ArrayView<const Extension> extensions) &&;
/** @overload */ /** @overload */
template<class ...E> DeviceCreateInfo& addEnabledExtensions() { DeviceCreateInfo& addEnabledExtensions(std::initializer_list<Extension> extension) &;
/** @overload */
DeviceCreateInfo&& addEnabledExtensions(std::initializer_list<Extension> extension) &&;
/** @overload */
template<class ...E> DeviceCreateInfo& addEnabledExtensions() & {
static_assert(Implementation::IsExtension<E...>::value, "expected only Vulkan device extensions"); static_assert(Implementation::IsExtension<E...>::value, "expected only Vulkan device extensions");
return addEnabledExtensions({E{}...}); return addEnabledExtensions(std::initializer_list<Extension>{E{}...});
}
/** @overload */
template<class ...E> DeviceCreateInfo&& addEnabledExtensions() && {
addEnabledExtensions<E...>();
return std::move(*this);
} }
/** /**
@ -173,9 +209,13 @@ class MAGNUM_VK_EXPORT DeviceCreateInfo {
* At least one queue has to be added. * At least one queue has to be added.
* @see @ref DeviceProperties::pickQueueFamily() * @see @ref DeviceProperties::pickQueueFamily()
*/ */
DeviceCreateInfo& addQueues(UnsignedInt family, Containers::ArrayView<const Float> priorities, Containers::ArrayView<const Containers::Reference<Queue>> output); DeviceCreateInfo& addQueues(UnsignedInt family, Containers::ArrayView<const Float> priorities, Containers::ArrayView<const Containers::Reference<Queue>> output) &;
/** @overload */
DeviceCreateInfo&& addQueues(UnsignedInt family, Containers::ArrayView<const Float> priorities, Containers::ArrayView<const Containers::Reference<Queue>> output) &&;
/** @overload */ /** @overload */
DeviceCreateInfo& addQueues(UnsignedInt family, std::initializer_list<Float> priorities, std::initializer_list<Containers::Reference<Queue>> output); DeviceCreateInfo& addQueues(UnsignedInt family, std::initializer_list<Float> priorities, std::initializer_list<Containers::Reference<Queue>> output) &;
/** @overload */
DeviceCreateInfo&& addQueues(UnsignedInt family, std::initializer_list<Float> priorities, std::initializer_list<Containers::Reference<Queue>> output) &&;
/** /**
* @brief Add queues using raw info * @brief Add queues using raw info
@ -185,7 +225,9 @@ class MAGNUM_VK_EXPORT DeviceCreateInfo {
* queue properties using the `pNext` chain. The info is uses as-is, * queue properties using the `pNext` chain. The info is uses as-is,
* with all pointers expected to stay in scope until device creation. * with all pointers expected to stay in scope until device creation.
*/ */
DeviceCreateInfo& addQueues(const VkDeviceQueueCreateInfo& info); DeviceCreateInfo& addQueues(const VkDeviceQueueCreateInfo& info) &;
/** @overload */
DeviceCreateInfo&& addQueues(const VkDeviceQueueCreateInfo& info) &&;
/** @brief Underlying @type_vk{DeviceCreateInfo} structure */ /** @brief Underlying @type_vk{DeviceCreateInfo} structure */
VkDeviceCreateInfo& operator*() { return _info; } VkDeviceCreateInfo& operator*() { return _info; }
@ -353,6 +395,20 @@ class MAGNUM_VK_EXPORT Device {
*/ */
explicit Device(Instance& instance, const DeviceCreateInfo& info); explicit Device(Instance& instance, const DeviceCreateInfo& info);
/**
* @brief Construct with reusing already populated device properties
*
* Compared to @ref Device(Instance&, const DeviceCreateInfo&), it can
* take ownership of the @ref DeviceProperties added to @p info earlier
* via @ref DeviceCreateInfo::DeviceCreateInfo(DeviceProperties&&, const ExtensionProperties*, Flags) or any of the other r-value-taking
* constructors.
*
* With that, the @ref properties() getter and any APIs relying on it
* can reuse what was possibly already queried without having to repeat
* the potentially complex queries second time.
*/
explicit Device(Instance& instance, DeviceCreateInfo&& info);
/** /**
* @brief Construct without creating the device * @brief Construct without creating the device
* *
@ -392,6 +448,15 @@ class MAGNUM_VK_EXPORT Device {
/** @brief Handle flags */ /** @brief Handle flags */
HandleFlags handleFlags() const { return _flags; } HandleFlags handleFlags() const { return _flags; }
/**
* @brief Device properties
*
* If a r-value @ref DeviceProperties instance was propagated to
* @ref DeviceCreateInfo and then to @ref Device, it's reused here.
* Otherwise the contents are populated on first use.
*/
DeviceProperties& properties() { return *_properties; }
/** /**
* @brief Version supported by the device * @brief Version supported by the device
* *
@ -477,6 +542,10 @@ class MAGNUM_VK_EXPORT Device {
private: private:
friend Implementation::DeviceState; friend Implementation::DeviceState;
/* Common guts for Device(Instance&, DeviceCreateInfo&) and
Device(Instance&, DeviceCreateInfo&&) */
explicit Device(Instance& isntance, const DeviceCreateInfo&, DeviceProperties&&);
template<class T> MAGNUM_VK_LOCAL void initializeExtensions(Containers::ArrayView<const T> enabledExtensions); 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 void initialize(Instance& instance, Version version);
@ -487,6 +556,7 @@ class MAGNUM_VK_EXPORT Device {
HandleFlags _flags; HandleFlags _flags;
Version _version; Version _version;
Math::BoolVector<Implementation::ExtensionCount> _extensionStatus; Math::BoolVector<Implementation::ExtensionCount> _extensionStatus;
Containers::Pointer<DeviceProperties> _properties;
Containers::Pointer<Implementation::DeviceState> _state; Containers::Pointer<Implementation::DeviceState> _state;
/* This member is bigger than you might think */ /* This member is bigger than you might think */

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

@ -54,9 +54,11 @@ struct DeviceVkTest: VulkanTester {
void createInfoCopiedStrings(); void createInfoCopiedStrings();
void createInfoNoQueuePriorities(); void createInfoNoQueuePriorities();
void createInfoWrongQueueOutputCount(); void createInfoWrongQueueOutputCount();
void createInfoRvalue();
void construct(); void construct();
void constructExtensions(); void constructExtensions();
void constructTransferDeviceProperties();
void constructExtensionsCommandLineDisable(); void constructExtensionsCommandLineDisable();
void constructExtensionsCommandLineEnable(); void constructExtensionsCommandLineEnable();
void constructMultipleQueues(); void constructMultipleQueues();
@ -64,7 +66,9 @@ struct DeviceVkTest: VulkanTester {
void constructMove(); void constructMove();
void constructUnknownExtension(); void constructUnknownExtension();
void constructNoQueue(); void constructNoQueue();
void wrap(); void wrap();
void populateGlobalFunctionPointers(); void populateGlobalFunctionPointers();
}; };
@ -126,9 +130,11 @@ DeviceVkTest::DeviceVkTest(): VulkanTester{NoCreate} {
&DeviceVkTest::createInfoCopiedStrings, &DeviceVkTest::createInfoCopiedStrings,
&DeviceVkTest::createInfoNoQueuePriorities, &DeviceVkTest::createInfoNoQueuePriorities,
&DeviceVkTest::createInfoWrongQueueOutputCount, &DeviceVkTest::createInfoWrongQueueOutputCount,
&DeviceVkTest::createInfoRvalue,
&DeviceVkTest::construct, &DeviceVkTest::construct,
&DeviceVkTest::constructExtensions}); &DeviceVkTest::constructExtensions,
&DeviceVkTest::constructTransferDeviceProperties});
addInstancedTests({&DeviceVkTest::constructExtensionsCommandLineDisable, addInstancedTests({&DeviceVkTest::constructExtensionsCommandLineDisable,
&DeviceVkTest::constructExtensionsCommandLineEnable}, &DeviceVkTest::constructExtensionsCommandLineEnable},
@ -233,6 +239,33 @@ void DeviceVkTest::createInfoWrongQueueOutputCount() {
CORRADE_COMPARE(out.str(), "Vk::DeviceCreateInfo::addQueues(): expected 3 outuput queue references but got 2\n"); CORRADE_COMPARE(out.str(), "Vk::DeviceCreateInfo::addQueues(): expected 3 outuput queue references but got 2\n");
} }
void DeviceVkTest::createInfoRvalue() {
Float zero[1]{};
Queue a{NoCreate}, b{NoCreate};
Containers::Reference<Queue> reference[1]{a};
VkDeviceQueueCreateInfo rawQueueInfo{};
rawQueueInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
rawQueueInfo.pQueuePriorities = zero;
rawQueueInfo.queueFamilyIndex = 0;
rawQueueInfo.queueCount = 1;
DeviceCreateInfo&& info = DeviceCreateInfo{pickDevice(instance())}
.addEnabledExtensions(Containers::ArrayView<const Containers::StringView>{})
.addEnabledExtensions(std::initializer_list<Containers::StringView>{})
.addEnabledExtensions(Containers::ArrayView<const Extension>{})
.addEnabledExtensions(std::initializer_list<Extension>{})
.addEnabledExtensions<>()
.addQueues(0, zero, reference)
.addQueues(0, {0.0f}, {b})
.addQueues(rawQueueInfo);
/* Just to test something, main point is that the above compiles, links and
returns a &&. Can't test anything related to the contents because the
destructor gets called at the end of the expression. */
CORRADE_VERIFY(&info);
}
void DeviceVkTest::construct() { void DeviceVkTest::construct() {
if(std::getenv("MAGNUM_VULKAN_VERSION")) if(std::getenv("MAGNUM_VULKAN_VERSION"))
CORRADE_SKIP("Can't test with the MAGNUM_VULKAN_VERSION environment variable set"); CORRADE_SKIP("Can't test with the MAGNUM_VULKAN_VERSION environment variable set");
@ -258,6 +291,11 @@ void DeviceVkTest::construct() {
/* The queue should be also filled in */ /* The queue should be also filled in */
CORRADE_VERIFY(queue.handle()); CORRADE_VERIFY(queue.handle());
/* Device properties should be lazy-populated and different from the
above instances because we didn't transfer the ownership */
CORRADE_COMPARE(device.properties().name(), deviceProperties.name());
CORRADE_VERIFY(&device.properties().properties() != &deviceProperties.properties());
} }
/* Shouldn't crash or anything */ /* Shouldn't crash or anything */
@ -303,6 +341,19 @@ void DeviceVkTest::constructExtensions() {
CORRADE_VERIFY(device->TrimCommandPoolKHR); CORRADE_VERIFY(device->TrimCommandPoolKHR);
} }
void DeviceVkTest::constructTransferDeviceProperties() {
DeviceProperties deviceProperties = pickDevice(instance());
const void* vkProperties = &deviceProperties.properties();
Queue queue{NoCreate};
Device device{instance(), DeviceCreateInfo{std::move(deviceProperties)}
.addQueues(0, {0.0f}, {queue})
};
/* Device properties should be the same address as in the original instance
because the ownership got transferred through */
CORRADE_COMPARE(&device.properties().properties(), vkProperties);
}
void DeviceVkTest::constructExtensionsCommandLineDisable() { void DeviceVkTest::constructExtensionsCommandLineDisable() {
auto&& data = ConstructCommandLineData[testCaseInstanceId()]; auto&& data = ConstructCommandLineData[testCaseInstanceId()];
setTestCaseDescription(data.nameDisable); setTestCaseDescription(data.nameDisable);
@ -496,6 +547,9 @@ void DeviceVkTest::constructRawQueue() {
} }
void DeviceVkTest::constructMove() { void DeviceVkTest::constructMove() {
if(std::getenv("MAGNUM_VULKAN_VERSION"))
CORRADE_SKIP("Can't test with the MAGNUM_VULKAN_VERSION environment variable set");
DeviceProperties deviceProperties = pickDevice(instance()); DeviceProperties deviceProperties = pickDevice(instance());
ExtensionProperties extensions = deviceProperties.enumerateExtensionProperties(); ExtensionProperties extensions = deviceProperties.enumerateExtensionProperties();
if(!extensions.isSupported<Extensions::KHR::maintenance1>()) if(!extensions.isSupported<Extensions::KHR::maintenance1>())
@ -517,6 +571,7 @@ void DeviceVkTest::constructMove() {
CORRADE_COMPARE(b.handleFlags(), HandleFlag::DestroyOnDestruction); CORRADE_COMPARE(b.handleFlags(), HandleFlag::DestroyOnDestruction);
CORRADE_COMPARE(b.handle(), handle); CORRADE_COMPARE(b.handle(), handle);
CORRADE_COMPARE(b.version(), version); CORRADE_COMPARE(b.version(), version);
CORRADE_COMPARE(b.properties().apiVersion(), version);
CORRADE_VERIFY(b.isExtensionEnabled<Extensions::KHR::maintenance1>()); CORRADE_VERIFY(b.isExtensionEnabled<Extensions::KHR::maintenance1>());
/* Function pointers in a are left in whatever state they were before, as /* Function pointers in a are left in whatever state they were before, as
that doesn't matter */ that doesn't matter */
@ -529,6 +584,7 @@ void DeviceVkTest::constructMove() {
CORRADE_COMPARE(c.handleFlags(), HandleFlag::DestroyOnDestruction); CORRADE_COMPARE(c.handleFlags(), HandleFlag::DestroyOnDestruction);
CORRADE_COMPARE(c.handle(), handle); CORRADE_COMPARE(c.handle(), handle);
CORRADE_COMPARE(c.version(), version); CORRADE_COMPARE(c.version(), version);
CORRADE_COMPARE(c.properties().apiVersion(), version);
CORRADE_VERIFY(c.isExtensionEnabled<Extensions::KHR::maintenance1>()); CORRADE_VERIFY(c.isExtensionEnabled<Extensions::KHR::maintenance1>());
/* Everything is swapped, including function pointers */ /* Everything is swapped, including function pointers */
CORRADE_VERIFY(!b->CreateBuffer); CORRADE_VERIFY(!b->CreateBuffer);

Loading…
Cancel
Save