Browse Source

Vk: querying device memory heaps and types.

Memory type flags are put into a new, separate Memory.h header as those
will be needed more often than the (ever-growing) DeviceProperties --
from Image and Buffer constructors, in particular.
pull/234/head
Vladimír Vondruš 6 years ago
parent
commit
a4d906de86
  1. 2
      doc/vulkan-mapping.dox
  2. 2
      src/Magnum/Vk/CMakeLists.txt
  3. 80
      src/Magnum/Vk/DeviceProperties.cpp
  4. 116
      src/Magnum/Vk/DeviceProperties.h
  5. 3
      src/Magnum/Vk/Implementation/InstanceState.cpp
  6. 1
      src/Magnum/Vk/Implementation/InstanceState.h
  7. 61
      src/Magnum/Vk/Memory.cpp
  8. 114
      src/Magnum/Vk/Memory.h
  9. 1
      src/Magnum/Vk/Test/CMakeLists.txt
  10. 18
      src/Magnum/Vk/Test/DevicePropertiesTest.cpp
  11. 102
      src/Magnum/Vk/Test/DevicePropertiesVkTest.cpp
  12. 60
      src/Magnum/Vk/Test/MemoryTest.cpp
  13. 4
      src/Magnum/Vk/Vk.h

2
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** | |

2
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

80
src/Magnum/Vk/DeviceProperties.cpp

@ -43,6 +43,7 @@ namespace Magnum { namespace Vk {
struct DeviceProperties::State {
VkPhysicalDeviceProperties2 properties{};
VkPhysicalDeviceMemoryProperties2 memoryProperties{};
Containers::Array<VkQueueFamilyProperties2> queueFamilyProperties;
};
@ -176,6 +177,65 @@ Containers::Optional<UnsignedInt> 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<DeviceProperties> 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<void*>(UnsignedInt(value)) << Debug::nospace << ")";
}
Debug& operator<<(Debug& debug, const MemoryHeapFlags value) {
return Containers::enumSetDebugOutput(debug, value, "Vk::MemoryHeapFlags{}", {
Vk::MemoryHeapFlag::DeviceLocal});
}
}}

116
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<MemoryHeapFlag> 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<UnsignedInt> 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;

3
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<Extensions::KHR::get_physical_device_properties2>()) {
getPhysicalDevicePropertiesImplementation = &DeviceProperties::getPropertiesImplementationKHR;
getPhysicalDeviceQueueFamilyPropertiesImplementation = &DeviceProperties::getQueueFamilyPropertiesImplementationKHR;
getPhysicalDeviceMemoryPropertiesImplementation = &DeviceProperties::getMemoryPropertiesImplementationKHR;
} else {
getPhysicalDevicePropertiesImplementation = DeviceProperties::getPropertiesImplementationDefault;
getPhysicalDeviceQueueFamilyPropertiesImplementation = &DeviceProperties::getQueueFamilyPropertiesImplementationDefault;
getPhysicalDeviceMemoryPropertiesImplementation = &DeviceProperties::getMemoryPropertiesImplementationDefault;
}
}

1
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&);
};
}}}

61
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š <mosra@centrum.cz>
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 <Corrade/Containers/EnumSet.hpp>
#include <Corrade/Utility/Debug.h>
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<void*>(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});
}
}}

114
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š <mosra@centrum.cz>
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 <Corrade/Containers/EnumSet.h>
#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<MemoryFlag> MemoryFlags;
CORRADE_ENUMSET_OPERATORS(MemoryFlags)
/**
@debugoperatorclassenum{DeviceProperties,MemoryFlags}
@m_since_latest
*/
MAGNUM_VK_EXPORT Debug& operator<<(Debug& debug, MemoryFlags value);
}}
#endif

1
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)

18
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)

102
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<DeviceProperties> 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<DeviceProperties> 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<DeviceProperties> 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<DeviceProperties> 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<DeviceProperties> device = tryPickDevice(instance());

60
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š <mosra@centrum.cz>
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 <sstream>
#include <Corrade/TestSuite/Tester.h>
#include <Corrade/Utility/DebugStl.h>
#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)

4
src/Magnum/Vk/Vk.h

@ -51,6 +51,10 @@ class InstanceCreateInfo;
class InstanceExtension;
class InstanceExtensionProperties;
class LayerProperties;
enum class MemoryFlag: UnsignedInt;
typedef Containers::EnumSet<MemoryFlag> MemoryFlags;
enum class MemoryHeapFlag: UnsignedInt;
typedef Containers::EnumSet<MemoryHeapFlag> MemoryHeapFlags;
class Queue;
enum class QueueFlag: UnsignedInt;
typedef Containers::EnumSet<QueueFlag> QueueFlags;

Loading…
Cancel
Save