diff --git a/src/Magnum/Vk/Device.cpp b/src/Magnum/Vk/Device.cpp index ee1acc279..81d1ecad8 100644 --- a/src/Magnum/Vk/Device.cpp +++ b/src/Magnum/Vk/Device.cpp @@ -151,8 +151,33 @@ DeviceCreateInfo::DeviceCreateInfo(VkPhysicalDevice physicalDevice, const VkDevi member instead of doing a copy */ _info(info) {} +DeviceCreateInfo::DeviceCreateInfo(DeviceCreateInfo&& other) noexcept: + _physicalDevice{other._physicalDevice}, + /* Can't use {} with GCC 4.8 here because it tries to initialize the first + member instead of doing a copy */ + _info(other._info), + _state{std::move(other._state)} +{ + /* Ensure the previous instance doesn't reference state that's now ours */ + /** @todo this is now more like a destructible move, do it more selectively + and clear only what's really ours and not external? */ + other._info.pNext = nullptr; + other._info.enabledExtensionCount = 0; + other._info.ppEnabledExtensionNames = nullptr; + other._info.queueCreateInfoCount = 0; + other._info.pQueueCreateInfos = nullptr; +} + DeviceCreateInfo::~DeviceCreateInfo() = default; +DeviceCreateInfo& DeviceCreateInfo::operator=(DeviceCreateInfo&& other) noexcept { + using std::swap; + swap(other._physicalDevice, _physicalDevice); + swap(other._info, _info); + swap(other._state, other._state); + return *this; +} + DeviceCreateInfo& DeviceCreateInfo::addEnabledExtensions(const Containers::ArrayView extensions) & { if(extensions.empty()) return *this; /* This can happen in case we used the NoInit or VkDeviceCreateInfo diff --git a/src/Magnum/Vk/Device.h b/src/Magnum/Vk/Device.h index 281ba53ed..484d5961c 100644 --- a/src/Magnum/Vk/Device.h +++ b/src/Magnum/Vk/Device.h @@ -144,8 +144,20 @@ class MAGNUM_VK_EXPORT DeviceCreateInfo { */ explicit DeviceCreateInfo(VkPhysicalDevice physicalDevice, const VkDeviceCreateInfo& info); + /** @brief Copying is not allowed */ + DeviceCreateInfo(const DeviceCreateInfo&) = delete; + + /** @brief Move constructor */ + DeviceCreateInfo(DeviceCreateInfo&& other) noexcept; + ~DeviceCreateInfo(); + /** @brief Copying is not allowed */ + DeviceCreateInfo& operator=(const DeviceCreateInfo&) = delete; + + /** @brief Move assignment */ + DeviceCreateInfo& operator=(DeviceCreateInfo&& other) noexcept; + /* All the && overloads below are there in order to allow code like Device device{instance, DeviceCreateInfo{pickDevice(instance)} diff --git a/src/Magnum/Vk/Test/DeviceVkTest.cpp b/src/Magnum/Vk/Test/DeviceVkTest.cpp index 25f00c89a..de2075fd4 100644 --- a/src/Magnum/Vk/Test/DeviceVkTest.cpp +++ b/src/Magnum/Vk/Test/DeviceVkTest.cpp @@ -55,6 +55,8 @@ struct DeviceVkTest: VulkanTester { void createInfoCopiedStrings(); void createInfoNoQueuePriorities(); void createInfoWrongQueueOutputCount(); + void createInfoConstructCopy(); + void createInfoConstructMove(); void createInfoRvalue(); void construct(); @@ -137,6 +139,8 @@ DeviceVkTest::DeviceVkTest(): VulkanTester{NoCreate} { &DeviceVkTest::createInfoCopiedStrings, &DeviceVkTest::createInfoNoQueuePriorities, &DeviceVkTest::createInfoWrongQueueOutputCount, + &DeviceVkTest::createInfoConstructCopy, + &DeviceVkTest::createInfoConstructMove, &DeviceVkTest::createInfoRvalue, &DeviceVkTest::construct, @@ -248,6 +252,47 @@ void DeviceVkTest::createInfoWrongQueueOutputCount() { CORRADE_COMPARE(out.str(), "Vk::DeviceCreateInfo::addQueues(): expected 3 outuput queue references but got 2\n"); } +void DeviceVkTest::createInfoConstructCopy() { + CORRADE_VERIFY(!(std::is_copy_constructible{})); + CORRADE_VERIFY(!(std::is_copy_assignable{})); +} + +void DeviceVkTest::createInfoConstructMove() { + if(std::getenv("MAGNUM_DISABLE_EXTENSIONS")) + CORRADE_SKIP("Can't test with the MAGNUM_DISABLE_EXTENSIONS environment variable set"); + + Queue queue{NoCreate}; + DeviceCreateInfo a{pickDevice(instance()), DeviceCreateInfo::Flag::NoImplicitExtensions}; + a.addQueues(0, {0.35f}, {queue}) + .addEnabledExtensions(); + + DeviceCreateInfo b{std::move(a)}; + CORRADE_COMPARE(a->enabledExtensionCount, 0); + CORRADE_VERIFY(!a->ppEnabledExtensionNames); + CORRADE_COMPARE(a->queueCreateInfoCount, 0); + CORRADE_VERIFY(!a->pQueueCreateInfos); + CORRADE_COMPARE(b->enabledExtensionCount, 2); + CORRADE_VERIFY(b->ppEnabledExtensionNames); + CORRADE_COMPARE(b->ppEnabledExtensionNames[1], "VK_KHR_bind_memory2"_s); + CORRADE_COMPARE(b->queueCreateInfoCount, 1); + CORRADE_VERIFY(b->pQueueCreateInfos); + CORRADE_COMPARE(b->pQueueCreateInfos[0].pQueuePriorities[0], 0.35f); + + DeviceCreateInfo c{{}, {}}; + c = std::move(b); + CORRADE_COMPARE(b->enabledExtensionCount, 0); + CORRADE_VERIFY(!b->ppEnabledExtensionNames); + CORRADE_COMPARE(b->queueCreateInfoCount, 0); + CORRADE_VERIFY(!b->pQueueCreateInfos); + CORRADE_COMPARE(c->enabledExtensionCount, 2); + CORRADE_VERIFY(c->ppEnabledExtensionNames); + CORRADE_COMPARE(c->ppEnabledExtensionNames[1], "VK_KHR_bind_memory2"_s); + CORRADE_COMPARE(c->queueCreateInfoCount, 1); + CORRADE_VERIFY(c->pQueueCreateInfos); + CORRADE_COMPARE(c->pQueueCreateInfos[0].pQueuePriorities[0], 0.35f); +} + void DeviceVkTest::createInfoRvalue() { /* Verify that there actually are graphics queues so we don't exit inside addQueues() */