diff --git a/CMakeLists.txt b/CMakeLists.txt index c02afcc0b..0913b722f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -217,8 +217,10 @@ if(BUILD_TESTS) endif() endif() -# OpenGLTester library, built by default only if GL tests are enabled +# OpenGLTester / VulkanTester libraries, built by default only if GL / VK tests +# are enabled cmake_dependent_option(WITH_OPENGLTESTER "Build OpenGLTester library" OFF "NOT BUILD_GL_TESTS" ON) +cmake_dependent_option(WITH_VULKANTESTER "Build VulkanTester library" OFF "NOT BUILD_VK_TESTS" ON) # Dynamic linking is meaningless on Emscripten and too inconvenient on Android if(CORRADE_TARGET_EMSCRIPTEN OR CORRADE_TARGET_ANDROID) diff --git a/doc/Doxyfile b/doc/Doxyfile index 11ad3f9ff..bdcab4f62 100644 --- a/doc/Doxyfile +++ b/doc/Doxyfile @@ -2256,7 +2256,7 @@ PREDEFINED = DOXYGEN_GENERATING_OUTPUT \ CORRADE_VISIBILITY_LOCAL= CORRADE_VISIBILITY_IMPORT= \ CORRADE_IGNORE_DEPRECATED_PUSH= CORRADE_IGNORE_DEPRECATED_POP= \ CORRADE_ENUMSET_OPERATORS(message)= MAGNUM_BUILD_DEPRECATED \ - MAGNUM_TARGET_GL + MAGNUM_TARGET_GL MAGNUM_TARGET_VK # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this # tag can be used to specify a list of macro names that should be expanded. The diff --git a/doc/building.dox b/doc/building.dox index 088c52954..db019acd1 100644 --- a/doc/building.dox +++ b/doc/building.dox @@ -565,6 +565,8 @@ code: - `WITH_OPENGLTESTER` --- The @ref GL::OpenGLTester class. Requires `TARGET_GL` to be enabled; enables building of one of the windowless application libraries based on the target platform. +- `WITH_VULKANTESTER` --- The @ref Vk::VulkanTester class. Requires + `TARGET_VK` to be enabled. Magnum also contains a set of dependency-less plugins for importing essential file formats. Additional plugins are provided in a separate plugin repository, diff --git a/doc/cmake.dox b/doc/cmake.dox index e28d6802d..15700cf78 100644 --- a/doc/cmake.dox +++ b/doc/cmake.dox @@ -231,6 +231,7 @@ There are also extensions to @ref Corrade::TestSuite::Tester for testing GPU code: - `OpenGLTester` --- @ref GL::OpenGLTester class +- `VulkanTester` --- @ref Vk::VulkanTester class The library also contains a set of plugins for importing essential file formats. Additional plugins are provided in separate plugin repository, see diff --git a/modules/FindMagnum.cmake b/modules/FindMagnum.cmake index d69a5ed83..d9d296f81 100644 --- a/modules/FindMagnum.cmake +++ b/modules/FindMagnum.cmake @@ -86,6 +86,7 @@ # GlxContext - GLX context # WglContext - WGL context # OpenGLTester - OpenGLTester class +# VulkanTester - VulkanTester class # MagnumFont - Magnum bitmap font plugin # MagnumFontConverter - Magnum bitmap font converter plugin # ObjImporter - OBJ importer plugin @@ -372,7 +373,7 @@ set(_MAGNUM_IMPLICITLY_ENABLED_COMPONENTS DebugTools MeshTools SceneGraph Shaders ShaderTools Text TextureTools Trade GL Primitives) if(NOT CORRADE_TARGET_EMSCRIPTEN) - list(APPEND _MAGNUM_LIBRARY_COMPONENTS Vk) + list(APPEND _MAGNUM_LIBRARY_COMPONENTS Vk VulkanTester) list(APPEND _MAGNUM_EXECUTABLE_COMPONENTS vk-info) endif() if(NOT CORRADE_TARGET_ANDROID) @@ -466,6 +467,7 @@ if(MAGNUM_TARGET_GL) endif() set(_MAGNUM_Trade_DEPENDENCIES ) +set(_MAGNUM_VulkanTester_DEPENDENCIES Vk) set(_MAGNUM_AndroidApplication_DEPENDENCIES GL) set(_MAGNUM_EmscriptenApplication_DEPENDENCIES) if(MAGNUM_TARGET_GL) @@ -891,6 +893,10 @@ foreach(_component ${Magnum_FIND_COMPONENTS}) elseif(_component STREQUAL OpenGLTester) set(_MAGNUM_${_COMPONENT}_INCLUDE_PATH_SUFFIX Magnum/GL) + # VulkanTester library + elseif(_component STREQUAL VulkanTester) + set(_MAGNUM_${_COMPONENT}_INCLUDE_PATH_SUFFIX Magnum/Vk) + # Primitives library elseif(_component STREQUAL Primitives) set(_MAGNUM_${_COMPONENT}_INCLUDE_PATH_NAMES Cube.h) diff --git a/src/Magnum/Vk/CMakeLists.txt b/src/Magnum/Vk/CMakeLists.txt index 1b1d4cc74..5704f8af8 100644 --- a/src/Magnum/Vk/CMakeLists.txt +++ b/src/Magnum/Vk/CMakeLists.txt @@ -125,6 +125,37 @@ if(WITH_VK_INFO) add_executable(Magnum::vk-info ALIAS magnum-vk-info) endif() +if(WITH_VULKANTESTER) + if(NOT TARGET_VK) + message(SEND_ERROR "VulkanTester is available only if TARGET_VK is enabled") + endif() + + find_package(Corrade REQUIRED TestSuite) + + set(MagnumVulkanTester_SRCS VulkanTester.cpp) + set(MagnumVulkanTester_HEADERS VulkanTester.h) + + # Unlike with OpenGLTester, we shouldn't need a separate library that links + # exclusively to MagnumVkTestLib as there is no global state that could + # cause problems on Windows. + add_library(MagnumVulkanTester STATIC + ${MagnumVulkanTester_SRCS} + ${MagnumVulkanTester_HEADERS}) + set_target_properties(MagnumVulkanTester PROPERTIES + DEBUG_POSTFIX "-d" + FOLDER "Magnum/Vk") + target_link_libraries(MagnumVulkanTester PUBLIC MagnumVk Corrade::TestSuite) + + install(FILES ${MagnumVulkanTester_HEADERS} DESTINATION ${MAGNUM_INCLUDE_INSTALL_DIR}/Vk) + install(TARGETS MagnumVulkanTester + RUNTIME DESTINATION ${MAGNUM_BINARY_INSTALL_DIR} + LIBRARY DESTINATION ${MAGNUM_LIBRARY_INSTALL_DIR} + ARCHIVE DESTINATION ${MAGNUM_LIBRARY_INSTALL_DIR}) + + # Magnum VulkanTester target alias for superprojects + add_library(Magnum::VulkanTester ALIAS MagnumVulkanTester) +endif() + if(BUILD_TESTS) # Library with graceful assert for testing add_library(MagnumVkTestLib ${SHARED_OR_STATIC} diff --git a/src/Magnum/Vk/VulkanTester.cpp b/src/Magnum/Vk/VulkanTester.cpp new file mode 100644 index 000000000..b1e5eb078 --- /dev/null +++ b/src/Magnum/Vk/VulkanTester.cpp @@ -0,0 +1,50 @@ +/* + 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 "VulkanTester.h" + +#include /* sigh, for setSkippedArgumentPrefixes() */ +#include + +#include "Magnum/Vk/DeviceProperties.h" + +namespace Magnum { namespace Vk { + +VulkanTester::VulkanTester(): VulkanTester{NoCreate} { + *_deviceProperties = pickDevice(_instance); + _device = Vk::Device{_instance, Vk::DeviceCreateInfo{*_deviceProperties} + .addQueues(_deviceProperties->pickQueueFamily(Vk::QueueFlag::Graphics), {0.0f}, {_queue}) + }; +} + +VulkanTester::VulkanTester(NoCreateT): VulkanTester{NoCreate, NoCreate} { + _instance = Vk::Instance{Vk::InstanceCreateInfo{arguments().first, arguments().second} + .setApplicationInfo(testName(), {}) + }; +} + +VulkanTester::VulkanTester(NoCreateT, NoCreateT): TestSuite::Tester{TestSuite::Tester::TesterConfiguration{}.setSkippedArgumentPrefixes({"magnum"})}, _instance{NoCreate}, _device{NoCreate}, _deviceProperties{Containers::InPlaceInit, NoCreate}, _queue{NoCreate} {} + +}} diff --git a/src/Magnum/Vk/VulkanTester.h b/src/Magnum/Vk/VulkanTester.h new file mode 100644 index 000000000..104ae9864 --- /dev/null +++ b/src/Magnum/Vk/VulkanTester.h @@ -0,0 +1,175 @@ +#ifndef Magnum_Vk_VulkanTester_h +#define Magnum_Vk_VulkanTester_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. +*/ + +/** @file + * @brief Class @ref Magnum::Vk::VulkanTester + * @m_since_latest + */ + +#include "Magnum/configure.h" + +#ifdef MAGNUM_TARGET_VK +#include + +#include "Magnum/Vk/Instance.h" +#include "Magnum/Vk/Device.h" +#include "Magnum/Vk/Queue.h" + +namespace Magnum { namespace Vk { + +/** +@brief Base class for Vulkan tests and benchmarks +@m_since_latest + +Extends @ref Corrade::TestSuite::Tester with features for Vulkan testing and +benchmarking. Be sure to read its documentation first to have an overview of +the base features. + +This class is built into a separate static library and only if +`WITH_VULKANTESTER` is enabled when building Magnum. To use it with CMake, +request the `VulkanTester` component of the `Magnum` package. Derive your test +class from this class instead of @ref Corrade::TestSuite::Tester and +either link to `Magnum::VulkanTester` target or add it to the `LIBRARIES` +section of the @ref corrade-cmake-add-test "corrade_add_test()" macro: + +@code{.cmake} +find_package(Magnum REQUIRED VulkanTester) + +# ... +corrade_add_test(YourTest YourTest.cpp LIBRARIES Magnum::VulkanTester) +@endcode + +Additionally, if you're using Magnum as a CMake subproject, ensure it's enabled +as it's not built by default: + +@code{.cmake} +set(WITH_OPENGLTESTER ON CACHE BOOL "" FORCE) +add_subdirectory(magnum EXCLUDE_FROM_ALL) +@endcode + +See @ref building, @ref cmake and @ref testsuite for more information. + +@section Vk-VulkanTester-device Vulkan device and instance creation + +The class implicitly creates a Vulkan @ref Instance and @ref Device with +default layers and extensions and one graphics queue. These are then available +through @ref instance(), @ref device(), @ref deviceProperties() and +@ref queue() getters. + +If you want to create a custom device, use the @ref VulkanTester(NoCreateT) +constructor. You can then move the device and queue instances to the getters to +make them available through common interfaces again. If you want to create a +custom instance as well, use the @ref VulkanTester(NoCreateT, NoCreateT) +variant. +*/ +class VulkanTester: public TestSuite::Tester { + public: + /** + * @brief Default constructor + * + * Creates an instance using implicit settings, picks a default device + * and creates a graphics queue on that device. These are then exposed + * through @ref instance(), @ref device(), @ref deviceProperties() and + * @ref queue() getters. + */ + explicit VulkanTester(); + + /** + * @brief Construct without creating a device + * + * Use the @ref instance() to pick and create a device. You can then + * move it to @ref device(), @ref deviceProperties() and @ref queue() + * to have them accessible through common interfaces again. + */ + explicit VulkanTester(NoCreateT); + + /** + * @brief Construct without creating an instance or device + * + * Leaves the initialization completely on the user. You can move the + * instances to @ref instance(), @ref device(), @ref deviceProperties() + * and @ref queue() to have them accessible through common interfaces. + */ + explicit VulkanTester(NoCreateT, NoCreateT); + + protected: + /** + * @brief Vulkan instance + * + * In case the class was constructed using + * @ref VulkanTester(NoCreateT, NoCreateT), this instance is initially + * not created. Move a created instance onto it to make it useful. + */ + Instance& instance() { return _instance; } + + /** + * @brief Vulkan device + * + * In case the class was constructed using @ref VulkanTester(NoCreateT) + * or @ref VulkanTester(NoCreateT, NoCreateT), this instance is + * initially not created. Move a created instance onto it to make it + * useful. + */ + Device& device() { return _device; } + + /** + * @brief Vulkan device properties + * + * In case the class was constructed using @ref VulkanTester(NoCreateT) + * or @ref VulkanTester(NoCreateT, NoCreateT), this instance is + * initially not created. Move a created instance onto it to make it + * useful. + */ + DeviceProperties& deviceProperties() { return *_deviceProperties; } + + /** + * @brief Vulkan queue + * + * In case the calss was constructed using @ref VulkanTester(), the + * queue corresponds to @ref DeviceProperties::pickQueueFamily() with + * @ref QueueFlag::Graphics called on @ref deviceProperties(). + * + * In case the class was constructed using @ref VulkanTester(NoCreateT) + * or @ref VulkanTester(NoCreateT, NoCreateT), this instance is + * initially not created. Move a created instance onto it to make it + * useful. + */ + Queue& queue() { return _queue; } + + private: + Instance _instance; + Device _device; + Containers::Pointer _deviceProperties; + Queue _queue; +}; + +}} +#else +#error this header is available only in the Vulkan build +#endif + +#endif