diff --git a/doc/vulkan-mapping.dox b/doc/vulkan-mapping.dox index 5686fd3c4..aa91d1dde 100644 --- a/doc/vulkan-mapping.dox +++ b/doc/vulkan-mapping.dox @@ -197,7 +197,7 @@ Vulkan function | Matching API @fn_vk{GetDeviceQueue}, \n @fn_vk{GetDeviceQueue2} @m_class{m-label m-flat m-success} **1.1** | @ref Device constructor @fn_vk{GetEventStatus} | | @fn_vk{GetFenceStatus} | | -@fn_vk{GetImageMemoryRequirements}, \n @fn_vk{GetImageMemoryRequirements2} @m_class{m-label m-flat m-success} **KHR, 1.1** | | +@fn_vk{GetImageMemoryRequirements}, \n @fn_vk{GetImageMemoryRequirements2} @m_class{m-label m-flat m-success} **KHR, 1.1** | @ref Image::memoryRequirements() @fn_vk{GetImageSparseMemoryRequirements}, \n @fn_vk{GetImageSparseMemoryRequirements2} @m_class{m-label m-flat m-success} **KHR, 1.1** | | @fn_vk{GetImageSubresourceLayout} | | @fn_vk{GetInstanceProcAddr} | @ref Instance constructor @@ -329,6 +329,7 @@ Vulkan structure | Matching API Vulkan structure | Matching API --------------------------------------- | ------------ @type_vk{ImageCreateInfo} | @ref ImageCreateInfo +@type_vk{ImageMemoryRequirementsInfo} | not exposed, internal to @ref Image::memoryRequirements() @type_vk{InstanceCreateInfo} | @ref InstanceCreateInfo */ diff --git a/src/Magnum/Vk/DeviceProperties.h b/src/Magnum/Vk/DeviceProperties.h index 7e82e348d..a690d67dd 100644 --- a/src/Magnum/Vk/DeviceProperties.h +++ b/src/Magnum/Vk/DeviceProperties.h @@ -434,8 +434,8 @@ class MAGNUM_VK_EXPORT DeviceProperties { * should be considered etc.). Expected to have at least one bit * of the first @ref memoryCount() bits set, otherwise the * function will always fail. Defaults to all bits set, meaning - * all memory types are considered. Corresponds to the - * `memoryTypeBits` field of @type_vk{MemoryRequirements}. + * all memory types are considered. Corresponds to + * @ref MemoryRequirements::memories(). * * Queries memory properties using @ref memoryProperties() and out of * memory types set in @p memoryBits tries to find one that contains diff --git a/src/Magnum/Vk/Image.cpp b/src/Magnum/Vk/Image.cpp index cd9a81934..0ffc09e99 100644 --- a/src/Magnum/Vk/Image.cpp +++ b/src/Magnum/Vk/Image.cpp @@ -28,7 +28,9 @@ #include "Magnum/Vk/Device.h" #include "Magnum/Vk/Handle.h" #include "Magnum/Vk/Integration.h" +#include "Magnum/Vk/Memory.h" #include "Magnum/Vk/Result.h" +#include "Magnum/Vk/Implementation/DeviceState.h" namespace Magnum { namespace Vk { @@ -96,10 +98,31 @@ Image& Image::operator=(Image&& other) noexcept { return *this; } +MemoryRequirements Image::memoryRequirements() const { + MemoryRequirements requirements; + VkImageMemoryRequirementsInfo2 info{}; + info.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2; + info.image = _handle; + _device->state().getImageMemoryRequirementsImplementation(*_device, info, requirements); + return requirements; +} + VkImage Image::release() { const VkImage handle = _handle; _handle = {}; return handle; } +void Image::getMemoryRequirementsImplementationDefault(Device& device, const VkImageMemoryRequirementsInfo2& info, VkMemoryRequirements2& requirements) { + device->GetImageMemoryRequirements(device, info.image, &requirements.memoryRequirements); +} + +void Image::getMemoryRequirementsImplementationKHR(Device& device, const VkImageMemoryRequirementsInfo2& info, VkMemoryRequirements2& requirements) { + device->GetImageMemoryRequirements2KHR(device, &info, &requirements); +} + +void Image::getMemoryRequirementsImplementation11(Device& device, const VkImageMemoryRequirementsInfo2& info, VkMemoryRequirements2& requirements) { + device->GetImageMemoryRequirements2(device, &info, &requirements); +} + }} diff --git a/src/Magnum/Vk/Image.h b/src/Magnum/Vk/Image.h index cbc314887..776cc8f00 100644 --- a/src/Magnum/Vk/Image.h +++ b/src/Magnum/Vk/Image.h @@ -41,6 +41,8 @@ namespace Magnum { namespace Vk { +namespace Implementation { struct DeviceState; } + /** @brief Image usage @m_since_latest @@ -395,6 +397,14 @@ class MAGNUM_VK_EXPORT Image { /** @brief Handle flags */ HandleFlags handleFlags() const { return _flags; } + /** + * @brief Image memory requirements + * + * @see @fn_vk_keyword{GetImageMemoryRequirements2}, + * @fn_vk_keyword{GetImageMemoryRequirements} + */ + MemoryRequirements memoryRequirements() const; + /** * @brief Release the underlying Vulkan image * @@ -406,6 +416,12 @@ class MAGNUM_VK_EXPORT Image { VkImage release(); private: + friend Implementation::DeviceState; + + MAGNUM_VK_LOCAL static void getMemoryRequirementsImplementationDefault(Device& device, const VkImageMemoryRequirementsInfo2& info, VkMemoryRequirements2& requirements); + MAGNUM_VK_LOCAL static void getMemoryRequirementsImplementationKHR(Device& device, const VkImageMemoryRequirementsInfo2& info, VkMemoryRequirements2& requirements); + MAGNUM_VK_LOCAL static void getMemoryRequirementsImplementation11(Device& device, const VkImageMemoryRequirementsInfo2& info, VkMemoryRequirements2& requirements); + /* Can't be a reference because of the NoCreate constructor */ Device* _device; diff --git a/src/Magnum/Vk/Implementation/DeviceState.cpp b/src/Magnum/Vk/Implementation/DeviceState.cpp index 79d481606..b6fd25e04 100644 --- a/src/Magnum/Vk/Implementation/DeviceState.cpp +++ b/src/Magnum/Vk/Implementation/DeviceState.cpp @@ -26,6 +26,8 @@ #include "DeviceState.h" #include "Magnum/Vk/Device.h" +#include "Magnum/Vk/Extensions.h" +#include "Magnum/Vk/Image.h" #include "Magnum/Vk/Version.h" namespace Magnum { namespace Vk { namespace Implementation { @@ -36,6 +38,14 @@ DeviceState::DeviceState(Device& device) { } else { getDeviceQueueImplementation = &Device::getQueueImplementationDefault; } + + if(device.isVersionSupported(Version::Vk11)) { + getImageMemoryRequirementsImplementation = &Image::getMemoryRequirementsImplementation11; + } else if(device.isExtensionEnabled()) { + getImageMemoryRequirementsImplementation = &Image::getMemoryRequirementsImplementationKHR; + } else { + getImageMemoryRequirementsImplementation = &Image::getMemoryRequirementsImplementationDefault; + } } }}} diff --git a/src/Magnum/Vk/Implementation/DeviceState.h b/src/Magnum/Vk/Implementation/DeviceState.h index e35075626..446f1f0ef 100644 --- a/src/Magnum/Vk/Implementation/DeviceState.h +++ b/src/Magnum/Vk/Implementation/DeviceState.h @@ -34,6 +34,8 @@ struct DeviceState { explicit DeviceState(Device& instance); void(*getDeviceQueueImplementation)(Device&, const VkDeviceQueueInfo2&, VkQueue&); + /** @todo put this eventually into a dedicated image state struct? */ + void(*getImageMemoryRequirementsImplementation)(Device&, const VkImageMemoryRequirementsInfo2&, VkMemoryRequirements2&); }; }}} diff --git a/src/Magnum/Vk/Memory.cpp b/src/Magnum/Vk/Memory.cpp index f53b372ad..44b1a1be6 100644 --- a/src/Magnum/Vk/Memory.cpp +++ b/src/Magnum/Vk/Memory.cpp @@ -30,6 +30,17 @@ namespace Magnum { namespace Vk { +MemoryRequirements::MemoryRequirements(): _requirements{} { + _requirements.sType = VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2; +} + +MemoryRequirements::MemoryRequirements(NoInitT) noexcept {} + +MemoryRequirements::MemoryRequirements(const VkMemoryRequirements2& requirements): + /* Can't use {} with GCC 4.8 here because it tries to initialize the first + member instead of doing a copy */ + _requirements(requirements) {} + Debug& operator<<(Debug& debug, const MemoryFlag value) { debug << "Vk::MemoryFlag" << Debug::nospace; diff --git a/src/Magnum/Vk/Memory.h b/src/Magnum/Vk/Memory.h index 751ab2ddf..12f56ef33 100644 --- a/src/Magnum/Vk/Memory.h +++ b/src/Magnum/Vk/Memory.h @@ -26,12 +26,14 @@ */ /** @file - * @brief Enum @ref Magnum::Vk::MemoryFlag, enum set @ref Magnum::Vk::MemoryFlags + * @brief Class @ref Magnum::Vk::MemoryRequirements, enum @ref Magnum::Vk::MemoryFlag, enum set @ref Magnum::Vk::MemoryFlags */ #include #include "Magnum/Magnum.h" +#include "Magnum/Tags.h" +#include "Magnum/Vk/Vk.h" #include "Magnum/Vk/Vulkan.h" #include "Magnum/Vk/visibility.h" @@ -109,6 +111,69 @@ CORRADE_ENUMSET_OPERATORS(MemoryFlags) */ MAGNUM_VK_EXPORT Debug& operator<<(Debug& debug, MemoryFlags value); +/** +@brief Device memory requirements +@m_since_latest + +Wraps a @type_vk_keyword{MemoryRequirements2}. Not constructible directly, +returned from @ref Image::memoryRequirements(). +@see @ref DeviceProperties::pickMemory() +*/ +class MAGNUM_VK_EXPORT MemoryRequirements { + public: + /** + * @brief Construct without initializing the contents + * + * Note that not even the `sType` field is set --- the structure has to + * be fully initialized afterwards in order to be usable. + */ + explicit MemoryRequirements(NoInitT) noexcept; + + /** + * @brief Construct from existing data + * + * Copies the existing values verbatim, pointers are kept unchanged + * without taking over the ownership. Modifying the newly created + * instance will not modify the original data nor the pointed-to data. + */ + explicit MemoryRequirements(const VkMemoryRequirements2& requirements); + + /** @brief Underlying @type_vk{MemoryRequirements} structure */ + VkMemoryRequirements2& requirements() { return _requirements; } + /** @overload */ + const VkMemoryRequirements2& requirements() const { return _requirements; } + /** @overload */ + operator VkMemoryRequirements2&() { return _requirements; } + /** @overload */ + operator const VkMemoryRequirements2&() const { return _requirements; } + /** @overload */ + VkMemoryRequirements2* operator->() { return &_requirements; } + /** @overload */ + const VkMemoryRequirements2* operator->() const { return &_requirements; } + + /** @brief Required memory size */ + UnsignedLong size() const { + return _requirements.memoryRequirements.size; + } + + /** @brief Required memory alignment */ + UnsignedLong alignment() const { + return _requirements.memoryRequirements.alignment; + } + + /** @brief Bits indicating which memory */ + UnsignedInt memories() const { + return _requirements.memoryRequirements.memoryTypeBits; + } + + private: + friend Image; + + explicit MemoryRequirements(); + + VkMemoryRequirements2 _requirements; +}; + }} #endif diff --git a/src/Magnum/Vk/Test/ImageVkTest.cpp b/src/Magnum/Vk/Test/ImageVkTest.cpp index 30b2f3e95..01043d635 100644 --- a/src/Magnum/Vk/Test/ImageVkTest.cpp +++ b/src/Magnum/Vk/Test/ImageVkTest.cpp @@ -23,8 +23,9 @@ DEALINGS IN THE SOFTWARE. */ -#include "Magnum/Vk/Image.h" #include "Magnum/Vk/Handle.h" +#include "Magnum/Vk/Image.h" +#include "Magnum/Vk/Memory.h" #include "Magnum/Vk/Result.h" #include "Magnum/Vk/VulkanTester.h" @@ -43,6 +44,8 @@ struct ImageVkTest: VulkanTester { void constructMove(); void wrap(); + + void memoryRequirements(); }; ImageVkTest::ImageVkTest() { @@ -55,7 +58,9 @@ ImageVkTest::ImageVkTest() { &ImageVkTest::constructCubeMapArray, &ImageVkTest::constructMove, - &ImageVkTest::wrap}); + &ImageVkTest::wrap, + + &ImageVkTest::memoryRequirements}); } void ImageVkTest::construct1D() { @@ -180,6 +185,16 @@ void ImageVkTest::wrap() { device()->DestroyImage(device(), image, nullptr); } +void ImageVkTest::memoryRequirements() { + /* Use linear tiling for a deterministic memory size */ + ImageCreateInfo2D info{ImageUsage::Sampled, VK_FORMAT_R8G8B8A8_UNORM, {128, 64}, 1}; + info->tiling = VK_IMAGE_TILING_LINEAR; + Image image{device(), info, NoAllocate}; + + MemoryRequirements requirements = image.memoryRequirements(); + CORRADE_COMPARE(requirements.size(), 128*64*4); +} + }}}} CORRADE_TEST_MAIN(Magnum::Vk::Test::ImageVkTest) diff --git a/src/Magnum/Vk/Test/MemoryTest.cpp b/src/Magnum/Vk/Test/MemoryTest.cpp index c7440eec0..d19e1052b 100644 --- a/src/Magnum/Vk/Test/MemoryTest.cpp +++ b/src/Magnum/Vk/Test/MemoryTest.cpp @@ -34,15 +34,41 @@ namespace Magnum { namespace Vk { namespace Test { namespace { struct MemoryTest: TestSuite::Tester { explicit MemoryTest(); + void requirementsConstructNoInit(); + void requirementsConstructFromVk(); + void debugMemoryFlag(); void debugMemoryFlags(); }; MemoryTest::MemoryTest() { - addTests({&MemoryTest::debugMemoryFlag, + addTests({&MemoryTest::requirementsConstructNoInit, + &MemoryTest::requirementsConstructFromVk, + + &MemoryTest::debugMemoryFlag, &MemoryTest::debugMemoryFlags}); } +void MemoryTest::requirementsConstructNoInit() { + MemoryRequirements requirements{NoInit}; + requirements->sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; + new(&requirements) MemoryRequirements{NoInit}; + CORRADE_COMPARE(requirements->sType, VK_STRUCTURE_TYPE_APPLICATION_INFO); + + CORRADE_VERIFY((std::is_nothrow_constructible::value)); + + /* Implicit construction is not allowed */ + CORRADE_VERIFY(!(std::is_convertible::value)); +} + +void MemoryTest::requirementsConstructFromVk() { + VkMemoryRequirements2 vkRequirements; + vkRequirements.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; + + MemoryRequirements requirements{vkRequirements}; + CORRADE_COMPARE(requirements->sType, VK_STRUCTURE_TYPE_APPLICATION_INFO); +} + void MemoryTest::debugMemoryFlag() { std::ostringstream out; Debug{&out} << MemoryFlag::HostCached << MemoryFlag(0xdeadcafe); diff --git a/src/Magnum/Vk/Vk.h b/src/Magnum/Vk/Vk.h index b3bfe970c..f942fc453 100644 --- a/src/Magnum/Vk/Vk.h +++ b/src/Magnum/Vk/Vk.h @@ -52,6 +52,7 @@ class InstanceCreateInfo; class InstanceExtension; class InstanceExtensionProperties; class LayerProperties; +class MemoryRequirements; enum class MemoryFlag: UnsignedInt; typedef Containers::EnumSet MemoryFlags; enum class MemoryHeapFlag: UnsignedInt;