diff --git a/doc/vulkan-mapping.dox b/doc/vulkan-mapping.dox index 67988d118..12d5a52f4 100644 --- a/doc/vulkan-mapping.dox +++ b/doc/vulkan-mapping.dox @@ -207,7 +207,7 @@ Vulkan function | Matching API @fn_vk{GetPhysicalDeviceFeatures}, \n @fn_vk{GetPhysicalDeviceFeatures2} @m_class{m-label m-flat m-success} **KHR, 1.1** | | @fn_vk{GetPhysicalDeviceFormatProperties}, \n @fn_vk{GetPhysicalDeviceFormatProperties2} @m_class{m-label m-flat m-success} **KHR, 1.1** | | @fn_vk{GetPhysicalDeviceImageFormatProperties}, \n @fn_vk{GetPhysicalDeviceImageFormatProperties2} @m_class{m-label m-flat m-success} **KHR, 1.1** | | -@fn_vk{GetPhysicalDeviceMemoryProperties}, \n @fn_vk{GetPhysicalDeviceMemoryProperties2} @m_class{m-label m-flat m-success} **KHR, 1.1** | | +@fn_vk{GetPhysicalDeviceMemoryProperties}, \n @fn_vk{GetPhysicalDeviceMemoryProperties2} @m_class{m-label m-flat m-success} **KHR, 1.1** | @ref DeviceProperties::memoryProperties() @fn_vk{GetPhysicalDeviceProperties}, \n @fn_vk{GetPhysicalDeviceProperties2} @m_class{m-label m-flat m-success} **KHR, 1.1** | @ref DeviceProperties @fn_vk{GetPhysicalDeviceQueueFamilyProperties}, \n @fn_vk{GetPhysicalDeviceQueueFamilyProperties2} @m_class{m-label m-flat m-success} **KHR, 1.1** | @ref DeviceProperties::queueFamilyProperties() @fn_vk{GetPhysicalDeviceSparseImageFormatProperties}, \n @fn_vk{GetPhysicalDeviceSparseImageFormatProperties2} @m_class{m-label m-flat m-success} **KHR, 1.1** | | diff --git a/src/Magnum/Vk/CMakeLists.txt b/src/Magnum/Vk/CMakeLists.txt index 8b5f87d8e..3f8906b93 100644 --- a/src/Magnum/Vk/CMakeLists.txt +++ b/src/Magnum/Vk/CMakeLists.txt @@ -32,6 +32,7 @@ set(MagnumVk_SRCS Extensions.cpp Handle.cpp Instance.cpp + Memory.cpp Result.cpp Version.cpp @@ -58,6 +59,7 @@ set(MagnumVk_HEADERS Instance.h Integration.h LayerProperties.h + Memory.h Queue.h Result.h TypeTraits.h diff --git a/src/Magnum/Vk/DeviceProperties.cpp b/src/Magnum/Vk/DeviceProperties.cpp index 5aabb18e1..e6e0d3981 100644 --- a/src/Magnum/Vk/DeviceProperties.cpp +++ b/src/Magnum/Vk/DeviceProperties.cpp @@ -43,6 +43,7 @@ namespace Magnum { namespace Vk { struct DeviceProperties::State { VkPhysicalDeviceProperties2 properties{}; + VkPhysicalDeviceMemoryProperties2 memoryProperties{}; Containers::Array queueFamilyProperties; }; @@ -176,6 +177,65 @@ Containers::Optional DeviceProperties::tryPickQueueFamily(const Que return {}; } +const VkPhysicalDeviceMemoryProperties2& DeviceProperties::memoryProperties() { + if(!_state) _state.emplace(); + + if(!_state->memoryProperties.sType) { + _state->memoryProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PROPERTIES_2; + _instance->state().getPhysicalDeviceMemoryPropertiesImplementation(*this, _state->memoryProperties); + } + + return _state->memoryProperties; +} + +void DeviceProperties::getMemoryPropertiesImplementationDefault(DeviceProperties& self, VkPhysicalDeviceMemoryProperties2& properties) { + return (**self._instance).GetPhysicalDeviceMemoryProperties(self._handle, &properties.memoryProperties); +} + +void DeviceProperties::getMemoryPropertiesImplementationKHR(DeviceProperties& self, VkPhysicalDeviceMemoryProperties2& properties) { + return (**self._instance).GetPhysicalDeviceMemoryProperties2KHR(self._handle, &properties); +} + +void DeviceProperties::getMemoryPropertiesImplementation11(DeviceProperties& self, VkPhysicalDeviceMemoryProperties2& properties) { + return (**self._instance).GetPhysicalDeviceMemoryProperties2(self._handle, &properties); +} + +UnsignedInt DeviceProperties::memoryHeapCount() { + return memoryProperties().memoryProperties.memoryHeapCount; +} + +UnsignedLong DeviceProperties::memoryHeapSize(const UnsignedInt heap) { + const VkPhysicalDeviceMemoryProperties& properties = memoryProperties().memoryProperties; + CORRADE_ASSERT(heap < properties.memoryHeapCount, + "Vk::DeviceProperties::memoryHeapSize(): index" << heap << "out of range for" << properties.memoryHeapCount << "memory heaps", {}); + return properties.memoryHeaps[heap].size; +} + +MemoryHeapFlags DeviceProperties::memoryHeapFlags(const UnsignedInt heap) { + const VkPhysicalDeviceMemoryProperties& properties = memoryProperties().memoryProperties; + CORRADE_ASSERT(heap < properties.memoryHeapCount, + "Vk::DeviceProperties::memoryHeapFlags(): index" << heap << "out of range for" << properties.memoryHeapCount << "memory heaps", {}); + return MemoryHeapFlag(properties.memoryHeaps[heap].flags); +} + +UnsignedInt DeviceProperties::memoryCount() { + return memoryProperties().memoryProperties.memoryTypeCount; +} + +MemoryFlags DeviceProperties::memoryFlags(const UnsignedInt memory) { + const VkPhysicalDeviceMemoryProperties& properties = memoryProperties().memoryProperties; + CORRADE_ASSERT(memory < properties.memoryTypeCount, + "Vk::DeviceProperties::memoryFlags(): index" << memory << "out of range for" << properties.memoryTypeCount << "memory types", {}); + return MemoryFlag(properties.memoryTypes[memory].propertyFlags); +} + +UnsignedInt DeviceProperties::memoryHeapIndex(const UnsignedInt memory) { + const VkPhysicalDeviceMemoryProperties& properties = memoryProperties().memoryProperties; + CORRADE_ASSERT(memory < properties.memoryTypeCount, + "Vk::DeviceProperties::memoryHeapIndex(): index" << memory << "out of range for" << properties.memoryTypeCount << "memory types", {}); + return properties.memoryTypes[memory].heapIndex; +} + Containers::Array enumerateDevices(Instance& instance) { /* Retrieve total device count */ UnsignedInt count; @@ -297,4 +357,24 @@ Debug& operator<<(Debug& debug, const QueueFlags value) { Vk::QueueFlag::Protected}); } +Debug& operator<<(Debug& debug, const MemoryHeapFlag value) { + debug << "Vk::MemoryHeapFlag" << Debug::nospace; + + switch(value) { + /* LCOV_EXCL_START */ + #define _c(value) case Vk::MemoryHeapFlag::value: return debug << "::" << Debug::nospace << #value; + _c(DeviceLocal) + #undef _c + /* LCOV_EXCL_STOP */ + } + + /* Flag bits should be in hex, unlike plain values */ + return debug << "(" << Debug::nospace << reinterpret_cast(UnsignedInt(value)) << Debug::nospace << ")"; +} + +Debug& operator<<(Debug& debug, const MemoryHeapFlags value) { + return Containers::enumSetDebugOutput(debug, value, "Vk::MemoryHeapFlags{}", { + Vk::MemoryHeapFlag::DeviceLocal}); +} + }} diff --git a/src/Magnum/Vk/DeviceProperties.h b/src/Magnum/Vk/DeviceProperties.h index ff0a7860a..82e3e0078 100644 --- a/src/Magnum/Vk/DeviceProperties.h +++ b/src/Magnum/Vk/DeviceProperties.h @@ -26,7 +26,7 @@ */ /** @file - * @brief Class @ref Magnum::Vk::DeviceProperties, enum @ref Magnum::Vk::DeviceType, @ref Magnum::Vk::QueueFlag, enum set @ref Magnum::Vk::QueueFlags, function @ref Magnum::Vk::enumerateDevices(), @ref Magnum::Vk::pickDevice(), @ref Magnum::Vk::tryPickDevice() + * @brief Class @ref Magnum::Vk::DeviceProperties, enum @ref Magnum::Vk::DeviceType, @ref Magnum::Vk::QueueFlag, @ref Magnum::Vk::MemoryHeapFlag, enum set @ref Magnum::Vk::QueueFlags, @ref Magnum::Vk::MemoryHeapFlags, function @ref Magnum::Vk::enumerateDevices(), @ref Magnum::Vk::pickDevice(), @ref Magnum::Vk::tryPickDevice() * @m_since_latest */ @@ -128,6 +128,47 @@ CORRADE_ENUMSET_OPERATORS(QueueFlags) */ MAGNUM_VK_EXPORT Debug& operator<<(Debug& debug, QueueFlags value); +/** +@brief Memory heap flag +@m_since_latest + +Wraps a @type_vk_keyword{MemoryHeapFlagBits}. +@see @ref QueueFlags, @ref DeviceProperties::queueFamilyFlags() +@m_enum_values_as_keywords +*/ +enum class MemoryHeapFlag: UnsignedInt { + /** Corresponds to device-local memory */ + DeviceLocal = VK_MEMORY_HEAP_DEVICE_LOCAL_BIT, + + /** @todo MultiInstance, Vk 1.1 */ +}; + +/** +@debugoperatorclassenum{DeviceProperties,MemoryHeapFlag} +@m_since_latest +*/ +MAGNUM_VK_EXPORT Debug& operator<<(Debug& debug, MemoryHeapFlag value); + +/** +@brief Memory heap flags +@m_since_latest + +Type-safe wrapper for @type_vk_keyword{MemoryHeapFlags}. +@see @ref DeviceProperties::memoryHeapFlags(), @ref MemoryFlags +*/ +typedef Containers::EnumSet MemoryHeapFlags; + +CORRADE_ENUMSET_OPERATORS(MemoryHeapFlags) + +/** +@debugoperatorclassenum{DeviceProperties,MemoryHeapFlags} +@m_since_latest +*/ +MAGNUM_VK_EXPORT Debug& operator<<(Debug& debug, MemoryHeapFlags value); + +/* MemoryFlag/MemoryFlags are in Memory.h since those are used mainly in + contexts where DeviceProperties isn't present */ + /** @brief Physical device properties @m_since_latest @@ -311,6 +352,75 @@ class MAGNUM_VK_EXPORT DeviceProperties { */ Containers::Optional tryPickQueueFamily(QueueFlags flags); + /** + * @brief Device memory properties + * + * Populated lazily on first request. If Vulkan 1.1 or the + * @vk_extension{KHR,get_physical_device_properties2} extension is not + * enabled on the originating instance, only the Vulkan 1.0 subset of + * device properties is queried. + * @see @fn_vk_keyword{GetPhysicalDeviceMemoryProperties2}, + * @fn_vk_keyword{GetPhysicalDeviceMemoryProperties} + */ + const VkPhysicalDeviceMemoryProperties2& memoryProperties(); + + /** + * @brief Memory heap count + * + * Convenience access to @ref memoryProperties() internals, populated + * lazily on first request. + */ + UnsignedInt memoryHeapCount(); + + /** + * @brief Memory heap size + * @param heap Memory heap index, expected to be smaller than + * @ref memoryHeapCount() + * + * Convenience access to @ref memoryProperties() internals, populated + * lazily on first request. + */ + UnsignedLong memoryHeapSize(UnsignedInt heap); + + /** + * @brief Memory heap size + * @param heap Memory heap index, expected to be smaller than + * @ref memoryHeapCount() + * + * Convenience access to @ref memoryProperties() internals, populated + * lazily on first request. + */ + MemoryHeapFlags memoryHeapFlags(UnsignedInt heap); + + /** + * @brief Memory type count + * + * Convenience access to @ref memoryProperties() internals, populated + * lazily on first request. + */ + UnsignedInt memoryCount(); + + /** + * @brief Memory type flags + * @param memory Memory type index, expected to be smaller than + * @ref memoryCount() + * + * Convenience access to @ref memoryProperties() internals, populated + * lazily on first request. + */ + MemoryFlags memoryFlags(UnsignedInt memory); + + /** + * @brief Memory heap index + * @param memory Memory type index, expected to be smaller than + * @ref memoryCount() + * @return Memory heap index, always smaller than @ref memoryHeapCount() + * + * Convenience access to @ref memoryProperties() internals, populated + * lazily on first request. + */ + UnsignedInt memoryHeapIndex(UnsignedInt memory); + private: friend Implementation::InstanceState; @@ -331,6 +441,10 @@ class MAGNUM_VK_EXPORT DeviceProperties { MAGNUM_VK_LOCAL static void getQueueFamilyPropertiesImplementationKHR(DeviceProperties& self, UnsignedInt& count, VkQueueFamilyProperties2* properties); MAGNUM_VK_LOCAL static void getQueueFamilyPropertiesImplementation11(DeviceProperties& self, UnsignedInt& count, VkQueueFamilyProperties2* properties); + MAGNUM_VK_LOCAL static void getMemoryPropertiesImplementationDefault(DeviceProperties& self, VkPhysicalDeviceMemoryProperties2& properties); + MAGNUM_VK_LOCAL static void getMemoryPropertiesImplementationKHR(DeviceProperties& self, VkPhysicalDeviceMemoryProperties2& properties); + MAGNUM_VK_LOCAL static void getMemoryPropertiesImplementation11(DeviceProperties& self, VkPhysicalDeviceMemoryProperties2& properties); + /* Can't be a reference because of the NoCreate constructor */ Instance* _instance; diff --git a/src/Magnum/Vk/Implementation/InstanceState.cpp b/src/Magnum/Vk/Implementation/InstanceState.cpp index 1b780ae73..75449384c 100644 --- a/src/Magnum/Vk/Implementation/InstanceState.cpp +++ b/src/Magnum/Vk/Implementation/InstanceState.cpp @@ -35,12 +35,15 @@ InstanceState::InstanceState(Instance& instance, Int argc, const char** argv): a if(instance.isVersionSupported(Version::Vk11)) { getPhysicalDevicePropertiesImplementation = &DeviceProperties::getPropertiesImplementation11; getPhysicalDeviceQueueFamilyPropertiesImplementation = &DeviceProperties::getQueueFamilyPropertiesImplementation11; + getPhysicalDeviceMemoryPropertiesImplementation = &DeviceProperties::getMemoryPropertiesImplementation11; } else if(instance.isExtensionEnabled()) { getPhysicalDevicePropertiesImplementation = &DeviceProperties::getPropertiesImplementationKHR; getPhysicalDeviceQueueFamilyPropertiesImplementation = &DeviceProperties::getQueueFamilyPropertiesImplementationKHR; + getPhysicalDeviceMemoryPropertiesImplementation = &DeviceProperties::getMemoryPropertiesImplementationKHR; } else { getPhysicalDevicePropertiesImplementation = DeviceProperties::getPropertiesImplementationDefault; getPhysicalDeviceQueueFamilyPropertiesImplementation = &DeviceProperties::getQueueFamilyPropertiesImplementationDefault; + getPhysicalDeviceMemoryPropertiesImplementation = &DeviceProperties::getMemoryPropertiesImplementationDefault; } } diff --git a/src/Magnum/Vk/Implementation/InstanceState.h b/src/Magnum/Vk/Implementation/InstanceState.h index 04ff8b61d..b6821ea7f 100644 --- a/src/Magnum/Vk/Implementation/InstanceState.h +++ b/src/Magnum/Vk/Implementation/InstanceState.h @@ -38,6 +38,7 @@ struct InstanceState { void(*getPhysicalDevicePropertiesImplementation)(DeviceProperties&, VkPhysicalDeviceProperties2&); void(*getPhysicalDeviceQueueFamilyPropertiesImplementation)(DeviceProperties&, UnsignedInt&, VkQueueFamilyProperties2*); + void(*getPhysicalDeviceMemoryPropertiesImplementation)(DeviceProperties&, VkPhysicalDeviceMemoryProperties2&); }; }}} diff --git a/src/Magnum/Vk/Memory.cpp b/src/Magnum/Vk/Memory.cpp new file mode 100644 index 000000000..f53b372ad --- /dev/null +++ b/src/Magnum/Vk/Memory.cpp @@ -0,0 +1,61 @@ +/* + 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 "Memory.h" + +#include +#include + +namespace Magnum { namespace Vk { + +Debug& operator<<(Debug& debug, const MemoryFlag value) { + debug << "Vk::MemoryFlag" << Debug::nospace; + + switch(value) { + /* LCOV_EXCL_START */ + #define _c(value) case Vk::MemoryFlag::value: return debug << "::" << Debug::nospace << #value; + _c(DeviceLocal) + _c(HostVisible) + _c(HostCoherent) + _c(HostCached) + _c(LazilyAllocated) + #undef _c + /* LCOV_EXCL_STOP */ + } + + /* Flag bits should be in hex, unlike plain values */ + return debug << "(" << Debug::nospace << reinterpret_cast(UnsignedInt(value)) << Debug::nospace << ")"; +} + +Debug& operator<<(Debug& debug, const MemoryFlags value) { + return Containers::enumSetDebugOutput(debug, value, "Vk::MemoryFlags{}", { + Vk::MemoryFlag::DeviceLocal, + Vk::MemoryFlag::HostVisible, + Vk::MemoryFlag::HostCoherent, + Vk::MemoryFlag::HostCached, + Vk::MemoryFlag::LazilyAllocated}); +} + +}} diff --git a/src/Magnum/Vk/Memory.h b/src/Magnum/Vk/Memory.h new file mode 100644 index 000000000..751ab2ddf --- /dev/null +++ b/src/Magnum/Vk/Memory.h @@ -0,0 +1,114 @@ +#ifndef Magnum_Vk_Memory_h +#define Magnum_Vk_Memory_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 Enum @ref Magnum::Vk::MemoryFlag, enum set @ref Magnum::Vk::MemoryFlags + */ + +#include + +#include "Magnum/Magnum.h" +#include "Magnum/Vk/Vulkan.h" +#include "Magnum/Vk/visibility.h" + +namespace Magnum { namespace Vk { + +/** +@brief Memory type flag +@m_since_latest + +Wraps a @type_vk_keyword{MemoryPropertyFlagBits}. +@see @ref MemoryFlags, @ref DeviceProperties::memoryFlags() +@m_enum_values_as_keywords +*/ +enum class MemoryFlag: UnsignedInt { + /** + * Device local. Always corresponds to a heap with + * @ref MemoryHeapFlag::DeviceLocal. + * + * @m_class{m-note m-success} + * + * @par + * This memory is the most efficient for device access. + */ + DeviceLocal = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, + + /** Memory that can be mapped for host access */ + HostVisible = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, + + /** Memory with coherent access on the host */ + HostCoherent = VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, + + /** + * Memory that is cached on the host. Host memory accesses to uncached + * memory are slower than to cached memory, however uncached memory is + * always @ref MemoryFlag::HostCoherent. + */ + HostCached = VK_MEMORY_PROPERTY_HOST_CACHED_BIT, + + /** + * Lazily allocated memory. Allows only device access (i.e., there's no + * memory that has both this and @ref MemoryFlag::HostVisible set). + * + * @m_class{m-note m-success} + * + * @par + * The device is allowed (but not required) to allocate the memory + * as-needed and thus is useful for example for temporary framebuffer + * attachments --- certain tiled architectures might not even need to + * allocate the memory in that case. + */ + LazilyAllocated = VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT, + + /** @todo Protected, VK 1.1 */ +}; + +/** +@debugoperatorclassenum{DeviceProperties,MemoryFlag} +@m_since_latest +*/ +MAGNUM_VK_EXPORT Debug& operator<<(Debug& debug, MemoryFlag value); + +/** +@brief Memory type flags +@m_since_latest + +@see @ref DeviceProperties::memoryFlags() +*/ +typedef Containers::EnumSet MemoryFlags; + +CORRADE_ENUMSET_OPERATORS(MemoryFlags) + +/** +@debugoperatorclassenum{DeviceProperties,MemoryFlags} +@m_since_latest +*/ +MAGNUM_VK_EXPORT Debug& operator<<(Debug& debug, MemoryFlags value); + +}} + +#endif diff --git a/src/Magnum/Vk/Test/CMakeLists.txt b/src/Magnum/Vk/Test/CMakeLists.txt index f65e42b55..06eee16fe 100644 --- a/src/Magnum/Vk/Test/CMakeLists.txt +++ b/src/Magnum/Vk/Test/CMakeLists.txt @@ -35,6 +35,7 @@ corrade_add_test(VkHandleTest HandleTest.cpp LIBRARIES MagnumVk) corrade_add_test(VkInstanceTest InstanceTest.cpp LIBRARIES MagnumVk) corrade_add_test(VkIntegrationTest IntegrationTest.cpp LIBRARIES MagnumVk) corrade_add_test(VkLayerPropertiesTest LayerPropertiesTest.cpp LIBRARIES MagnumVk) +corrade_add_test(VkMemoryTest MemoryTest.cpp LIBRARIES MagnumVk) corrade_add_test(VkResultTest ResultTest.cpp LIBRARIES MagnumVk) corrade_add_test(VkVersionTest VersionTest.cpp LIBRARIES MagnumVk) diff --git a/src/Magnum/Vk/Test/DevicePropertiesTest.cpp b/src/Magnum/Vk/Test/DevicePropertiesTest.cpp index 4cce9baba..72f09eefc 100644 --- a/src/Magnum/Vk/Test/DevicePropertiesTest.cpp +++ b/src/Magnum/Vk/Test/DevicePropertiesTest.cpp @@ -40,6 +40,8 @@ struct DevicePropertiesTest: TestSuite::Tester { void debugDeviceType(); void debugQueueFamilyPropertiesFlag(); void debugQueueFamilyPropertiesFlags(); + void debugMemoryHeapFlag(); + void debugMemoryHeapFlags(); }; DevicePropertiesTest::DevicePropertiesTest() { @@ -48,7 +50,9 @@ DevicePropertiesTest::DevicePropertiesTest() { &DevicePropertiesTest::debugDeviceType, &DevicePropertiesTest::debugQueueFamilyPropertiesFlag, - &DevicePropertiesTest::debugQueueFamilyPropertiesFlags}); + &DevicePropertiesTest::debugQueueFamilyPropertiesFlags, + &DevicePropertiesTest::debugMemoryHeapFlag, + &DevicePropertiesTest::debugMemoryHeapFlags}); } void DevicePropertiesTest::constructNoCreate() { @@ -84,6 +88,18 @@ void DevicePropertiesTest::debugQueueFamilyPropertiesFlags() { CORRADE_COMPARE(out.str(), "Vk::QueueFlag::Graphics|Vk::QueueFlag::Compute Vk::QueueFlags{}\n"); } +void DevicePropertiesTest::debugMemoryHeapFlag() { + std::ostringstream out; + Debug{&out} << MemoryHeapFlag::DeviceLocal << MemoryHeapFlag(0xdeadcafe); + CORRADE_COMPARE(out.str(), "Vk::MemoryHeapFlag::DeviceLocal Vk::MemoryHeapFlag(0xdeadcafe)\n"); +} + +void DevicePropertiesTest::debugMemoryHeapFlags() { + std::ostringstream out; + Debug{&out} << (MemoryHeapFlag::DeviceLocal|MemoryHeapFlag(0xf0)) << MemoryHeapFlags{}; + CORRADE_COMPARE(out.str(), "Vk::MemoryHeapFlag::DeviceLocal|Vk::MemoryHeapFlag(0xf0) Vk::MemoryHeapFlags{}\n"); +} + }}}} CORRADE_TEST_MAIN(Magnum::Vk::Test::DevicePropertiesTest) diff --git a/src/Magnum/Vk/Test/DevicePropertiesVkTest.cpp b/src/Magnum/Vk/Test/DevicePropertiesVkTest.cpp index 76f230d28..16aeba0e6 100644 --- a/src/Magnum/Vk/Test/DevicePropertiesVkTest.cpp +++ b/src/Magnum/Vk/Test/DevicePropertiesVkTest.cpp @@ -37,6 +37,7 @@ #include "Magnum/Vk/ExtensionProperties.h" #include "Magnum/Vk/Instance.h" #include "Magnum/Vk/LayerProperties.h" +#include "Magnum/Vk/Memory.h" #include "Magnum/Vk/Result.h" #include "Magnum/Vk/Version.h" #include "Magnum/Vk/VulkanTester.h" @@ -65,6 +66,12 @@ struct DevicePropertiesVkTest: VulkanTester { void queueFamiliesPick(); void queueFamiliesPickFailed(); + void memoryHeaps(); + void memoryHeapOutOfRange(); + + void memoryTypes(); + void memoryTypeOutOfRange(); + void pickDevice(); void pickDeviceIndex(); void pickDeviceType(); @@ -102,6 +109,12 @@ DevicePropertiesVkTest::DevicePropertiesVkTest(): VulkanTester{NoCreate} { &DevicePropertiesVkTest::queueFamiliesPick, &DevicePropertiesVkTest::queueFamiliesPickFailed, + &DevicePropertiesVkTest::memoryHeaps, + &DevicePropertiesVkTest::memoryHeapOutOfRange, + + &DevicePropertiesVkTest::memoryTypes, + &DevicePropertiesVkTest::memoryTypeOutOfRange, + &DevicePropertiesVkTest::pickDevice, &DevicePropertiesVkTest::pickDeviceIndex, &DevicePropertiesVkTest::pickDeviceType}); @@ -325,6 +338,95 @@ void DevicePropertiesVkTest::queueFamiliesPickFailed() { "Vk::DeviceProperties::tryPickQueueFamily(): no Vk::QueueFlag(0xc0ffeee0) found among {} queue families\n", devices[0].queueFamilyCount())); } +void DevicePropertiesVkTest::memoryHeaps() { + Containers::Array devices = enumerateDevices(instance()); + CORRADE_VERIFY(!devices.empty()); + + Debug{} << "Available memory heap count:" << devices[0].memoryHeapCount(); + + CORRADE_COMPARE_AS(devices[0].memoryHeapCount(), 0, + TestSuite::Compare::Greater); + + bool atLeastOneDeviceLocal = false; + for(std::size_t i = 0; i != devices[0].memoryHeapCount(); ++i) { + CORRADE_ITERATION(i); + CORRADE_ITERATION(devices[0].memoryHeapFlags(i)); + + if(devices[0].memoryHeapFlags(i) & MemoryHeapFlag::DeviceLocal) + atLeastOneDeviceLocal = true; + + /* A heap should have at least 64 MB (more like at least 512 MB + nowadays but let's be conservative) */ + CORRADE_COMPARE_AS(devices[0].memoryHeapSize(i), std::size_t{1024*1024*64}, + TestSuite::Compare::Greater); + } + + CORRADE_VERIFY(atLeastOneDeviceLocal); +} + +void DevicePropertiesVkTest::memoryHeapOutOfRange() { + #ifdef CORRADE_NO_ASSERT + CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions"); + #endif + + Containers::Array devices = enumerateDevices(instance()); + CORRADE_VERIFY(!devices.empty()); + + const UnsignedInt count = devices[0].memoryHeapCount(); + + std::ostringstream out; + Error redirectError{&out}; + devices[0].memoryHeapSize(count); + devices[0].memoryHeapFlags(count); + CORRADE_COMPARE(out.str(), Utility::formatString( + "Vk::DeviceProperties::memoryHeapSize(): index {0} out of range for {0} memory heaps\n" + "Vk::DeviceProperties::memoryHeapFlags(): index {0} out of range for {0} memory heaps\n", count)); +} + +void DevicePropertiesVkTest::memoryTypes() { + Containers::Array devices = enumerateDevices(instance()); + CORRADE_VERIFY(!devices.empty()); + + Debug{} << "Available memory type count:" << devices[0].memoryCount(); + + CORRADE_COMPARE_AS(devices[0].memoryCount(), 0, + TestSuite::Compare::Greater); + + bool atLeastOneDeviceLocal = false; + for(std::size_t i = 0; i != devices[0].memoryCount(); ++i) { + CORRADE_ITERATION(i); + CORRADE_ITERATION(devices[0].memoryFlags(i)); + + if(devices[0].memoryFlags(i) & MemoryFlag::DeviceLocal) + atLeastOneDeviceLocal = true; + + /* Heap index should be in range */ + CORRADE_COMPARE_AS(devices[0].memoryHeapIndex(i), devices[0].memoryHeapCount(), + TestSuite::Compare::Less); + } + + CORRADE_VERIFY(atLeastOneDeviceLocal); +} + +void DevicePropertiesVkTest::memoryTypeOutOfRange() { + #ifdef CORRADE_NO_ASSERT + CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions"); + #endif + + Containers::Array devices = enumerateDevices(instance()); + CORRADE_VERIFY(!devices.empty()); + + const UnsignedInt count = devices[0].memoryCount(); + + std::ostringstream out; + Error redirectError{&out}; + devices[0].memoryFlags(count); + devices[0].memoryHeapIndex(count); + CORRADE_COMPARE(out.str(), Utility::formatString( + "Vk::DeviceProperties::memoryFlags(): index {0} out of range for {0} memory types\n" + "Vk::DeviceProperties::memoryHeapIndex(): index {0} out of range for {0} memory types\n", count)); +} + void DevicePropertiesVkTest::pickDevice() { /* Default behavior */ Containers::Optional device = tryPickDevice(instance()); diff --git a/src/Magnum/Vk/Test/MemoryTest.cpp b/src/Magnum/Vk/Test/MemoryTest.cpp new file mode 100644 index 000000000..c7440eec0 --- /dev/null +++ b/src/Magnum/Vk/Test/MemoryTest.cpp @@ -0,0 +1,60 @@ +/* + 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 + +#include "Magnum/Vk/Memory.h" + +namespace Magnum { namespace Vk { namespace Test { namespace { + +struct MemoryTest: TestSuite::Tester { + explicit MemoryTest(); + + void debugMemoryFlag(); + void debugMemoryFlags(); +}; + +MemoryTest::MemoryTest() { + addTests({&MemoryTest::debugMemoryFlag, + &MemoryTest::debugMemoryFlags}); +} + +void MemoryTest::debugMemoryFlag() { + std::ostringstream out; + Debug{&out} << MemoryFlag::HostCached << MemoryFlag(0xdeadcafe); + CORRADE_COMPARE(out.str(), "Vk::MemoryFlag::HostCached Vk::MemoryFlag(0xdeadcafe)\n"); +} + +void MemoryTest::debugMemoryFlags() { + std::ostringstream out; + Debug{&out} << (MemoryFlag::HostCached|MemoryFlag::LazilyAllocated) << MemoryFlags{}; + CORRADE_COMPARE(out.str(), "Vk::MemoryFlag::HostCached|Vk::MemoryFlag::LazilyAllocated Vk::MemoryFlags{}\n"); +} + +}}}} + +CORRADE_TEST_MAIN(Magnum::Vk::Test::MemoryTest) diff --git a/src/Magnum/Vk/Vk.h b/src/Magnum/Vk/Vk.h index 57138970e..51afdd2a2 100644 --- a/src/Magnum/Vk/Vk.h +++ b/src/Magnum/Vk/Vk.h @@ -51,6 +51,10 @@ class InstanceCreateInfo; class InstanceExtension; class InstanceExtensionProperties; class LayerProperties; +enum class MemoryFlag: UnsignedInt; +typedef Containers::EnumSet MemoryFlags; +enum class MemoryHeapFlag: UnsignedInt; +typedef Containers::EnumSet MemoryHeapFlags; class Queue; enum class QueueFlag: UnsignedInt; typedef Containers::EnumSet QueueFlags;