diff --git a/doc/snippets/MagnumVk.cpp b/doc/snippets/MagnumVk.cpp index 0b56aa397..f81587c49 100644 --- a/doc/snippets/MagnumVk.cpp +++ b/doc/snippets/MagnumVk.cpp @@ -227,6 +227,20 @@ buffer.bindMemory(memory, 0); /* [Buffer-creation-custom-allocation] */ } +{ +Vk::Device device{NoCreate}; +Vk::CommandBuffer cmd{NoCreate}; +/* [Buffer-usage-fill] */ +Vk::Buffer buffer{device, Vk::BufferCreateInfo{ + Vk::BufferUsage::TransferDestination|DOXYGEN_IGNORE(Vk::BufferUsage{}), DOXYGEN_IGNORE(0) +}, DOXYGEN_IGNORE(Vk::MemoryFlag{})}; + +DOXYGEN_IGNORE() + +cmd.fillBuffer(buffer, 0x00000000); +/* [Buffer-usage-fill] */ +} + { /* The include should be a no-op here since it was already included above */ /* [CommandPool-creation] */ diff --git a/doc/vulkan-mapping.dox b/doc/vulkan-mapping.dox index 170f76d99..cdbe2c084 100644 --- a/doc/vulkan-mapping.dox +++ b/doc/vulkan-mapping.dox @@ -142,7 +142,7 @@ Vulkan function | Matching API @fn_vk{CmdDrawIndirect} | | @fn_vk{CmdDrawIndirectCount} @m_class{m-label m-flat m-success} **KHR, 1.2** | | @fn_vk{CmdExecuteCommands} | | -@fn_vk{CmdFillBuffer} | | +@fn_vk{CmdFillBuffer} | @ref CommandBuffer::fillBuffer() @fn_vk{CmdInsertDebugUtilsLabelEXT} @m_class{m-label m-flat m-warning} **EXT** | | @fn_vk{CmdPipelineBarrier} | @ref CommandBuffer::pipelineBarrier() @fn_vk{CmdPushConstants} | | diff --git a/src/Magnum/Vk/Buffer.cpp b/src/Magnum/Vk/Buffer.cpp index 426116d94..465a876fd 100644 --- a/src/Magnum/Vk/Buffer.cpp +++ b/src/Magnum/Vk/Buffer.cpp @@ -25,6 +25,7 @@ #include "Buffer.h" #include "BufferCreateInfo.h" +#include "CommandBuffer.h" #include "Magnum/Vk/Assert.h" #include "Magnum/Vk/Device.h" @@ -159,4 +160,9 @@ VkResult Buffer::bindMemoryImplementation11(Device& device, UnsignedInt count, c return device->BindBufferMemory2(device, count, infos); } +CommandBuffer& CommandBuffer::fillBuffer(const VkBuffer buffer, const UnsignedLong offset, const UnsignedLong size, UnsignedInt value) { + (**_device).CmdFillBuffer(_handle, buffer, offset, size, value); + return *this; +} + }} diff --git a/src/Magnum/Vk/Buffer.h b/src/Magnum/Vk/Buffer.h index 294a88f67..cace8fd8d 100644 --- a/src/Magnum/Vk/Buffer.h +++ b/src/Magnum/Vk/Buffer.h @@ -76,6 +76,15 @@ available through @ref dedicatedMemory(). This matches current behavior of the above, except that you have more control over choosing and allocating the memory. +@section Vk-Buffer-usage Buffer usage + +@subsection Vk-Buffer-usage-fill Clearing / filling buffer data + +The following snippet shows zero-filling the whole buffer using +@ref CommandBuffer::fillBuffer(): + +@snippet MagnumVk.cpp Buffer-usage-fill + @see @ref Image */ class MAGNUM_VK_EXPORT Buffer { diff --git a/src/Magnum/Vk/CommandBuffer.h b/src/Magnum/Vk/CommandBuffer.h index 2ce120744..f2461cbac 100644 --- a/src/Magnum/Vk/CommandBuffer.h +++ b/src/Magnum/Vk/CommandBuffer.h @@ -426,6 +426,36 @@ class MAGNUM_VK_EXPORT CommandBuffer { /** @overload */ CommandBuffer& pipelineBarrier(PipelineStages sourceStages, PipelineStages destinationStages, std::initializer_list imageMemoryBarriers, DependencyFlags dependencyFlags = {}); + /** + * @brief Fill a buffer region with a fixed value + * @param buffer Source @p Buffer or a raw Vulkan buffer handle to + * fill. Expected to have been created with + * @ref BufferUsage::TransferDestination. + * @param offset Offset of the region to fill, in bytes + * @param size Size of the region to fill, in bytes + * @param value A 4-byte value to repeat in the region, interpreted + * accoding to the machine endianness. If @p size is not divisible + * by 4, the last remaining bytes are not filled. + * @return Reference to self (for method chaining) + * + * Allowed only outside of a render pass. See @ref Vk-Buffer-usage-fill + * for a usage example. + * @see @fn_vk_keyword{CmdFillBuffer} + */ + CommandBuffer& fillBuffer(VkBuffer buffer, UnsignedLong offset, UnsignedLong size, UnsignedInt value); + + /** + * @brief Fill the whole buffer with a fixed value + * @return Reference to self (for method chaining) + * + * Allowed only outside of a render pass. Equivalent to + * @ref fillBuffer(VkBuffer, UnsignedLong, UnsignedLong, UnsignedInt) + * with @p offset set to @cpp 0 @ce and @p size to @def_vk{WHOLE_SIZE}. + */ + CommandBuffer& fillBuffer(VkBuffer buffer, UnsignedInt value) { + return fillBuffer(buffer, 0, VK_WHOLE_SIZE, value); + } + private: friend CommandPool; friend Implementation::DeviceState; diff --git a/src/Magnum/Vk/Test/BufferVkTest.cpp b/src/Magnum/Vk/Test/BufferVkTest.cpp index 6a68f8c84..40d5e8fcc 100644 --- a/src/Magnum/Vk/Test/BufferVkTest.cpp +++ b/src/Magnum/Vk/Test/BufferVkTest.cpp @@ -23,12 +23,19 @@ DEALINGS IN THE SOFTWARE. */ +#include +#include #include +#include #include "Magnum/Vk/BufferCreateInfo.h" +#include "Magnum/Vk/CommandBuffer.h" +#include "Magnum/Vk/CommandPoolCreateInfo.h" #include "Magnum/Vk/DeviceProperties.h" +#include "Magnum/Vk/Fence.h" #include "Magnum/Vk/Handle.h" #include "Magnum/Vk/MemoryAllocateInfo.h" +#include "Magnum/Vk/Pipeline.h" #include "Magnum/Vk/Result.h" #include "Magnum/Vk/VulkanTester.h" @@ -48,6 +55,8 @@ struct BufferVkTest: VulkanTester { void bindDedicatedMemory(); void directAllocation(); + + void cmdFillBuffer(); }; BufferVkTest::BufferVkTest() { @@ -61,9 +70,13 @@ BufferVkTest::BufferVkTest() { &BufferVkTest::bindMemory, &BufferVkTest::bindDedicatedMemory, - &BufferVkTest::directAllocation}); + &BufferVkTest::directAllocation, + + &BufferVkTest::cmdFillBuffer}); } +using namespace Containers::Literals; + void BufferVkTest::construct() { { Buffer buffer{device(), BufferCreateInfo{BufferUsage::StorageBuffer, 1024}, NoAllocate}; @@ -169,6 +182,39 @@ void BufferVkTest::directAllocation() { CORRADE_VERIFY(buffer.dedicatedMemory().handle()); } +void BufferVkTest::cmdFillBuffer() { + CommandPool pool{device(), CommandPoolCreateInfo{ + device().properties().pickQueueFamily(QueueFlag::Graphics)}}; + CommandBuffer cmd = pool.allocate(); + + Buffer a{device(), BufferCreateInfo{ + BufferUsage::TransferSource|BufferUsage::TransferDestination, 16 + }, MemoryFlag::HostVisible}; + Utility::copy("0123456789abcdef"_s, a.dedicatedMemory().map()); + + cmd.begin() + .fillBuffer(a, 4, 8, 0x2e2e2e2e) + .pipelineBarrier( + PipelineStage::Transfer, PipelineStage::Host, + {{Access::TransferWrite, Access::HostRead}}, + {}, {}) + .end(); + queue().submit({SubmitInfo{}.setCommandBuffers({cmd})}).wait(); + CORRADE_COMPARE(arrayView(a.dedicatedMemory().mapRead()), "0123........cdef"_s); + + /* Test the full fill as well */ + pool.reset(); + cmd.begin() + .fillBuffer(a, 0x2e2e2e2e) + .pipelineBarrier( + PipelineStage::Transfer, PipelineStage::Host, + {{Access::TransferWrite, Access::HostRead}}, + {}, {}) + .end(); + queue().submit({SubmitInfo{}.setCommandBuffers({cmd})}).wait(); + CORRADE_COMPARE(arrayView(a.dedicatedMemory().mapRead()), "................"_s); +} + }}}} CORRADE_TEST_MAIN(Magnum::Vk::Test::BufferVkTest)