From 086f531f1709f6077497e2578b8a02e802c2f801 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Wed, 18 Nov 2020 20:01:32 +0100 Subject: [PATCH] Vk: binding Buffer memory. Again basically the same as with Image. --- src/Magnum/Vk/Buffer.cpp | 47 ++++++++++++++-- src/Magnum/Vk/Buffer.h | 45 +++++++++++++++- src/Magnum/Vk/CMakeLists.txt | 2 +- src/Magnum/Vk/Implementation/DeviceState.cpp | 3 ++ src/Magnum/Vk/Implementation/DeviceState.h | 1 + src/Magnum/Vk/Test/BufferTest.cpp | 22 +++++++- src/Magnum/Vk/Test/BufferVkTest.cpp | 57 +++++++++++++++++++- src/Magnum/Vk/Test/CMakeLists.txt | 2 +- 8 files changed, 170 insertions(+), 9 deletions(-) diff --git a/src/Magnum/Vk/Buffer.cpp b/src/Magnum/Vk/Buffer.cpp index ce4a46943..d20a76f23 100644 --- a/src/Magnum/Vk/Buffer.cpp +++ b/src/Magnum/Vk/Buffer.cpp @@ -28,7 +28,6 @@ #include "Magnum/Vk/Assert.h" #include "Magnum/Vk/Device.h" #include "Magnum/Vk/Handle.h" -#include "Magnum/Vk/Memory.h" #include "Magnum/Vk/Implementation/DeviceState.h" namespace Magnum { namespace Vk { @@ -58,13 +57,13 @@ Buffer Buffer::wrap(Device& device, const VkBuffer handle, const HandleFlags fla return out; } -Buffer::Buffer(Device& device, const BufferCreateInfo& info, NoAllocateT): _device{&device}, _flags{HandleFlag::DestroyOnDestruction} { +Buffer::Buffer(Device& device, const BufferCreateInfo& info, NoAllocateT): _device{&device}, _flags{HandleFlag::DestroyOnDestruction}, _dedicatedMemory{NoCreate} { MAGNUM_VK_INTERNAL_ASSERT_SUCCESS(device->CreateBuffer(device, info, nullptr, &_handle)); } -Buffer::Buffer(NoCreateT): _device{}, _handle{} {} +Buffer::Buffer(NoCreateT): _device{}, _handle{}, _dedicatedMemory{NoCreate} {} -Buffer::Buffer(Buffer&& other) noexcept: _device{other._device}, _handle{other._handle}, _flags{other._flags} { +Buffer::Buffer(Buffer&& other) noexcept: _device{other._device}, _handle{other._handle}, _flags{other._flags}, _dedicatedMemory{std::move(other._dedicatedMemory)} { other._handle = {}; } @@ -78,6 +77,7 @@ Buffer& Buffer::operator=(Buffer&& other) noexcept { swap(other._device, _device); swap(other._handle, _handle); swap(other._flags, _flags); + swap(other._dedicatedMemory, _dedicatedMemory); return *this; } @@ -90,6 +90,32 @@ MemoryRequirements Buffer::memoryRequirements() const { return requirements; } +void Buffer::bindMemory(Memory& memory, const UnsignedLong offset) { + VkBindBufferMemoryInfo info{}; + info.sType = VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_INFO; + info.buffer = _handle; + info.memory = memory; + info.memoryOffset = offset; + _device->state().bindBufferMemoryImplementation(*_device, 1, &info); +} + +void Buffer::bindDedicatedMemory(Memory&& memory) { + bindMemory(memory, 0); + _dedicatedMemory = std::move(memory); +} + +bool Buffer::hasDedicatedMemory() const { + /* Sigh. Though better than needing to have `const handle()` overloads + returning `const VkDeviceMemory_T*` */ + return const_cast(*this)._dedicatedMemory.handle(); +} + +Memory& Buffer::dedicatedMemory() { + CORRADE_ASSERT(_dedicatedMemory.handle(), + "Vk::Buffer::dedicatedMemory(): buffer doesn't have a dedicated memory", _dedicatedMemory); + return _dedicatedMemory; +} + VkBuffer Buffer::release() { const VkBuffer handle = _handle; _handle = {}; @@ -108,4 +134,17 @@ void Buffer::getMemoryRequirementsImplementation11(Device& device, const VkBuffe device->GetBufferMemoryRequirements2(device, &info, &requirements); } +void Buffer::bindMemoryImplementationDefault(Device& device, UnsignedInt count, const VkBindBufferMemoryInfo* const infos) { + for(std::size_t i = 0; i != count; ++i) + device->BindBufferMemory(device, infos[i].buffer, infos[i].memory, infos[i].memoryOffset); +} + +void Buffer::bindMemoryImplementationKHR(Device& device, UnsignedInt count, const VkBindBufferMemoryInfo* const infos) { + device->BindBufferMemory2KHR(device, count, infos); +} + +void Buffer::bindMemoryImplementation11(Device& device, UnsignedInt count, const VkBindBufferMemoryInfo* const infos) { + device->BindBufferMemory2(device, count, infos); +} + }} diff --git a/src/Magnum/Vk/Buffer.h b/src/Magnum/Vk/Buffer.h index b11474238..85eb8c65d 100644 --- a/src/Magnum/Vk/Buffer.h +++ b/src/Magnum/Vk/Buffer.h @@ -34,6 +34,7 @@ #include "Magnum/Magnum.h" #include "Magnum/Tags.h" +#include "Magnum/Vk/Memory.h" #include "Magnum/Vk/Vk.h" #include "Magnum/Vk/Vulkan.h" #include "Magnum/Vk/visibility.h" @@ -227,11 +228,48 @@ class MAGNUM_VK_EXPORT Buffer { /** * @brief Buffer memory requirements * - * @see @fn_vk_keyword{GetBufferMemoryRequirements2}, + * @see @ref bindMemory(), @fn_vk_keyword{GetBufferMemoryRequirements2}, * @fn_vk_keyword{GetBufferMemoryRequirements} */ MemoryRequirements memoryRequirements() const; + /** + * @brief Bind buffer memory + * + * Assumes that @p memory type, the amount of @p memory at @p offset + * and @p offset alignment corresponds to buffer memory requirements. + * @see @ref memoryRequirements(), @ref bindDedicatedMemory(), + * @fn_vk_keyword{BindBufferMemory2}, + * @fn_vk_keyword{BindBufferMemory} + */ + void bindMemory(Memory& memory, UnsignedLong offset); + + /** + * @brief Bind a dedicated buffer memory + * + * Equivalent to @ref bindMemory() with @p offset set to @cpp 0 @ce, + * with the additional effect that @p memory ownership transfers to the + * buffer and is then available through @ref dedicatedMemory(). + */ + void bindDedicatedMemory(Memory&& memory); + + /** + * @brief Whether the buffer has a dedicated memory + * + * Returns @cpp true @ce if the buffer memory was bound using + * @ref bindDedicatedMemory(), @cpp false @ce otherwise. + * @see @ref dedicatedMemory() + */ + bool hasDedicatedMemory() const; + + /** + * @brief Dedicated buffer memory + * + * Expects that the buffer has a dedicated memory. + * @see @ref hasDedicatedMemory() + */ + Memory& dedicatedMemory(); + /** * @brief Release the underlying Vulkan buffer * @@ -249,11 +287,16 @@ class MAGNUM_VK_EXPORT Buffer { MAGNUM_VK_LOCAL static void getMemoryRequirementsImplementationKHR(Device& device, const VkBufferMemoryRequirementsInfo2& info, VkMemoryRequirements2& requirements); MAGNUM_VK_LOCAL static void getMemoryRequirementsImplementation11(Device& device, const VkBufferMemoryRequirementsInfo2& info, VkMemoryRequirements2& requirements); + MAGNUM_VK_LOCAL static void bindMemoryImplementationDefault(Device& device, UnsignedInt count, const VkBindBufferMemoryInfo* infos); + MAGNUM_VK_LOCAL static void bindMemoryImplementationKHR(Device& device, UnsignedInt count, const VkBindBufferMemoryInfo* infos); + MAGNUM_VK_LOCAL static void bindMemoryImplementation11(Device& device, UnsignedInt count, const VkBindBufferMemoryInfo* infos); + /* Can't be a reference because of the NoCreate constructor */ Device* _device; VkBuffer _handle; HandleFlags _flags; + Memory _dedicatedMemory; }; }} diff --git a/src/Magnum/Vk/CMakeLists.txt b/src/Magnum/Vk/CMakeLists.txt index 21150bf0e..5c10f74fb 100644 --- a/src/Magnum/Vk/CMakeLists.txt +++ b/src/Magnum/Vk/CMakeLists.txt @@ -27,7 +27,6 @@ find_package(Vulkan REQUIRED) set(MagnumVk_SRCS - Buffer.cpp CommandBuffer.cpp CommandPool.cpp Extensions.cpp @@ -42,6 +41,7 @@ set(MagnumVk_SRCS Implementation/InstanceState.cpp) set(MagnumVk_GracefulAssert_SRCS + Buffer.cpp Device.cpp DeviceProperties.cpp Enums.cpp diff --git a/src/Magnum/Vk/Implementation/DeviceState.cpp b/src/Magnum/Vk/Implementation/DeviceState.cpp index aa9151692..1654df8ba 100644 --- a/src/Magnum/Vk/Implementation/DeviceState.cpp +++ b/src/Magnum/Vk/Implementation/DeviceState.cpp @@ -53,10 +53,13 @@ DeviceState::DeviceState(Device& device) { if(device.isVersionSupported(Version::Vk11)) { bindImageMemoryImplementation = &Image::bindMemoryImplementation11; + bindBufferMemoryImplementation = &Buffer::bindMemoryImplementation11; } else if(device.isExtensionEnabled()) { bindImageMemoryImplementation = &Image::bindMemoryImplementationKHR; + bindBufferMemoryImplementation = &Buffer::bindMemoryImplementationKHR; } else { bindImageMemoryImplementation = &Image::bindMemoryImplementationDefault; + bindBufferMemoryImplementation = &Buffer::bindMemoryImplementationDefault; } } diff --git a/src/Magnum/Vk/Implementation/DeviceState.h b/src/Magnum/Vk/Implementation/DeviceState.h index 07a9b0f08..6b8f84711 100644 --- a/src/Magnum/Vk/Implementation/DeviceState.h +++ b/src/Magnum/Vk/Implementation/DeviceState.h @@ -37,6 +37,7 @@ struct DeviceState { /** @todo put this eventually into a dedicated buffer / image state struct? */ void(*getBufferMemoryRequirementsImplementation)(Device&, const VkBufferMemoryRequirementsInfo2&, VkMemoryRequirements2&); void(*getImageMemoryRequirementsImplementation)(Device&, const VkImageMemoryRequirementsInfo2&, VkMemoryRequirements2&); + void(*bindBufferMemoryImplementation)(Device&, UnsignedInt, const VkBindBufferMemoryInfo*); void(*bindImageMemoryImplementation)(Device&, UnsignedInt, const VkBindImageMemoryInfo*); }; diff --git a/src/Magnum/Vk/Test/BufferTest.cpp b/src/Magnum/Vk/Test/BufferTest.cpp index 5281937db..28dd412af 100644 --- a/src/Magnum/Vk/Test/BufferTest.cpp +++ b/src/Magnum/Vk/Test/BufferTest.cpp @@ -24,7 +24,9 @@ */ #include +#include #include +#include #include "Magnum/Vk/Buffer.h" @@ -39,6 +41,8 @@ struct BufferTest: TestSuite::Tester { void constructNoCreate(); void constructCopy(); + + void dedicatedMemoryNotDedicated(); }; BufferTest::BufferTest() { @@ -47,7 +51,9 @@ BufferTest::BufferTest() { &BufferTest::createInfoConstructFromVk, &BufferTest::constructNoCreate, - &BufferTest::constructCopy}); + &BufferTest::constructCopy, + + &BufferTest::dedicatedMemoryNotDedicated}); } void BufferTest::createInfoConstruct() { @@ -93,6 +99,20 @@ void BufferTest::constructCopy() { CORRADE_VERIFY(!(std::is_assignable{})); } +void BufferTest::dedicatedMemoryNotDedicated() { + #ifdef CORRADE_NO_ASSERT + CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions"); + #endif + + Buffer buffer{NoCreate}; + CORRADE_VERIFY(!buffer.hasDedicatedMemory()); + + std::ostringstream out; + Error redirectError{&out}; + buffer.dedicatedMemory(); + CORRADE_COMPARE(out.str(), "Vk::Buffer::dedicatedMemory(): buffer doesn't have a dedicated memory\n"); +} + }}}} CORRADE_TEST_MAIN(Magnum::Vk::Test::BufferTest) diff --git a/src/Magnum/Vk/Test/BufferVkTest.cpp b/src/Magnum/Vk/Test/BufferVkTest.cpp index 9714a3cac..2430115b9 100644 --- a/src/Magnum/Vk/Test/BufferVkTest.cpp +++ b/src/Magnum/Vk/Test/BufferVkTest.cpp @@ -23,7 +23,10 @@ DEALINGS IN THE SOFTWARE. */ +#include + #include "Magnum/Vk/Buffer.h" +#include "Magnum/Vk/DeviceProperties.h" #include "Magnum/Vk/Handle.h" #include "Magnum/Vk/Memory.h" #include "Magnum/Vk/Result.h" @@ -40,6 +43,9 @@ struct BufferVkTest: VulkanTester { void wrap(); void memoryRequirements(); + + void bindMemory(); + void bindDedicatedMemory(); }; BufferVkTest::BufferVkTest() { @@ -48,7 +54,10 @@ BufferVkTest::BufferVkTest() { &BufferVkTest::wrap, - &BufferVkTest::memoryRequirements}); + &BufferVkTest::memoryRequirements, + + &BufferVkTest::bindMemory, + &BufferVkTest::bindDedicatedMemory}); } void BufferVkTest::construct() { @@ -66,17 +75,29 @@ void BufferVkTest::constructMove() { Buffer a{device(), BufferCreateInfo{BufferUsage::StorageBuffer, 1024}, NoAllocate}; VkBuffer handle = a.handle(); + /* Verify that also the dedicated memory gets moved */ + MemoryRequirements requirements = a.memoryRequirements(); + a.bindDedicatedMemory(Vk::Memory{device(), Vk::MemoryAllocateInfo{requirements.size(), + device().properties().pickMemory(Vk::MemoryFlag::DeviceLocal, requirements.memories())}}); + VkDeviceMemory memoryHandle = a.dedicatedMemory().handle(); + Buffer b = std::move(a); CORRADE_VERIFY(!a.handle()); + CORRADE_VERIFY(!a.hasDedicatedMemory()); CORRADE_COMPARE(b.handle(), handle); CORRADE_COMPARE(b.handleFlags(), HandleFlag::DestroyOnDestruction); + CORRADE_VERIFY(b.hasDedicatedMemory()); + CORRADE_COMPARE(b.dedicatedMemory().handle(), memoryHandle); Buffer c{NoCreate}; c = std::move(b); CORRADE_VERIFY(!b.handle()); + CORRADE_VERIFY(!b.hasDedicatedMemory()); CORRADE_COMPARE(b.handleFlags(), HandleFlags{}); CORRADE_COMPARE(c.handle(), handle); CORRADE_COMPARE(c.handleFlags(), HandleFlag::DestroyOnDestruction); + CORRADE_VERIFY(c.hasDedicatedMemory()); + CORRADE_COMPARE(c.dedicatedMemory().handle(), memoryHandle); CORRADE_VERIFY(std::is_nothrow_move_constructible::value); CORRADE_VERIFY(std::is_nothrow_move_assignable::value); @@ -104,6 +125,40 @@ void BufferVkTest::memoryRequirements() { CORRADE_COMPARE(requirements.size(), 16384); } +void BufferVkTest::bindMemory() { + Buffer buffer{device(), BufferCreateInfo{BufferUsage::StorageBuffer, 16384}, NoAllocate}; + MemoryRequirements requirements = buffer.memoryRequirements(); + + /* Similarly to the Image bindMemory() test, use a 128 kB offset */ + constexpr UnsignedLong offset = 128*1024; + CORRADE_COMPARE_AS(offset, requirements.alignment(), + TestSuite::Compare::Divisible); + + Vk::Memory memory{device(), Vk::MemoryAllocateInfo{ + requirements.size() + offset, + device().properties().pickMemory(Vk::MemoryFlag::DeviceLocal, requirements.memories())}}; + + buffer.bindMemory(memory, offset); + CORRADE_VERIFY(!buffer.hasDedicatedMemory()); +} + +void BufferVkTest::bindDedicatedMemory() { + Buffer buffer{device(), BufferCreateInfo{BufferUsage::StorageBuffer, 16384}, NoAllocate}; + MemoryRequirements requirements = buffer.memoryRequirements(); + + /** @todo expand once KHR_dedicated_allocation is implemented */ + + Vk::Memory memory{device(), Vk::MemoryAllocateInfo{ + requirements.size(), + device().properties().pickMemory(Vk::MemoryFlag::DeviceLocal, requirements.memories())}}; + VkDeviceMemory handle = memory.handle(); + CORRADE_VERIFY(handle); + + buffer.bindDedicatedMemory(std::move(memory)); + CORRADE_VERIFY(buffer.hasDedicatedMemory()); + CORRADE_COMPARE(buffer.dedicatedMemory().handle(), handle); +} + }}}} CORRADE_TEST_MAIN(Magnum::Vk::Test::BufferVkTest) diff --git a/src/Magnum/Vk/Test/CMakeLists.txt b/src/Magnum/Vk/Test/CMakeLists.txt index 5ac6b9727..7b92ec028 100644 --- a/src/Magnum/Vk/Test/CMakeLists.txt +++ b/src/Magnum/Vk/Test/CMakeLists.txt @@ -24,7 +24,7 @@ # DEALINGS IN THE SOFTWARE. # -corrade_add_test(VkBufferTest BufferTest.cpp LIBRARIES MagnumVk) +corrade_add_test(VkBufferTest BufferTest.cpp LIBRARIES MagnumVkTestLib) corrade_add_test(VkCommandBufferTest CommandBufferTest.cpp LIBRARIES MagnumVk) corrade_add_test(VkCommandPoolTest CommandPoolTest.cpp LIBRARIES MagnumVk) corrade_add_test(VkDeviceTest DeviceTest.cpp LIBRARIES MagnumVk)