From 613a0d8cf6b6248d151ad88facd7f844d21c0558 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Sun, 13 Dec 2020 01:51:23 +0100 Subject: [PATCH] Vk: write an internal helper for connecting Vulkan structures. --- src/Magnum/Vk/CMakeLists.txt | 1 + src/Magnum/Vk/DeviceProperties.cpp | 8 +- .../Vk/Implementation/structureHelpers.h | 59 +++++++++++++ src/Magnum/Vk/Test/CMakeLists.txt | 4 + src/Magnum/Vk/Test/StructureHelpersTest.cpp | 82 +++++++++++++++++++ 5 files changed, 149 insertions(+), 5 deletions(-) create mode 100644 src/Magnum/Vk/Implementation/structureHelpers.h create mode 100644 src/Magnum/Vk/Test/StructureHelpersTest.cpp diff --git a/src/Magnum/Vk/CMakeLists.txt b/src/Magnum/Vk/CMakeLists.txt index 2c3fae6fa..9a6bc0623 100644 --- a/src/Magnum/Vk/CMakeLists.txt +++ b/src/Magnum/Vk/CMakeLists.txt @@ -93,6 +93,7 @@ set(MagnumVk_PRIVATE_HEADERS Implementation/compressedPixelFormatMapping.hpp Implementation/pixelFormatMapping.hpp + Implementation/structureHelpers.h Implementation/vertexFormatMapping.hpp) # Objects shared between main and test library diff --git a/src/Magnum/Vk/DeviceProperties.cpp b/src/Magnum/Vk/DeviceProperties.cpp index 9a5e28d86..2794993da 100644 --- a/src/Magnum/Vk/DeviceProperties.cpp +++ b/src/Magnum/Vk/DeviceProperties.cpp @@ -43,6 +43,7 @@ #include "Magnum/Vk/Version.h" #include "Magnum/Vk/Implementation/Arguments.h" #include "Magnum/Vk/Implementation/InstanceState.h" +#include "Magnum/Vk/Implementation/structureHelpers.h" namespace Magnum { namespace Vk { @@ -192,11 +193,8 @@ const VkPhysicalDeviceProperties2& DeviceProperties::properties() { Containers::Reference next = _state->properties.pNext; /* Fetch driver properties, if supported */ - if(isVersionSupported(Version::Vk12) || extensionPropertiesInternal().isSupported()) { - *next = &_state->driverProperties; - next = _state->driverProperties.pNext; - _state->driverProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES; - } + if(isVersionSupported(Version::Vk12) || extensionPropertiesInternal().isSupported()) + connect(next, _state->driverProperties, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES); _state->getPropertiesImplementation(*this, _state->properties); } diff --git a/src/Magnum/Vk/Implementation/structureHelpers.h b/src/Magnum/Vk/Implementation/structureHelpers.h new file mode 100644 index 000000000..62f847fac --- /dev/null +++ b/src/Magnum/Vk/Implementation/structureHelpers.h @@ -0,0 +1,59 @@ +#ifndef Magnum_Vk_Implementation_structureHelpers_h +#define Magnum_Vk_Implementation_structureHelpers_h +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, + 2020 Vladimír Vondruš + + 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. +*/ + +#include +#include + +#include "Magnum/Magnum.h" +#include "Magnum/Vk/Vulkan.h" + +namespace Magnum { namespace Vk { namespace Implementation { + +/* Meant to be used for connecting a longer chain of structures. Anything + that was connected to the `next` pointer before is reconnected to + `structure.pNext`; the `next` reference is rebound to the `structure.pNext` + field connected so it can be passed to another structureConnect() again. */ +template inline void structureConnect(Containers::Reference& next, T& structure, VkStructureType type) { + void* const previousNext = next; + *next = &structure; + structure.sType = type; + structure.pNext = previousNext; + next = structure.pNext; +} + +template inline void structureConnect(Containers::Reference& next, T& structure, VkStructureType type) { + /* There's no better way as the pNext are either const void* or void* + and it's a mess. For example VkDeviceCreateInfo has const void* but it + can point to VkPhysicalDeviceFeatures2 which then has void* as it's + primarily an output structure. So we'll just drop all const-correctness + and operate on void*. */ + structureConnect(reinterpret_cast&>(next), structure, type); +} + +}}} + +#endif diff --git a/src/Magnum/Vk/Test/CMakeLists.txt b/src/Magnum/Vk/Test/CMakeLists.txt index b60e3809d..a2ddf9c3e 100644 --- a/src/Magnum/Vk/Test/CMakeLists.txt +++ b/src/Magnum/Vk/Test/CMakeLists.txt @@ -42,6 +42,9 @@ corrade_add_test(VkResultTest ResultTest.cpp LIBRARIES MagnumVk) corrade_add_test(VkRenderPassTest RenderPassTest.cpp LIBRARIES MagnumVkTestLib) corrade_add_test(VkShaderTest ShaderTest.cpp LIBRARIES MagnumVk) +corrade_add_test(VkStructureHelpersTest StructureHelpersTest.cpp) +target_include_directories(VkStructureHelpersTest PRIVATE $) + add_library(VkAssertTestObjects OBJECT AssertTest.cpp) target_include_directories(VkAssertTestObjects PRIVATE $) corrade_add_test(VkAssertTest @@ -125,6 +128,7 @@ set_target_properties( VkResultTest VkRenderPassTest VkShaderTest + VkStructureHelpersTest VkVersionTest PROPERTIES FOLDER "Magnum/Vk/Test") diff --git a/src/Magnum/Vk/Test/StructureHelpersTest.cpp b/src/Magnum/Vk/Test/StructureHelpersTest.cpp new file mode 100644 index 000000000..3f2ad40e9 --- /dev/null +++ b/src/Magnum/Vk/Test/StructureHelpersTest.cpp @@ -0,0 +1,82 @@ +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, + 2020 Vladimír Vondruš + + 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. +*/ + +#include + +#include "Magnum/Vk/Implementation/structureHelpers.h" + +namespace Magnum { namespace Vk { namespace Test { namespace { + +struct StructureHelpersTest: TestSuite::Tester { + explicit StructureHelpersTest(); + + template void connect(); +}; + +StructureHelpersTest::StructureHelpersTest() { + addTests({ + &StructureHelpersTest::connect, + &StructureHelpersTest::connect}); +} + +template struct Type; +template<> struct Type { + static const char* name() { return "const void*"; } +}; +template<> struct Type { + static const char* name() { return "void*"; } +}; + +template void StructureHelpersTest::connect() { + typedef typename std::remove_reference::type NextType; + setTestCaseTemplateName(Type::name()); + + VkPhysicalDeviceVariablePointersFeatures variableFeatures{}; + + T info{}; + info.pNext = &variableFeatures; + + Containers::Reference next = info.pNext; + + VkPhysicalDeviceMultiviewFeatures multiviewFeatures{}; + Implementation::structureConnect(next, multiviewFeatures, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES); + CORRADE_COMPARE(info.pNext, &multiviewFeatures); + CORRADE_COMPARE(multiviewFeatures.sType, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES); + CORRADE_COMPARE(const_cast(&*next), const_cast(&multiviewFeatures.pNext)); + /* The pre-existing next pointer should be preserved */ + CORRADE_COMPARE(*next, &variableFeatures); + + VkPhysicalDeviceSamplerYcbcrConversionFeatures ycbcrFeatures{}; + Implementation::structureConnect(next, ycbcrFeatures, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES); + CORRADE_COMPARE(multiviewFeatures.pNext, &ycbcrFeatures); + CORRADE_COMPARE(ycbcrFeatures.sType, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES); + CORRADE_COMPARE(const_cast(&*next), const_cast(&ycbcrFeatures.pNext)); + /* The pre-existing next pointer should be preserved */ + CORRADE_COMPARE(*next, &variableFeatures); +} + +}}}} + +CORRADE_TEST_MAIN(Magnum::Vk::Test::StructureHelpersTest)