Browse Source

Vk: implement image clears, buffer, image and buffer/image copies.

Since depth/stencil images can't be linear, I needed buffer/image copies
to test those, and conversely to test buffer/image copies I needed image
clears.

A pretty big chunk of work, and it led to a discovery of a SwiftShader
bug, which I will work around next. First Vulkan driver workaround, so
the whole scaffolding needs to get added as well.
pull/494/head
Vladimír Vondruš 5 years ago
parent
commit
47add2f7dd
  1. 115
      doc/snippets/MagnumVk.cpp
  2. 26
      doc/vulkan-mapping.dox
  3. 2
      doc/vulkan-support.dox
  4. 98
      src/Magnum/Vk/Buffer.cpp
  5. 214
      src/Magnum/Vk/Buffer.h
  6. 268
      src/Magnum/Vk/CommandBuffer.h
  7. 5
      src/Magnum/Vk/Device.cpp
  8. 441
      src/Magnum/Vk/Image.cpp
  9. 1056
      src/Magnum/Vk/Image.h
  10. 12
      src/Magnum/Vk/Implementation/DeviceState.cpp
  11. 5
      src/Magnum/Vk/Implementation/DeviceState.h
  12. 10
      src/Magnum/Vk/Pipeline.h
  13. 14
      src/Magnum/Vk/RenderPass.h
  14. 157
      src/Magnum/Vk/Test/BufferTest.cpp
  15. 72
      src/Magnum/Vk/Test/BufferVkTest.cpp
  16. 4
      src/Magnum/Vk/Test/CMakeLists.txt
  17. 533
      src/Magnum/Vk/Test/ImageTest.cpp
  18. 955
      src/Magnum/Vk/Test/ImageVkTest.cpp
  19. 9
      src/Magnum/Vk/Vk.h

115
doc/snippets/MagnumVk.cpp

@ -241,6 +241,30 @@ cmd.fillBuffer(buffer, 0x00000000);
/* [Buffer-usage-fill] */
}
{
Vk::Device device{NoCreate};
Vk::CommandBuffer cmd{NoCreate};
UnsignedLong size{};
/* [Buffer-usage-copy] */
Vk::Buffer input{device, Vk::BufferCreateInfo{
Vk::BufferUsage::TransferSource, size
}, Vk::MemoryFlag::HostVisible};
Vk::Buffer vertices{device, Vk::BufferCreateInfo{
Vk::BufferUsage::TransferDestination|Vk::BufferUsage::VertexBuffer, size
}, Vk::MemoryFlag::DeviceLocal};
DOXYGEN_IGNORE()
cmd.copyBuffer({input, vertices, {
{0, 0, size} /* Copy the whole buffer */
}})
.pipelineBarrier(Vk::PipelineStage::Transfer, Vk::PipelineStage::VertexInput, {
/* Make the buffer memory available for vertex input */
{Vk::Access::TransferWrite, Vk::Access::VertexAttributeRead, vertices}
});
/* [Buffer-usage-copy] */
}
{
/* The include should be a no-op here since it was already included above */
/* [CommandPool-creation] */
@ -483,6 +507,97 @@ image.bindMemory(memory, 0);
/* [Image-creation-custom-allocation] */
}
{
Vk::Device device{NoCreate};
Vk::CommandBuffer cmd{NoCreate};
/* [Image-usage-clear] */
Vk::Image image{device, Vk::ImageCreateInfo2D{
Vk::ImageUsage::TransferDestination|DOXYGEN_IGNORE(Vk::ImageUsage{}), Vk::PixelFormat::RGBA8Srgb, DOXYGEN_IGNORE({}, 1)
}, DOXYGEN_IGNORE(Vk::MemoryFlag{})};
DOXYGEN_IGNORE()
cmd.pipelineBarrier(Vk::PipelineStage::TopOfPipe, Vk::PipelineStage::Transfer, {
/* Transition the image to a layout required by the clear operation */
{Vk::Accesses{}, Vk::Access::TransferWrite,
Vk::ImageLayout::Undefined, Vk::ImageLayout::TransferDestination, image}
})
.clearColorImage(image, Vk::ImageLayout::TransferDestination, 0x1f1f1f_srgbf);
/* [Image-usage-clear] */
}
{
Vk::Device device{NoCreate};
Vk::CommandBuffer cmd{NoCreate};
/* [Image-usage-copy-from-buffer] */
Vk::Buffer input{device, Vk::BufferCreateInfo{
Vk::BufferUsage::TransferSource, 256*256*4 DOXYGEN_IGNORE()
}, Vk::MemoryFlag::HostVisible};
Vk::Image texture{device, Vk::ImageCreateInfo2D{
Vk::ImageUsage::TransferDestination|Vk::ImageUsage::Sampled,
Vk::PixelFormat::RGBA8Srgb, {256, 256}, DOXYGEN_IGNORE(1)
}, Vk::MemoryFlag::DeviceLocal};
DOXYGEN_IGNORE()
cmd.pipelineBarrier(Vk::PipelineStage::TopOfPipe, Vk::PipelineStage::Transfer, {
/* Transition the image to a layout required by the copy operation */
{Vk::Accesses{}, Vk::Access::TransferWrite,
Vk::ImageLayout::Undefined, Vk::ImageLayout::TransferDestination, texture}
})
.copyBufferToImage({input, texture, Vk::ImageLayout::TransferDestination, {
/* Copy the whole buffer to the first level of the image */
Vk::BufferImageCopy2D{0, Vk::ImageAspect::Color, 0, {{}, {256, 256}}}
}})
.pipelineBarrier(Vk::PipelineStage::Transfer, Vk::PipelineStage::FragmentShader, {
/* Make the image memory available for fragment shader sampling */
{Vk::Access::TransferWrite, Vk::Access::ShaderRead,
Vk::ImageLayout::TransferDestination, Vk::ImageLayout::ShaderReadOnly, texture}
});
/* [Image-usage-copy-from-buffer] */
/* [Image-usage-copy-from-buffer-multiple] */
cmd.copyBufferToImage(Vk::CopyBufferToImageInfo2D{
input, texture, Vk::ImageLayout::Undefined, {
/* Assuming mip levels are tightly packed after each other */
{ 0, Vk::ImageAspect::Color, 0, {{}, {256, 256}}},
{262144, Vk::ImageAspect::Color, 1, {{}, {128, 128}}},
{327680, Vk::ImageAspect::Color, 2, {{}, { 64, 64}}},
DOXYGEN_IGNORE()
}
});
/* [Image-usage-copy-from-buffer-multiple] */
}
{
Vk::Device device{NoCreate};
Vk::CommandBuffer cmd{NoCreate};
/* [Image-usage-copy-from-image] */
Vk::Image a{device, Vk::ImageCreateInfo2D{
Vk::ImageUsage::TransferSource|DOXYGEN_IGNORE(Vk::ImageUsage{}),
Vk::PixelFormat::RGBA8Srgb, {256, 256}, DOXYGEN_IGNORE(1)
}, DOXYGEN_IGNORE({})};
Vk::Image b{device, Vk::ImageCreateInfo2D{
Vk::ImageUsage::TransferDestination|DOXYGEN_IGNORE(Vk::ImageUsage{}), Vk::PixelFormat::RGBA8Srgb, {256, 256}, DOXYGEN_IGNORE(1)
}, DOXYGEN_IGNORE({})};
DOXYGEN_IGNORE()
cmd.pipelineBarrier(Vk::PipelineStage::TopOfPipe, Vk::PipelineStage::Transfer, {
/* Transfer both images to a layout required by the copy operation */
{Vk::Accesses{}, Vk::Access::TransferRead,
Vk::ImageLayout::DOXYGEN_IGNORE(Undefined), Vk::ImageLayout::TransferSource, a},
{Vk::Accesses{}, Vk::Access::TransferWrite,
Vk::ImageLayout::Undefined, Vk::ImageLayout::TransferDestination, b}
})
.copyImage({a, Vk::ImageLayout::TransferSource,
b, Vk::ImageLayout::TransferDestination, {
/* Copy the whole first layer/level between the images */
{Vk::ImageAspect::Color, 0, 0, 1, {}, 0, 0, 1, {}, {256, 256, 1}}
}});
/* [Image-usage-copy-from-image] */
}
{
Vk::Device device{NoCreate};
/* The include should be a no-op here since it was already included above */

26
doc/vulkan-mapping.dox

@ -120,14 +120,14 @@ Vulkan function | Matching API
@fn_vk{CmdBuildAccelerationStructuresIndirectKHR} @m_class{m-label m-flat m-warning} **KHR** | |
@fn_vk{CmdBuildAccelerationStructuresKHR} @m_class{m-label m-flat m-warning} **KHR** | |
@fn_vk{CmdClearAttachments} | |
@fn_vk{CmdClearColorImage} | |
@fn_vk{CmdClearDepthStencilImage} | |
@fn_vk{CmdClearColorImage} | @ref CommandBuffer::clearColorImage()
@fn_vk{CmdClearDepthStencilImage} | @ref CommandBuffer::clearDepthStencilImage(), \n @ref CommandBuffer::clearDepthImage(), \n @ref CommandBuffer::clearStencilImage()
@fn_vk{CmdCopyAccelerationStructureKHR} @m_class{m-label m-flat m-warning} **KHR** | |
@fn_vk{CmdCopyAccelerationStructureToMemoryKHR} @m_class{m-label m-flat m-warning} **KHR** | |
@fn_vk{CmdCopyBuffer}, \n @fn_vk{CmdCopyBuffer2KHR} @m_class{m-label m-flat m-warning} **KHR** | |
@fn_vk{CmdCopyBufferToImage}, \n @fn_vk{CmdCopyBufferToImage2KHR} @m_class{m-label m-flat m-warning} **KHR** | |
@fn_vk{CmdCopyImage}, \n @fn_vk{CmdCopyImage2KHR} @m_class{m-label m-flat m-warning} **KHR** | |
@fn_vk{CmdCopyImageToBuffer}, \n @fn_vk{CmdCopyImageToBuffer2KHR} @m_class{m-label m-flat m-warning} **KHR** | |
@fn_vk{CmdCopyBuffer}, \n @fn_vk{CmdCopyBuffer2KHR} @m_class{m-label m-flat m-warning} **KHR** | @ref CommandBuffer::copyBuffer()
@fn_vk{CmdCopyBufferToImage}, \n @fn_vk{CmdCopyBufferToImage2KHR} @m_class{m-label m-flat m-warning} **KHR** | @ref CommandBuffer::copyBufferToImage()
@fn_vk{CmdCopyImage}, \n @fn_vk{CmdCopyImage2KHR} @m_class{m-label m-flat m-warning} **KHR** | @ref CommandBuffer::copyImage()
@fn_vk{CmdCopyImageToBuffer}, \n @fn_vk{CmdCopyImageToBuffer2KHR} @m_class{m-label m-flat m-warning} **KHR** | @ref CommandBuffer::copyImageToBuffer()
@fn_vk{CmdCopyMemoryToAccelerationStructureKHR} @m_class{m-label m-flat m-warning} **KHR** | |
@fn_vk{CmdCopyQueryPoolResults} | |
@fn_vk{CmdDebugMarkerBeginEXT} @m_class{m-label m-danger} **deprecated** @m_class{m-label m-flat m-warning} **EXT**, \n @fn_vk{CmdDebugMarkerEndEXT} @m_class{m-label m-danger} **deprecated** @m_class{m-label m-flat m-warning} **EXT** | |
@ -400,10 +400,10 @@ Vulkan structure | Matching API
@type_vk{BaseOutStructure} | |
@type_vk{BindSparseInfo} | |
@type_vk{BlitImageInfo2KHR} @m_class{m-label m-flat m-warning} **KHR** | |
@type_vk{BufferCopy}, \n @type_vk{BufferCopy2KHR} @m_class{m-label m-flat m-warning} **KHR** | |
@type_vk{BufferCopy}, \n @type_vk{BufferCopy2KHR} @m_class{m-label m-flat m-warning} **KHR** | @ref BufferCopy
@type_vk{BufferCreateInfo} | @ref BufferCreateInfo
@type_vk{BufferDeviceAddressInfo} @m_class{m-label m-flat m-success} **KHR, 1.2** | |
@type_vk{BufferImageCopy}, \n @type_vk{BufferImageCopy2KHR} @m_class{m-label m-flat m-warning} **KHR** | |
@type_vk{BufferImageCopy}, \n @type_vk{BufferImageCopy2KHR} @m_class{m-label m-flat m-warning} **KHR** | @ref BufferImageCopy
@type_vk{BufferMemoryBarrier} | @ref BufferMemoryBarrier
@type_vk{BufferMemoryRequirementsInfo}, \n @type_vk{BufferMemoryRequirementsInfo2} @m_class{m-label m-flat m-success} **KHR, 1.1** | not exposed, internal to @ref Buffer::memoryRequirements()
@type_vk{BufferOpaqueCaptureAddressCreateInfo} @m_class{m-label m-flat m-success} **KHR, 1.2** | |
@ -427,10 +427,10 @@ Vulkan structure | Matching API
@type_vk{ComponentMapping} | |
@type_vk{ComputePipelineCreateInfo} | |
@type_vk{ConformanceVersion} | |
@type_vk{CopyBufferInfo2KHR} @m_class{m-label m-flat m-warning} **KHR** | |
@type_vk{CopyBufferToImageInfo2KHR} @m_class{m-label m-flat m-warning} **KHR** | |
@type_vk{CopyImageInfo2KHR} @m_class{m-label m-flat m-warning} **KHR** | |
@type_vk{CopyImageToBuffer2KHR} @m_class{m-label m-flat m-warning} **KHR** | |
@type_vk{CopyBufferInfo2KHR} @m_class{m-label m-flat m-warning} **KHR** | @ref CopyBufferInfo
@type_vk{CopyBufferToImageInfo2KHR} @m_class{m-label m-flat m-warning} **KHR** | @ref CopyBufferToImageInfo
@type_vk{CopyImageInfo2KHR} @m_class{m-label m-flat m-warning} **KHR** | @ref CopyImageInfo
@type_vk{CopyImageToBuffer2KHR} @m_class{m-label m-flat m-warning} **KHR** | @ref CopyImageToBufferInfo
@type_vk{CopyAccelerationStructureInfoKHR} @m_class{m-label m-flat m-warning} **KHR** | |
@type_vk{CopyAccelerationStructureToMemoryInfoKHR} @m_class{m-label m-flat m-warning} **KHR** | |
@type_vk{CopyMemoryToAccelerationStructureInfoKHR} @m_class{m-label m-flat m-warning} **KHR** | |
@ -528,7 +528,7 @@ Vulkan structure | Matching API
Vulkan structure | Matching API
--------------------------------------- | ------------
@type_vk{ImageBlit}, \n @type_vk{ImageBlit2KHR} @m_class{m-label m-flat m-warning} **KHR** | |
@type_vk{ImageCopy}, \n @type_vk{ImageCopy2KHR} @m_class{m-label m-flat m-warning} **KHR** | |
@type_vk{ImageCopy}, \n @type_vk{ImageCopy2KHR} @m_class{m-label m-flat m-warning} **KHR** | @ref ImageCopy
@type_vk{ImageCreateInfo} | @ref ImageCreateInfo
@type_vk{ImageFormatListCreateInfo} @m_class{m-label m-flat m-success} **KHR, 1.2** | |
@type_vk{ImageFormatProperties}, \n @type_vk{ImageFormatProperties2} @m_class{m-label m-flat m-success} **KHR, 1.1** | |

2
doc/vulkan-support.dox

@ -126,7 +126,7 @@ Extension | Status
@vk_extension{KHR,portability_subset} | done except properties
@vk_extension{KHR,deferred_host_operations} | |
@vk_extension{KHR,pipeline_library} | |
@vk_extension{KHR,copy_commands2} | |
@vk_extension{KHR,copy_commands2} | done except blit and resolve
@vk_extension{KHR,ray_tracing_pipeline} | |
@vk_extension{KHR,ray_query} | |
@vk_extension{IMG,format_pvrtc} | done

98
src/Magnum/Vk/Buffer.cpp

@ -27,6 +27,8 @@
#include "BufferCreateInfo.h"
#include "CommandBuffer.h"
#include <Corrade/Containers/Array.h>
#include "Magnum/Vk/Assert.h"
#include "Magnum/Vk/Device.h"
#include "Magnum/Vk/DeviceProperties.h"
@ -160,9 +162,105 @@ VkResult Buffer::bindMemoryImplementation11(Device& device, UnsignedInt count, c
return device->BindBufferMemory2(device, count, infos);
}
BufferCopy::BufferCopy(const UnsignedLong sourceOffset, const UnsignedLong destinationOffset, const UnsignedLong size): _copy{} {
_copy.sType = VK_STRUCTURE_TYPE_BUFFER_COPY_2_KHR;
_copy.srcOffset = sourceOffset;
_copy.dstOffset = destinationOffset;
_copy.size = size;
}
BufferCopy::BufferCopy(NoInitT) noexcept {}
BufferCopy::BufferCopy(const VkBufferCopy2KHR& copy):
/* Can't use {} with GCC 4.8 here because it tries to initialize the first
member instead of doing a copy */
_copy(copy) {}
BufferCopy::BufferCopy(const VkBufferCopy& copy): _copy{
VK_STRUCTURE_TYPE_BUFFER_COPY_2_KHR,
nullptr,
copy.srcOffset,
copy.dstOffset,
copy.size
} {}
namespace {
/* Used by CopyBufferInfo::vkBufferCopies() as well */
VkBufferCopy vkBufferCopy(const VkBufferCopy2KHR& copy) {
CORRADE_ASSERT(!copy.pNext,
"Vk::BufferCopy: disallowing conversion to VkBufferCopy with non-empty pNext to prevent information loss", {});
return {
copy.srcOffset,
copy.dstOffset,
copy.size
};
}
}
VkBufferCopy BufferCopy::vkBufferCopy() const {
return Vk::vkBufferCopy(_copy);
}
CopyBufferInfo::CopyBufferInfo(const VkBuffer source, const VkBuffer destination, const Containers::ArrayView<const BufferCopy> regions): _info{} {
_info.sType = VK_STRUCTURE_TYPE_COPY_BUFFER_INFO_2_KHR;
_info.srcBuffer = source;
_info.dstBuffer = destination;
/* Vulkan 1.2.166 doesn't allow anything in VkBufferCopy2KHR::pNext yet so
there's no point in storing the original BufferCopy wrapper */
static_assert(sizeof(VkBufferCopy2KHR) == sizeof(BufferCopy),
"expecting BufferCopy to have no extra members referenced from pNext");
Containers::ArrayView<VkBufferCopy2KHR> vkBufferCopies2;
_data = Containers::ArrayTuple{
{NoInit, regions.size(), vkBufferCopies2}
};
for(std::size_t i = 0; i != regions.size(); ++i) {
/* Can't use {} with GCC 4.8 here because it tries to initialize the
first member instead of doing a copy */
new(vkBufferCopies2 + i) VkBufferCopy2KHR(BufferCopy{regions[i]});
}
_info.regionCount = regions.size();
_info.pRegions = vkBufferCopies2;
}
CopyBufferInfo::CopyBufferInfo(const VkBuffer source, const VkBuffer destination, const std::initializer_list<BufferCopy> regions): CopyBufferInfo{source, destination, Containers::arrayView(regions)} {}
CopyBufferInfo::CopyBufferInfo(NoInitT) noexcept {}
CopyBufferInfo::CopyBufferInfo(const VkCopyBufferInfo2KHR& info):
/* Can't use {} with GCC 4.8 here because it tries to initialize the first
member instead of doing a copy */
_info(info) {}
Containers::Array<VkBufferCopy> CopyBufferInfo::vkBufferCopies() const {
Containers::Array<VkBufferCopy> out{NoInit, _info.regionCount};
for(std::size_t i = 0; i != _info.regionCount; ++i)
new(out + i) VkBufferCopy(vkBufferCopy(_info.pRegions[i]));
return out;
}
CommandBuffer& CommandBuffer::fillBuffer(const VkBuffer buffer, const UnsignedLong offset, const UnsignedLong size, UnsignedInt value) {
(**_device).CmdFillBuffer(_handle, buffer, offset, size, value);
return *this;
}
CommandBuffer& CommandBuffer::copyBuffer(const CopyBufferInfo& info) {
_device->state().cmdCopyBufferImplementation(*this, info);
return *this;
}
void CommandBuffer::copyBufferImplementationDefault(CommandBuffer& self, const CopyBufferInfo& info) {
CORRADE_ASSERT(!info->pNext,
"Vk::CommandBuffer::copyBuffer(): disallowing extraction of CopyBufferInfo with non-empty pNext to prevent information loss", );
return (**self._device).CmdCopyBuffer(self, info->srcBuffer, info->dstBuffer, info->regionCount, info.vkBufferCopies());
}
void CommandBuffer::copyBufferImplementationKHR(CommandBuffer& self, const CopyBufferInfo& info) {
return (**self._device).CmdCopyBuffer2KHR(self, info);
}
}}

214
src/Magnum/Vk/Buffer.h

@ -30,6 +30,8 @@
* @m_since_latest
*/
#include <initializer_list>
#include <Corrade/Containers/ArrayTuple.h>
#include <Corrade/Containers/EnumSet.h>
#include "Magnum/Magnum.h"
@ -85,6 +87,23 @@ The following snippet shows zero-filling the whole buffer using
@snippet MagnumVk.cpp Buffer-usage-fill
@subsection Vk-Buffer-usage-copy Copying buffer data
Most common buffer copy operation is uploading vertex data from a host-visible
to device-local memory. This is the preferred workflow for static data over
using a host-visible memory directly, since it usually isn't the fastest for
device access.
The copy is done using @ref CommandBuffer::copyBuffer(). In most cases you'll
want to combine it with a @ref CommandBuffer::pipelineBarrier(PipelineStages, PipelineStages, Containers::ArrayView<const BufferMemoryBarrier>, DependencyFlags) "pipelineBarrier()"
after to make the memory visible for subsequent operations. The following
snippet shows populating a device-local vertex buffer from host-visible memory:
@snippet MagnumVk.cpp Buffer-usage-copy
It's also possible to copy data between buffers and images, see
@ref Vk-Image-usage-copy for examples.
@see @ref Image
*/
class MAGNUM_VK_EXPORT Buffer {
@ -241,6 +260,201 @@ class MAGNUM_VK_EXPORT Buffer {
Memory _dedicatedMemory;
};
/**
@brief Buffer copy region
@m_since_latest
Wraps a @type_vk_keyword{BufferCopy2KHR}. This class is subsequently passed to
a @ref CopyBufferInfo and then used in @ref CommandBuffer::copyBuffer(). See
@ref Vk-Buffer-usage-copy for usage information and examples.
@section Vk-BufferCopy-compatibility Compatibility with VkBufferCopy
While the class operates on the @type_vk{BufferCopy2KHR} structure that's
provided by the @vk_extension{KHR,copy_commands2} extension, conversion from
and to @type_vk{BufferCopy} is provided to some extent --- you can create a
@ref BufferCopy from it, call various methods on the instance and then get a
@type_vk{BufferCopy} back again using @ref vkBufferCopy().
For direct editing of the Vulkan structure, it's recommended to edit the
@type_vk{BufferCopy2KHR} fields and then perform the conversion instead of
editing the resulting @type_vk{BufferCopy}, as additional safety checks may be
done during the conversion to ensure no information is lost.
@see @ref ImageCopy, @ref BufferImageCopy
*/
class MAGNUM_VK_EXPORT BufferCopy {
public:
/**
* @brief Constructor
* @param sourceOffset Source buffer offset in bytes
* @param destinationOffset Destination buffer offset in bytes
* @param size Size to copy in bytes
*
* The following @type_vk{BufferCopy2KHR} fields are pre-filled in
* addition to `sType`, everything else is zero-filled:
*
* - `srcOffset` to @p sourceOffset
* - `dstOffset` to @p destinationOffset
* - `size`
*/
/*implicit*/ BufferCopy(UnsignedLong sourceOffset, UnsignedLong destinationOffset, UnsignedLong size);
/**
* @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 BufferCopy(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 BufferCopy(const VkBufferCopy2KHR& copy);
/**
* @brief Construct from a @type_vk{BufferCopy}
*
* Compared to the above, fills the common subset of
* @type_vk{BufferCopy2KHR}, sets `sType` and zero-fills `pNext`.
* @see @ref vkBufferCopy()
*/
explicit BufferCopy(const VkBufferCopy& copy);
/**
* @brief Corresponding @type_vk{BufferCopy} structure
*
* Provided for compatibility with Vulkan implementations that don't
* support the @vk_extension{KHR,copy_commands2} extensions. See
* @ref Vk-BufferCopy-compatibility for more information.
* @see @ref BufferCopy(const VkBufferCopy&),
* @ref CopyBufferInfo::vkBufferCopies(),
* @ref CopyImageInfo::vkImageCopies(),
* @ref ImageCopy::vkImageCopy(),
* @ref CopyImageToBufferInfo::vkBufferImageCopies(),
* @ref CopyBufferToImageInfo::vkBufferImageCopies(),
* @ref BufferImageCopy::vkBufferImageCopy()
*/
VkBufferCopy vkBufferCopy() const;
/** @brief Underlying @type_vk{BufferCopy2KHR} structure */
VkBufferCopy2KHR& operator*() { return _copy; }
/** @overload */
const VkBufferCopy2KHR& operator*() const { return _copy; }
/** @overload */
VkBufferCopy2KHR* operator->() { return &_copy; }
/** @overload */
const VkBufferCopy2KHR* operator->() const { return &_copy; }
/** @overload */
operator const VkBufferCopy2KHR*() const { return &_copy; }
/**
* @overload
*
* The class is implicitly convertible to a reference in addition to
* a pointer because the type is commonly used in arrays as well, which
* would be annoying to do with a pointer conversion.
*/
operator const VkBufferCopy2KHR&() const { return _copy; }
private:
VkBufferCopy2KHR _copy;
};
/**
@brief Buffer copy command
@m_since_latest
Wraps a @type_vk_keyword{CopyBufferInfo2KHR}. This class is subsequently used
in @ref CommandBuffer::copyBuffer(). See @ref Vk-Buffer-usage-copy for more
information.
@section Vk-CopyBufferInfo-compatibility Compatibility with vkCmdCopyBuffer()
While the class operates on the @type_vk{CopyBufferInfo2KHR} structure that's
provided by the @vk_extension{KHR,copy_commands2} extension, conversion from
and to the set of parameters accepted by @fn_vk{CmdCopyBuffer} is provided to
some extent --- you can create @ref BufferCopy instances out of
@type_vk{BufferCopy} structures, pass them together with the rest to
@ref CopyBufferInfo and then get a @type_vk{BufferCopy} list back again using
@ref vkBufferCopies().
For direct editing of the Vulkan structure, it's recommended to edit the
@type_vk{CopyBufferInfo2KHR} fields and then perform the conversion instead of
editing the resulting @type_vk{BufferCopy} list, as additional safety checks
may be done during the conversion to ensure no information is lost.
@see @ref CopyImageInfo, @ref CopyBufferToImageInfo, @ref CopyImageToBufferInfo
*/
class MAGNUM_VK_EXPORT CopyBufferInfo {
public:
/**
* @brief Constructor
* @param source Source @ref Buffer or a raw Vulkan buffer
* handle. Expected to have been created with
* @ref BufferUsage::TransferSource.
* @param destination Destination @ref Buffer or a raw Vulkan buffer
* handle. Expected to have been created with
* @ref BufferUsage::TransferDestination.
* @param regions Regions to copy. There has to be at least one.
*/
/*implicit*/ CopyBufferInfo(VkBuffer source, VkBuffer destination, Containers::ArrayView<const BufferCopy> regions);
/** @overload */
/*implicit*/ CopyBufferInfo(VkBuffer source, VkBuffer destination, std::initializer_list<BufferCopy> regions);
/**
* @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 CopyBufferInfo(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 CopyBufferInfo(const VkCopyBufferInfo2KHR& info);
/**
* @brief Corresponding @type_vk{BufferCopy} structures
*
* Provided for compatibility with Vulkan implementations that don't
* support the @vk_extension{KHR,copy_commands2} extension. See
* @ref Vk-CopyBufferInfo-compatibility for more information.
* @see @ref BufferImageCopy::vkBufferImageCopy(),
* @ref BufferCopy::vkBufferCopy(),
* @ref CopyImageInfo::vkImageCopies(),
* @ref ImageCopy::vkImageCopy(),
* @ref CopyImageToBufferInfo::vkBufferImageCopies(),
* @ref BufferImageCopy::vkBufferImageCopy()
*/
Containers::Array<VkBufferCopy> vkBufferCopies() const;
/** @brief Underlying @type_vk{CopyBufferInfo2KHR} structure */
VkCopyBufferInfo2KHR& operator*() { return _info; }
/** @overload */
const VkCopyBufferInfo2KHR& operator*() const { return _info; }
/** @overload */
VkCopyBufferInfo2KHR* operator->() { return &_info; }
/** @overload */
const VkCopyBufferInfo2KHR* operator->() const { return &_info; }
/** @overload */
operator const VkCopyBufferInfo2KHR*() const { return &_info; }
private:
VkCopyBufferInfo2KHR _info;
Containers::ArrayTuple _data;
};
}}
#endif

268
src/Magnum/Vk/CommandBuffer.h

@ -387,6 +387,8 @@ class MAGNUM_VK_EXPORT CommandBuffer {
* - and old and new @ref ImageLayout in @p imageMemoryBarriers have
* to be equal
*
* See @ref Vk-Buffer-usage-copy, @ref Vk-Image-usage-clear and
* @ref Vk-Image-usage-copy for usage examples.
* @see @fn_vk_keyword{CmdPipelineBarrier}
*/
CommandBuffer& pipelineBarrier(PipelineStages sourceStages, PipelineStages destinationStages, Containers::ArrayView<const MemoryBarrier> memoryBarriers, Containers::ArrayView<const BufferMemoryBarrier> bufferMemoryBarriers, Containers::ArrayView<const ImageMemoryBarrier> imageMemoryBarriers, DependencyFlags dependencyFlags = {});
@ -409,7 +411,8 @@ class MAGNUM_VK_EXPORT CommandBuffer {
* @return Reference to self (for method chaining)
*
* Equivalent to calling @ref pipelineBarrier(PipelineStages, PipelineStages, Containers::ArrayView<const MemoryBarrier>, Containers::ArrayView<const BufferMemoryBarrier>, Containers::ArrayView<const ImageMemoryBarrier>, DependencyFlags)
* with empty @p memoryBarriers and @p imageBarriers.
* with empty @p memoryBarriers and @p imageBarriers. See
* @ref Vk-Buffer-usage-copy for usage examples.
*/
CommandBuffer& pipelineBarrier(PipelineStages sourceStages, PipelineStages destinationStages, Containers::ArrayView<const BufferMemoryBarrier> bufferMemoryBarriers, DependencyFlags dependencyFlags = {});
/** @overload */
@ -420,7 +423,9 @@ class MAGNUM_VK_EXPORT CommandBuffer {
* @return Reference to self (for method chaining)
*
* Equivalent to calling @ref pipelineBarrier(PipelineStages, PipelineStages, Containers::ArrayView<const MemoryBarrier>, Containers::ArrayView<const BufferMemoryBarrier>, Containers::ArrayView<const ImageMemoryBarrier>, DependencyFlags)
* with empty @p memoryBarriers and @p bufferBarriers.
* with empty @p memoryBarriers and @p bufferBarriers. See
* @ref Vk-Image-usage-clear and @ref Vk-Image-usage-copy for usage
* examples.
*/
CommandBuffer& pipelineBarrier(PipelineStages sourceStages, PipelineStages destinationStages, Containers::ArrayView<const ImageMemoryBarrier> imageMemoryBarriers, DependencyFlags dependencyFlags = {});
/** @overload */
@ -440,7 +445,9 @@ class MAGNUM_VK_EXPORT CommandBuffer {
*
* Allowed only outside of a render pass. See @ref Vk-Buffer-usage-fill
* for a usage example.
* @see @fn_vk_keyword{CmdFillBuffer}
* @see @ref clearColorImage(), @ref clearDepthStencilImage(),
* @ref clearDepthImage(), @ref clearStencilImage(),
* @fn_vk_keyword{CmdFillBuffer}
*/
CommandBuffer& fillBuffer(VkBuffer buffer, UnsignedLong offset, UnsignedLong size, UnsignedInt value);
@ -456,6 +463,249 @@ class MAGNUM_VK_EXPORT CommandBuffer {
return fillBuffer(buffer, 0, VK_WHOLE_SIZE, value);
}
/**
* @brief Clear a floating-point or normalized color image
* @param image An @ref Image or a raw Vulkan image handle to
* clear. Expected to have been created with
* @ref ImageUsage::TransferDestination and a floating-point or
* normalized non-compressed @ref PixelFormat usable for transfer
* destination.
* @param layout Image layout. Can be either
* @ref ImageLayout::General or
* @ref ImageLayout::TransferDestination.
* @param color Color to clear the image with
* @return Reference to self (for method chaining)
*
* Allowed only outside of a render pass. For clearing inside a render
* pass you can either specify @ref AttachmentLoadOperation::Clear for
* a particular attachment, which will clear it on render pass begin
* (see @ref Vk-RenderPass-usage for an example), or use
* @fn_vk{CmdClearAttachments} which allows you to clear at any time
* inside a render pass. See @ref Vk-Image-usage-clear for a usage
* example.
*
* A single @type_vk{ImageSubresourceRange} is passed to the command,
* with the following fields are set:
*
* - `aspectMask` to @val_vk{IMAGE_ASPECT_COLOR,ImageAspectFlagBits}
* - `baseMipLevel` to @cpp 0 @ce
* - `levelCount` to @def_vk{REMAINING_MIP_LEVELS}
* - `baseArrayLayer` to @cpp 0 @ce
* - `layerCount` to @def_vk{REMAINING_ARRAY_LAYERS}
*
* @attention This function currently clears all layers and mip levels
* of the image, with no ability to specify particular layer/level
* ranges. For that please use the Vulkan API directly.
*
* @see @fn_vk_keyword{CmdClearColorImage}
*
* @todoc mention ImageLayout::SharedPresent being allowed once the
* extension is exposed
*/
CommandBuffer& clearColorImage(VkImage image, ImageLayout layout, const Color4& color);
/**
* @brief Clear a signed integral color image
* @return Reference to self (for method chaining)
*
* Allowed only outside of a render pass. Behaves like
* @ref clearColorImage(VkImage, ImageLayout, const Color4&), except
* that it's meant for images with a signed integral non-compressed
* @ref PixelFormat.
*/
CommandBuffer& clearColorImage(VkImage image, ImageLayout layout, const Vector4i& color);
/**
* @brief Clear an unsigned integral color image
* @return Reference to self (for method chaining)
*
* Allowed only outside of a render pass. Behaves like
* @ref clearColorImage(VkImage, ImageLayout, const Color4&), except
* that it's meant for images with an unsigned integral non-compressed
* @ref PixelFormat.
*/
CommandBuffer& clearColorImage(VkImage image, ImageLayout layout, const Vector4ui& color);
/**
* @brief Clear a combined depth/stencil image
* @param image An @ref Image or a raw Vulkan image handle to
* clear. Expected to have been be created with
* @ref ImageUsage::TransferDestination and a combined
* depth/stencil @ref PixelFormat usable for transfer destination.
* @param layout Image layout. Can be either
* @ref ImageLayout::General or
* @ref ImageLayout::TransferDestination.
* @param depth Depth value to clear with
* @param stencil Stencil value to clear with
* @return Reference to self (for method chaining)
*
* Allowed only outside of a render pass. For clearing inside a render
* pass you can either specify @ref AttachmentLoadOperation::Clear for
* a particular attachment, which will clear it on render pass begin
* (see @ref Vk-RenderPass-usage for an example), or use
* @fn_vk{CmdClearAttachments} which allows you to clear at any point
* inside a render pass. For clearing a depth-only or a stencil-only
* image (or just a depth orstencil buffer of a combined depth/stencil
* image) use @ref clearDepthImage() or @ref clearStencilImage()
* instead. See @ref Vk-Image-usage-clear for a usage example.
*
* A single @type_vk{ImageSubresourceRange} is passed to the command,
* with the following fields are set:
*
* - `aspectMask` to @val_vk{IMAGE_ASPECT_DEPTH,ImageAspectFlagBits}
* and @val_vk{IMAGE_ASPECT_STENCIL,ImageAspectFlagBits}
* - `baseMipLevel` to @cpp 0 @ce
* - `levelCount` to @def_vk{REMAINING_MIP_LEVELS}
* - `baseArrayLayer` to @cpp 0 @ce
* - `layerCount` to @def_vk{REMAINING_ARRAY_LAYERS}
*
* @attention This function currently clears all layers and mip levels
* of the image, with no ability to specify particular layer/level
* ranges. For that please use the Vulkan API directly.
*
* @see @fn_vk_keyword{CmdClearDepthStencilImage}
*/
CommandBuffer& clearDepthStencilImage(VkImage image, ImageLayout layout, Float depth, UnsignedInt stencil);
/**
* @brief Clear a depth-only image
* @param image An @ref Image or a raw Vulkan image handle to
* clear. Expected to have been be created with
* @ref ImageUsage::TransferDestination and a depth-only
* @ref PixelFormat usable for transfer destination.
* @param layout Image layout. Can be either
* @ref ImageLayout::General or
* @ref ImageLayout::TransferDestination.
* @param depth Depth value to clear with
* @return Reference to self (for method chaining)
*
* Allowed only outside of a render pass. For clearing inside a render
* pass you can either specify @ref AttachmentLoadOperation::Clear for
* a particular attachment, which will clear it on render pass begin
* (see @ref Vk-RenderPass-usage for an example), or use
* @fn_vk{CmdClearAttachments} which allows you to clear at any point
* inside a render pass. For clearing a combined depth/stencil image
* use @ref clearDepthStencilImage(), for clearing a stencil-only image
* or just the stencil buffer of a combined depth/stencil image use
* @ref clearStencilImage() instead. See @ref Vk-Image-usage-clear for
* a usage example.
*
* A single @type_vk{ImageSubresourceRange} is passed to the command,
* with the following fields are set:
*
* - `aspectMask` to @val_vk{IMAGE_ASPECT_DEPTH,ImageAspectFlagBits}
* - `baseMipLevel` to @cpp 0 @ce
* - `levelCount` to @def_vk{REMAINING_MIP_LEVELS}
* - `baseArrayLayer` to @cpp 0 @ce
* - `layerCount` to @def_vk{REMAINING_ARRAY_LAYERS}
*
* @attention This function currently clears all layers and mip levels
* of the image, with no ability to specify particular layer/level
* ranges. For that please use the Vulkan API directly.
*
* @see @fn_vk_keyword{CmdClearDepthStencilImage}
*/
CommandBuffer& clearDepthImage(VkImage image, ImageLayout layout, Float depth);
/**
* @brief Clear a stencil-only image
* @param image An @ref Image or a raw Vulkan image handle to
* clear. Expected to have been be created with
* @ref ImageUsage::TransferDestination and a stencil-only
* @ref PixelFormat usable for transfer destination.
* @param layout Image layout. Can be either
* @ref ImageLayout::General or
* @ref ImageLayout::TransferDestination.
* @param stencil Stencil value to clear with
* @return Reference to self (for method chaining)
*
* Allowed only outside of a render pass. For clearing inside a render
* pass you can either specify @ref AttachmentLoadOperation::Clear for
* a particular attachment, which will clear it on render pass begin
* (see @ref Vk-RenderPass-usage for an example), or use
* @fn_vk{CmdClearAttachments} which allows you to clear at any point
* inside a render pass. For clearing a combined depth/stencil image
* use @ref clearDepthStencilImage(), for clearing a depth-only image
* or just the depth buffer of a combined depth/stencil image use
* @ref clearDepthImage() instead. See @ref Vk-Image-usage-clear for a
* usage example.
*
* A single @type_vk{ImageSubresourceRange} is passed to the command,
* with the following fields set:
*
* - `aspectMask` to @val_vk{IMAGE_ASPECT_STENCIL,ImageAspectFlagBits}
* - `baseMipLevel` to @cpp 0 @ce
* - `levelCount` to @def_vk{REMAINING_MIP_LEVELS}
* - `baseArrayLayer` to @cpp 0 @ce
* - `layerCount` to @def_vk{REMAINING_ARRAY_LAYERS}
*
* @attention This function currently clears all layers and mip levels
* of the image, with no ability to specify particular layer/level
* ranges. For that please use the Vulkan API directly.
*
* @see @fn_vk_keyword{CmdClearDepthStencilImage}
*/
CommandBuffer& clearStencilImage(VkImage image, ImageLayout layout, UnsignedInt stencil);
/** @todo clearAttachments(), I'm too lazy to expose all the needed
structures right now */
/**
* @brief Copy data between buffer regions
* @return Reference to self (for method chaining)
*
* Allowed only outside of a render pass. If the
* @vk_extension{KHR,copy_commands2} extension is not supported and
* enabled on the device, the `pNext` chain in @p info and its
* substructures has to be empty. See @ref Vk-Buffer-usage-copy for
* details and usage examples.
* @see @fn_vk_keyword{CmdCopyBuffer2KHR},
* @fn_vk_keyword{CmdCopyBuffer}
*/
CommandBuffer& copyBuffer(const CopyBufferInfo& info);
/**
* @brief Copy data between images
* @return Reference to self (for method chaining)
*
* Allowed only outside of a render pass. If the
* @vk_extension{KHR,copy_commands2} extension is not supported
* and enabled on the device, the `pNext` chain in @p info and its
* substructures has to be empty. See @ref Vk-Image-usage-copy for
* details and usage examples.
* @see @fn_vk_keyword{CmdCopyImage2KHR},
* @fn_vk_keyword{CmdCopyImage}
*/
CommandBuffer& copyImage(const CopyImageInfo& info);
/**
* @brief Copy data from a buffer into an image
* @return Reference to self (for method chaining)
*
* Allowed only outside of a render pass. If the
* @vk_extension{KHR,copy_commands2} extension is not supported and
* enabled on the device, the `pNext` chain in @p info and its
* substructures has to be empty. See @ref Vk-Image-usage-copy for
* details and usage examples.
* @see @fn_vk_keyword{CmdCopyBufferToImage2KHR},
* @fn_vk_keyword{CmdCopyBufferToImage}
*/
CommandBuffer& copyBufferToImage(const CopyBufferToImageInfo& info);
/**
* @brief Copy image data into a buffer
* @return Reference to self (for method chaining)
*
* Allowed only outside of a render pass. If the
* @vk_extension{KHR,copy_commands2} extension is not supported and
* enabled on the device, the `pNext` chain in @p info and its
* substructures has to be empty. See @ref Vk-Image-usage-copy for
* details and usage examples.
* @see @fn_vk_keyword{CmdCopyImageToBuffer2KHR},
* @fn_vk_keyword{CmdCopyImageToBuffer}
*/
CommandBuffer& copyImageToBuffer(const CopyImageToBufferInfo& info);
private:
friend CommandPool;
friend Implementation::DeviceState;
@ -472,6 +722,18 @@ class MAGNUM_VK_EXPORT CommandBuffer {
MAGNUM_VK_LOCAL static void endRenderPassImplementationKHR(CommandBuffer& self, const VkSubpassEndInfo& endInfo);
MAGNUM_VK_LOCAL static void endRenderPassImplementation12(CommandBuffer& self, const VkSubpassEndInfo& endInfo);
MAGNUM_VK_LOCAL static void copyBufferImplementationDefault(CommandBuffer& self, const CopyBufferInfo& info);
MAGNUM_VK_LOCAL static void copyBufferImplementationKHR(CommandBuffer& self, const CopyBufferInfo& info);
MAGNUM_VK_LOCAL static void copyImageImplementationDefault(CommandBuffer& self, const CopyImageInfo& info);
MAGNUM_VK_LOCAL static void copyImageImplementationKHR(CommandBuffer& self, const CopyImageInfo& info);
MAGNUM_VK_LOCAL static void copyBufferToImageImplementationDefault(CommandBuffer& self, const CopyBufferToImageInfo& info);
MAGNUM_VK_LOCAL static void copyBufferToImageImplementationKHR(CommandBuffer& self, const CopyBufferToImageInfo& info);
MAGNUM_VK_LOCAL static void copyImageToBufferImplementationDefault(CommandBuffer& self, const CopyImageToBufferInfo& info);
MAGNUM_VK_LOCAL static void copyImageToBufferImplementationKHR(CommandBuffer& self, const CopyImageToBufferInfo& info);
/* Can't be a reference because of the NoCreate constructor */
Device* _device;

5
src/Magnum/Vk/Device.cpp

@ -175,6 +175,11 @@ DeviceCreateInfo::DeviceCreateInfo(DeviceProperties& deviceProperties, const Ext
addEnabledExtensions<Extensions::KHR::create_renderpass2>();
}
/* Enable the KHR_copy_commands2 extension. Not in any Vulkan version
yet. */
if(extensionProperties->isSupported<Extensions::KHR::copy_commands2>())
addEnabledExtensions<Extensions::KHR::copy_commands2>();
/* Enable the KHR_portability_subset extension, which *has to be*
enabled when available. Not enabling any of its features though,
that responsibility lies on the user. */

441
src/Magnum/Vk/Image.cpp

@ -25,9 +25,12 @@
#include "Image.h"
#include "ImageCreateInfo.h"
#include "CommandBuffer.h"
#include <Corrade/Containers/EnumSet.hpp>
#include <Corrade/Containers/Array.h>
#include "Magnum/Math/Color.h"
#include "Magnum/Vk/Assert.h"
#include "Magnum/Vk/Device.h"
#include "Magnum/Vk/DeviceProperties.h"
@ -233,4 +236,442 @@ VkResult Image::bindMemoryImplementation11(Device& device, UnsignedInt count, co
return device->BindImageMemory2(device, count, infos);
}
ImageCopy::ImageCopy(const ImageAspects aspects, const Int sourceLevel, const Int sourceLayerOffset, const Int sourceLayerCount, const Vector3i& sourceOffset, const Int destinationLevel, const Int destinationLayerOffset, const Int destinationLayerCount, const Vector3i& destinationOffset, const Vector3i& size): _copy{} {
_copy.sType = VK_STRUCTURE_TYPE_IMAGE_COPY_2_KHR;
_copy.srcSubresource.aspectMask = VkImageAspectFlags(aspects);
_copy.srcSubresource.mipLevel = sourceLevel;
_copy.srcSubresource.baseArrayLayer = sourceLayerOffset;
_copy.srcSubresource.layerCount = sourceLayerCount;
_copy.srcOffset = VkOffset3D(sourceOffset);
_copy.dstSubresource.aspectMask = VkImageAspectFlags(aspects);
_copy.dstSubresource.mipLevel = destinationLevel;
_copy.dstSubresource.baseArrayLayer = destinationLayerOffset;
_copy.dstSubresource.layerCount = destinationLayerCount;
_copy.dstOffset = VkOffset3D(destinationOffset);
_copy.extent = VkExtent3D(size);
}
ImageCopy::ImageCopy(NoInitT) noexcept {}
ImageCopy::ImageCopy(const VkImageCopy2KHR& copy):
/* Can't use {} with GCC 4.8 here because it tries to initialize the first
member instead of doing a copy */
_copy(copy) {}
ImageCopy::ImageCopy(const VkImageCopy& copy): _copy{
VK_STRUCTURE_TYPE_IMAGE_COPY_2_KHR,
nullptr,
copy.srcSubresource,
copy.srcOffset,
copy.dstSubresource,
copy.dstOffset,
copy.extent
} {}
namespace {
/* Used by CopyImageInfo::vkCopyImageInfo() as well */
VkImageCopy vkImageCopy(const VkImageCopy2KHR& copy) {
CORRADE_ASSERT(!copy.pNext,
"Vk::ImageCopy: disallowing conversion to VkImageCopy with non-empty pNext to prevent information loss", {});
return {
copy.srcSubresource,
copy.srcOffset,
copy.dstSubresource,
copy.dstOffset,
copy.extent
};
}
}
VkImageCopy ImageCopy::vkImageCopy() const {
return Vk::vkImageCopy(_copy);
}
CopyImageInfo::CopyImageInfo(const VkImage source, const ImageLayout sourceLayout, const VkImage destination, const ImageLayout destinationLayout, const Containers::ArrayView<const ImageCopy> regions): _info{} {
_info.sType = VK_STRUCTURE_TYPE_COPY_IMAGE_INFO_2_KHR;
_info.srcImage = source;
_info.srcImageLayout = VkImageLayout(sourceLayout);
_info.dstImage = destination;
_info.dstImageLayout = VkImageLayout(destinationLayout);
/* Vulkan 1.2.166 doesn't allow anything in VkImageCopy2KHR::pNext yet
so there's no point in storing the original ImageCopy wrapper */
static_assert(sizeof(VkImageCopy2KHR) == sizeof(ImageCopy),
"expecting ImageCopy to have no extra members referenced from pNext");
Containers::ArrayView<VkImageCopy2KHR> vkImageCopies2;
_data = Containers::ArrayTuple{
{NoInit, regions.size(), vkImageCopies2}
};
for(std::size_t i = 0; i != regions.size(); ++i) {
/* Can't use {} with GCC 4.8 here because it tries to initialize the
first member instead of doing a copy */
new(vkImageCopies2 + i) VkImageCopy2KHR(ImageCopy{regions[i]});
}
_info.regionCount = regions.size();
_info.pRegions = vkImageCopies2;
}
CopyImageInfo::CopyImageInfo(const VkImage source, const ImageLayout sourceLayout, const VkImage destination, const ImageLayout destinationLayout, const std::initializer_list<ImageCopy> regions): CopyImageInfo{source, sourceLayout, destination, destinationLayout, Containers::arrayView(regions)} {}
CopyImageInfo::CopyImageInfo(NoInitT) noexcept {}
CopyImageInfo::CopyImageInfo(const VkCopyImageInfo2KHR& info):
/* Can't use {} with GCC 4.8 here because it tries to initialize the first
member instead of doing a copy */
_info(info) {}
Containers::Array<VkImageCopy> CopyImageInfo::vkImageCopies() const {
Containers::Array<VkImageCopy> out{NoInit, _info.regionCount};
for(std::size_t i = 0; i != _info.regionCount; ++i)
new(out + i) VkImageCopy(vkImageCopy(_info.pRegions[i]));
return out;
}
BufferImageCopy::BufferImageCopy(const UnsignedLong bufferOffset, const UnsignedInt bufferRowLength, const UnsignedInt bufferImageHeight, const ImageAspect imageAspect, const Int imageLevel, const Int imageLayerOffset, const Int imageLayerCount, const Range3Di& imageRange): _copy{} {
_copy.sType = VK_STRUCTURE_TYPE_BUFFER_IMAGE_COPY_2_KHR;
_copy.bufferOffset = bufferOffset;
_copy.bufferRowLength = bufferRowLength;
_copy.bufferImageHeight = bufferImageHeight;
_copy.imageSubresource.aspectMask = VkImageAspectFlags(imageAspect);
_copy.imageSubresource.mipLevel = imageLevel;
_copy.imageSubresource.baseArrayLayer = imageLayerOffset;
_copy.imageSubresource.layerCount = imageLayerCount;
_copy.imageOffset = VkOffset3D(imageRange.min());
_copy.imageExtent = VkExtent3D(imageRange.size());
}
BufferImageCopy::BufferImageCopy(NoInitT) noexcept {}
BufferImageCopy::BufferImageCopy(const VkBufferImageCopy2KHR& copy):
/* Can't use {} with GCC 4.8 here because it tries to initialize the first
member instead of doing a copy */
_copy(copy) {}
BufferImageCopy::BufferImageCopy(const VkBufferImageCopy& copy): _copy{
VK_STRUCTURE_TYPE_BUFFER_IMAGE_COPY_2_KHR,
nullptr,
copy.bufferOffset,
copy.bufferRowLength,
copy.bufferImageHeight,
copy.imageSubresource,
copy.imageOffset,
copy.imageExtent
} {}
namespace {
/* Used by CopyImageToBufferInfo::vkImageCopies() and
CopyImageToBufferInfo::vkImageCopies() as well */
VkBufferImageCopy vkBufferImageCopy(const VkBufferImageCopy2KHR& copy) {
CORRADE_ASSERT(!copy.pNext,
"Vk::BufferImageCopy: disallowing conversion to VkBufferImageCopy with non-empty pNext to prevent information loss", {});
return {
copy.bufferOffset,
copy.bufferRowLength,
copy.bufferImageHeight,
copy.imageSubresource,
copy.imageOffset,
copy.imageExtent
};
}
}
VkBufferImageCopy BufferImageCopy::vkBufferImageCopy() const {
return Vk::vkBufferImageCopy(_copy);
}
BufferImageCopy1D::BufferImageCopy1D(const UnsignedLong bufferOffset, const ImageAspect aspect, const Int level, const Range1Di& range): BufferImageCopy{bufferOffset, 0, 0, aspect, level, 0, 1, {{range.min(), 0, 0}, {range.max(), 1, 1}}} {}
BufferImageCopy2D::BufferImageCopy2D(const UnsignedLong bufferOffset, const UnsignedInt bufferRowLength, const ImageAspect aspect, const Int level, const Range2Di& range): BufferImageCopy{bufferOffset, bufferRowLength, 0, aspect, level, 0, 1, {{range.min(), 0}, {range.max(), 1}}} {}
BufferImageCopy3D::BufferImageCopy3D(const UnsignedLong bufferOffset, const UnsignedInt bufferRowLength, const UnsignedInt bufferImageHeight, const ImageAspect aspect, const Int level, const Range3Di& range): BufferImageCopy{bufferOffset, bufferRowLength, bufferImageHeight, aspect, level, 0, 1, range} {}
BufferImageCopy1DArray::BufferImageCopy1DArray(const UnsignedLong bufferOffset, const UnsignedInt bufferRowLength, const ImageAspect aspect, const Int level, const Range2Di& range): BufferImageCopy{bufferOffset, bufferRowLength, 0, aspect, level, range.min().y(), range.sizeY(), {{range.min().x(), 0, 0}, {range.max().x(), 1, 1}}} {}
BufferImageCopy2DArray::BufferImageCopy2DArray(const UnsignedLong bufferOffset, const UnsignedInt bufferRowLength, const UnsignedInt bufferImageHeight, const ImageAspect aspect, const Int level, const Range3Di& range): BufferImageCopy{bufferOffset, bufferRowLength, bufferImageHeight, aspect, level, range.min().z(), range.sizeZ(), {{range.min().xy(), 0}, {range.max().xy(), 1}}} {}
BufferImageCopyCubeMap::BufferImageCopyCubeMap(const UnsignedLong bufferOffset, const UnsignedInt bufferRowLength, const UnsignedInt bufferImageHeight, const ImageAspect aspect, const Int level, const Range2Di& range): BufferImageCopy{bufferOffset, bufferRowLength, bufferImageHeight, aspect, level, 0, 6, {{range.min(), 0}, {range.max(), 1}}} {}
BufferImageCopyCubeMapArray::BufferImageCopyCubeMapArray(const UnsignedLong bufferOffset, const UnsignedInt bufferRowLength, const UnsignedInt bufferImageHeight, const ImageAspect aspect, const Int level, const Range3Di& range): BufferImageCopy{bufferOffset, bufferRowLength, bufferImageHeight, aspect, level, range.min().z(), range.sizeZ(), {{range.min().xy(), 0}, {range.max().xy(), 1}}} {}
CopyBufferToImageInfo::CopyBufferToImageInfo(const VkBuffer source, const VkImage destination, const ImageLayout destinationLayout, const Containers::ArrayView<const BufferImageCopy> regions): _info{} {
_info.sType = VK_STRUCTURE_TYPE_COPY_BUFFER_TO_IMAGE_INFO_2_KHR;
_info.srcBuffer = source;
_info.dstImage = destination;
_info.dstImageLayout = VkImageLayout(destinationLayout);
/* While not strictly needed right now, storing the original
BufferImageCopy instances as well to prepare for a future case where
VkBufferImageCopy2KHR::pNext will reference something stored there (such
as copy transformation) */
Containers::ArrayView<BufferImageCopy> wrappers;
Containers::ArrayView<VkBufferImageCopy2KHR> vkBufferImageCopies2;
_data = Containers::ArrayTuple{
{NoInit, regions.size(), wrappers},
{NoInit, regions.size(), vkBufferImageCopies2}
};
for(std::size_t i = 0; i != regions.size(); ++i) {
new(wrappers + i) BufferImageCopy{regions[i]};
/* Can't use {} with GCC 4.8 here because it tries to initialize the
first member instead of doing a copy */
new(vkBufferImageCopies2 + i) VkBufferImageCopy2KHR(wrappers[i]);
}
_info.regionCount = regions.size();
_info.pRegions = vkBufferImageCopies2;
}
CopyBufferToImageInfo::CopyBufferToImageInfo(NoInitT) noexcept {}
CopyBufferToImageInfo::CopyBufferToImageInfo(const VkCopyBufferToImageInfo2KHR& info):
/* Can't use {} with GCC 4.8 here because it tries to initialize the first
member instead of doing a copy */
_info(info) {}
CopyBufferToImageInfo::CopyBufferToImageInfo(const VkBuffer source, const VkImage destination, const ImageLayout destinationLayout, const std::initializer_list<BufferImageCopy> regions): CopyBufferToImageInfo{source, destination, destinationLayout, Containers::arrayView(regions)} {}
Containers::Array<VkBufferImageCopy> CopyBufferToImageInfo::vkBufferImageCopies() const {
Containers::Array<VkBufferImageCopy> out{NoInit, _info.regionCount};
for(std::size_t i = 0; i != _info.regionCount; ++i)
new(out + i) VkBufferImageCopy(vkBufferImageCopy(_info.pRegions[i]));
return out;
}
CopyBufferToImageInfo1D::CopyBufferToImageInfo1D(const VkBuffer source, const VkImage destination, const ImageLayout destinationLayout, const Containers::ArrayView<const BufferImageCopy1D> regions): CopyBufferToImageInfo{source, destination, destinationLayout, Containers::arrayCast<const BufferImageCopy>(regions)} {}
CopyBufferToImageInfo1D::CopyBufferToImageInfo1D(const VkBuffer source, const VkImage destination, const ImageLayout destinationLayout, const std::initializer_list<BufferImageCopy1D> regions): CopyBufferToImageInfo1D{source, destination, destinationLayout, Containers::arrayView(regions)} {}
CopyBufferToImageInfo2D::CopyBufferToImageInfo2D(const VkBuffer source, const VkImage destination, const ImageLayout destinationLayout, const Containers::ArrayView<const BufferImageCopy2D> regions): CopyBufferToImageInfo{source, destination, destinationLayout, Containers::arrayCast<const BufferImageCopy>(regions)} {}
CopyBufferToImageInfo2D::CopyBufferToImageInfo2D(const VkBuffer source, const VkImage destination, const ImageLayout destinationLayout, const std::initializer_list<BufferImageCopy2D> regions): CopyBufferToImageInfo2D{source, destination, destinationLayout, Containers::arrayView(regions)} {}
CopyBufferToImageInfo3D::CopyBufferToImageInfo3D(const VkBuffer source, const VkImage destination, const ImageLayout destinationLayout, const Containers::ArrayView<const BufferImageCopy3D> regions): CopyBufferToImageInfo{source, destination, destinationLayout, Containers::arrayCast<const BufferImageCopy>(regions)} {}
CopyBufferToImageInfo3D::CopyBufferToImageInfo3D(const VkBuffer source, const VkImage destination, const ImageLayout destinationLayout, const std::initializer_list<BufferImageCopy3D> regions): CopyBufferToImageInfo3D{source, destination, destinationLayout, Containers::arrayView(regions)} {}
CopyBufferToImageInfo1DArray::CopyBufferToImageInfo1DArray(const VkBuffer source, const VkImage destination, const ImageLayout destinationLayout, const Containers::ArrayView<const BufferImageCopy1DArray> regions): CopyBufferToImageInfo{source, destination, destinationLayout, Containers::arrayCast<const BufferImageCopy>(regions)} {}
CopyBufferToImageInfo1DArray::CopyBufferToImageInfo1DArray(const VkBuffer source, const VkImage destination, const ImageLayout destinationLayout, const std::initializer_list<BufferImageCopy1DArray> regions): CopyBufferToImageInfo1DArray{source, destination, destinationLayout, Containers::arrayView(regions)} {}
CopyBufferToImageInfo2DArray::CopyBufferToImageInfo2DArray(const VkBuffer source, const VkImage destination, const ImageLayout destinationLayout, const Containers::ArrayView<const BufferImageCopy2DArray> regions): CopyBufferToImageInfo{source, destination, destinationLayout, Containers::arrayCast<const BufferImageCopy>(regions)} {}
CopyBufferToImageInfo2DArray::CopyBufferToImageInfo2DArray(const VkBuffer source, const VkImage destination, const ImageLayout destinationLayout, const std::initializer_list<BufferImageCopy2DArray> regions): CopyBufferToImageInfo2DArray{source, destination, destinationLayout, Containers::arrayView(regions)} {}
CopyBufferToImageInfoCubeMap::CopyBufferToImageInfoCubeMap(const VkBuffer source, const VkImage destination, const ImageLayout destinationLayout, const Containers::ArrayView<const BufferImageCopyCubeMap> regions): CopyBufferToImageInfo{source, destination, destinationLayout, Containers::arrayCast<const BufferImageCopy>(regions)} {}
CopyBufferToImageInfoCubeMap::CopyBufferToImageInfoCubeMap(const VkBuffer source, const VkImage destination, const ImageLayout destinationLayout, const std::initializer_list<BufferImageCopyCubeMap> regions): CopyBufferToImageInfoCubeMap{source, destination, destinationLayout, Containers::arrayView(regions)} {}
CopyBufferToImageInfoCubeMapArray::CopyBufferToImageInfoCubeMapArray(const VkBuffer source, const VkImage destination, const ImageLayout destinationLayout, const Containers::ArrayView<const BufferImageCopyCubeMapArray> regions): CopyBufferToImageInfo{source, destination, destinationLayout, Containers::arrayCast<const BufferImageCopy>(regions)} {}
CopyBufferToImageInfoCubeMapArray::CopyBufferToImageInfoCubeMapArray(const VkBuffer source, const VkImage destination, const ImageLayout destinationLayout, const std::initializer_list<BufferImageCopyCubeMapArray> regions): CopyBufferToImageInfoCubeMapArray{source, destination, destinationLayout, Containers::arrayView(regions)} {}
CopyImageToBufferInfo::CopyImageToBufferInfo(const VkImage source, const ImageLayout sourceLayout, const VkBuffer destination, const Containers::ArrayView<const BufferImageCopy> regions): _info{} {
_info.sType = VK_STRUCTURE_TYPE_COPY_IMAGE_TO_BUFFER_INFO_2_KHR;
_info.srcImage = source;
_info.srcImageLayout = VkImageLayout(sourceLayout);
_info.dstBuffer = destination;
/* While not strictly needed right now, storing the original
BufferImageCopy instances as well to prepare for a future case where
VkBufferImageCopy2KHR::pNext will reference something stored there (such
as copy transformation) */
Containers::ArrayView<BufferImageCopy> wrappers;
Containers::ArrayView<VkBufferImageCopy2KHR> vkBufferImageCopies2;
_data = Containers::ArrayTuple{
{NoInit, regions.size(), wrappers},
{NoInit, regions.size(), vkBufferImageCopies2}
};
for(std::size_t i = 0; i != regions.size(); ++i) {
new(wrappers + i) BufferImageCopy{regions[i]};
/* Can't use {} with GCC 4.8 here because it tries to initialize the
first member instead of doing a copy */
new(vkBufferImageCopies2 + i) VkBufferImageCopy2KHR(wrappers[i]);
}
_info.regionCount = regions.size();
_info.pRegions = vkBufferImageCopies2;
}
CopyImageToBufferInfo::CopyImageToBufferInfo(const VkImage source, const ImageLayout sourceLayout, const VkBuffer destination, const std::initializer_list<BufferImageCopy> regions): CopyImageToBufferInfo{source, sourceLayout, destination, Containers::arrayView(regions)} {}
CopyImageToBufferInfo::CopyImageToBufferInfo(NoInitT) noexcept {}
CopyImageToBufferInfo::CopyImageToBufferInfo(const VkCopyImageToBufferInfo2KHR& info):
/* Can't use {} with GCC 4.8 here because it tries to initialize the first
member instead of doing a copy */
_info(info) {}
Containers::Array<VkBufferImageCopy> CopyImageToBufferInfo::vkBufferImageCopies() const {
Containers::Array<VkBufferImageCopy> out{NoInit, _info.regionCount};
for(std::size_t i = 0; i != _info.regionCount; ++i)
new(out + i) VkBufferImageCopy(vkBufferImageCopy(_info.pRegions[i]));
return out;
}
CopyImageToBufferInfo1D::CopyImageToBufferInfo1D(const VkImage source, const ImageLayout sourceLayout, const VkBuffer destination, const Containers::ArrayView<const BufferImageCopy1D> regions): CopyImageToBufferInfo{source, sourceLayout, destination, Containers::arrayCast<const BufferImageCopy>(regions)} {}
CopyImageToBufferInfo1D::CopyImageToBufferInfo1D(const VkImage source, const ImageLayout sourceLayout, const VkBuffer destination, const std::initializer_list<BufferImageCopy1D> regions): CopyImageToBufferInfo1D{source, sourceLayout, destination, Containers::arrayView(regions)} {}
CopyImageToBufferInfo2D::CopyImageToBufferInfo2D(const VkImage source, const ImageLayout sourceLayout, const VkBuffer destination, const Containers::ArrayView<const BufferImageCopy2D> regions): CopyImageToBufferInfo{source, sourceLayout, destination, Containers::arrayCast<const BufferImageCopy>(regions)} {}
CopyImageToBufferInfo2D::CopyImageToBufferInfo2D(const VkImage source, const ImageLayout sourceLayout, const VkBuffer destination, const std::initializer_list<BufferImageCopy2D> regions): CopyImageToBufferInfo2D{source, sourceLayout, destination, Containers::arrayView(regions)} {}
CopyImageToBufferInfo3D::CopyImageToBufferInfo3D(const VkImage source, const ImageLayout sourceLayout, const VkBuffer destination, const Containers::ArrayView<const BufferImageCopy3D> regions): CopyImageToBufferInfo{source, sourceLayout, destination, Containers::arrayCast<const BufferImageCopy>(regions)} {}
CopyImageToBufferInfo3D::CopyImageToBufferInfo3D(const VkImage source, const ImageLayout sourceLayout, const VkBuffer destination, const std::initializer_list<BufferImageCopy3D> regions): CopyImageToBufferInfo3D{source, sourceLayout, destination, Containers::arrayView(regions)} {}
CopyImageToBufferInfo1DArray::CopyImageToBufferInfo1DArray(const VkImage source, const ImageLayout sourceLayout, const VkBuffer destination, const Containers::ArrayView<const BufferImageCopy1DArray> regions): CopyImageToBufferInfo{source, sourceLayout, destination, Containers::arrayCast<const BufferImageCopy>(regions)} {}
CopyImageToBufferInfo1DArray::CopyImageToBufferInfo1DArray(const VkImage source, const ImageLayout sourceLayout, const VkBuffer destination, const std::initializer_list<BufferImageCopy1DArray> regions): CopyImageToBufferInfo1DArray{source, sourceLayout, destination, Containers::arrayView(regions)} {}
CopyImageToBufferInfo2DArray::CopyImageToBufferInfo2DArray(const VkImage source, const ImageLayout sourceLayout, const VkBuffer destination, const Containers::ArrayView<const BufferImageCopy2DArray> regions): CopyImageToBufferInfo{source, sourceLayout, destination, Containers::arrayCast<const BufferImageCopy>(regions)} {}
CopyImageToBufferInfo2DArray::CopyImageToBufferInfo2DArray(const VkImage source, const ImageLayout sourceLayout, const VkBuffer destination, const std::initializer_list<BufferImageCopy2DArray> regions): CopyImageToBufferInfo2DArray{source, sourceLayout, destination, Containers::arrayView(regions)} {}
CopyImageToBufferInfoCubeMap::CopyImageToBufferInfoCubeMap(const VkImage source, const ImageLayout sourceLayout, const VkBuffer destination, const Containers::ArrayView<const BufferImageCopyCubeMap> regions): CopyImageToBufferInfo{source, sourceLayout, destination, Containers::arrayCast<const BufferImageCopy>(regions)} {}
CopyImageToBufferInfoCubeMap::CopyImageToBufferInfoCubeMap(const VkImage source, const ImageLayout sourceLayout, const VkBuffer destination, const std::initializer_list<BufferImageCopyCubeMap> regions): CopyImageToBufferInfoCubeMap{source, sourceLayout, destination, Containers::arrayView(regions)} {}
CopyImageToBufferInfoCubeMapArray::CopyImageToBufferInfoCubeMapArray(const VkImage source, const ImageLayout sourceLayout, const VkBuffer destination, const Containers::ArrayView<const BufferImageCopyCubeMapArray> regions): CopyImageToBufferInfo{source, sourceLayout, destination, Containers::arrayCast<const BufferImageCopy>(regions)} {}
CopyImageToBufferInfoCubeMapArray::CopyImageToBufferInfoCubeMapArray(const VkImage source, const ImageLayout sourceLayout, const VkBuffer destination, const std::initializer_list<BufferImageCopyCubeMapArray> regions): CopyImageToBufferInfoCubeMapArray{source, sourceLayout, destination, Containers::arrayView(regions)} {}
CommandBuffer& CommandBuffer::clearColorImage(const VkImage image, const ImageLayout layout, const Color4& color) {
VkImageSubresourceRange range{};
range.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
range.baseMipLevel = 0;
range.levelCount = VK_REMAINING_MIP_LEVELS;
range.baseArrayLayer = 0;
range.layerCount = VK_REMAINING_ARRAY_LAYERS;
/* Why this is passed via a pointer, why?! */
const VkClearColorValue clear(color);
(**_device).CmdClearColorImage(_handle, image, VkImageLayout(layout), &clear, 1, &range);
return *this;
}
CommandBuffer& CommandBuffer::clearColorImage(const VkImage image, const ImageLayout layout, const Vector4i& color) {
VkImageSubresourceRange range{};
range.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
range.baseMipLevel = 0;
range.levelCount = VK_REMAINING_MIP_LEVELS;
range.baseArrayLayer = 0;
range.layerCount = VK_REMAINING_ARRAY_LAYERS;
/* Why this is passed via a pointer, why?! */
const VkClearColorValue clear(color);
(**_device).CmdClearColorImage(_handle, image, VkImageLayout(layout), &clear, 1, &range);
return *this;
}
CommandBuffer& CommandBuffer::clearColorImage(const VkImage image, const ImageLayout layout, const Vector4ui& color) {
VkImageSubresourceRange range{};
range.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
range.baseMipLevel = 0;
range.levelCount = VK_REMAINING_MIP_LEVELS;
range.baseArrayLayer = 0;
range.layerCount = VK_REMAINING_ARRAY_LAYERS;
/* Why this is passed via a pointer, why?! */
const VkClearColorValue clear(color);
(**_device).CmdClearColorImage(_handle, image, VkImageLayout(layout), &clear, 1, &range);
return *this;
}
CommandBuffer& CommandBuffer::clearDepthStencilImage(const VkImage image, const ImageLayout layout, const Float depth, const UnsignedInt stencil) {
VkImageSubresourceRange range{};
range.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT|VK_IMAGE_ASPECT_STENCIL_BIT;
range.baseMipLevel = 0;
range.levelCount = VK_REMAINING_MIP_LEVELS;
range.baseArrayLayer = 0;
range.layerCount = VK_REMAINING_ARRAY_LAYERS;
/* Why this is passed via a pointer, why?! */
const VkClearDepthStencilValue clear{depth, stencil};
(**_device).CmdClearDepthStencilImage(_handle, image, VkImageLayout(layout), &clear, 1, &range);
return *this;
}
CommandBuffer& CommandBuffer::clearDepthImage(const VkImage image, const ImageLayout layout, const Float depth) {
VkImageSubresourceRange range{};
range.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
range.baseMipLevel = 0;
range.levelCount = VK_REMAINING_MIP_LEVELS;
range.baseArrayLayer = 0;
range.layerCount = VK_REMAINING_ARRAY_LAYERS;
/* Why this is passed via a pointer, why?! */
const VkClearDepthStencilValue clear{depth, 0};
(**_device).CmdClearDepthStencilImage(_handle, image, VkImageLayout(layout), &clear, 1, &range);
return *this;
}
CommandBuffer& CommandBuffer::clearStencilImage(const VkImage image, const ImageLayout layout, const UnsignedInt stencil) {
VkImageSubresourceRange range{};
range.aspectMask = VK_IMAGE_ASPECT_STENCIL_BIT;
range.baseMipLevel = 0;
range.levelCount = VK_REMAINING_MIP_LEVELS;
range.baseArrayLayer = 0;
range.layerCount = VK_REMAINING_ARRAY_LAYERS;
/* Why this is passed via a pointer, why?! Also, the depth value will get
unused anyway, but I think it's good to maintain the fact that default
depth clear value is 1.0. */
const VkClearDepthStencilValue clear{1.0f, stencil};
(**_device).CmdClearDepthStencilImage(_handle, image, VkImageLayout(layout), &clear, 1, &range);
return *this;
}
CommandBuffer& CommandBuffer::copyImage(const CopyImageInfo& info) {
_device->state().cmdCopyImageImplementation(*this, info);
return *this;
}
void CommandBuffer::copyImageImplementationDefault(CommandBuffer& self, const CopyImageInfo& info) {
CORRADE_ASSERT(!info->pNext,
"Vk::CommandBuffer::copyImage(): disallowing extraction of CopyImageInfo with non-empty pNext to prevent information loss", );
return (**self._device).CmdCopyImage(self, info->srcImage, info->srcImageLayout, info->dstImage, info->dstImageLayout, info->regionCount, info.vkImageCopies());
}
void CommandBuffer::copyImageImplementationKHR(CommandBuffer& self, const CopyImageInfo& info) {
return (**self._device).CmdCopyImage2KHR(self, info);
}
CommandBuffer& CommandBuffer::copyBufferToImage(const CopyBufferToImageInfo& info) {
_device->state().cmdCopyBufferToImageImplementation(*this, info);
return *this;
}
void CommandBuffer::copyBufferToImageImplementationDefault(CommandBuffer& self, const CopyBufferToImageInfo& info) {
CORRADE_ASSERT(!info->pNext,
"Vk::CommandBuffer::copyBufferToImage(): disallowing extraction of CopyBufferToImageInfo with non-empty pNext to prevent information loss", );
return (**self._device).CmdCopyBufferToImage(self, info->srcBuffer, info->dstImage, info->dstImageLayout, info->regionCount, info.vkBufferImageCopies());
}
void CommandBuffer::copyBufferToImageImplementationKHR(CommandBuffer& self, const CopyBufferToImageInfo& info) {
return (**self._device).CmdCopyBufferToImage2KHR(self, info);
}
CommandBuffer& CommandBuffer::copyImageToBuffer(const CopyImageToBufferInfo& info) {
_device->state().cmdCopyImageToBufferImplementation(*this, info);
return *this;
}
void CommandBuffer::copyImageToBufferImplementationDefault(CommandBuffer& self, const CopyImageToBufferInfo& info) {
CORRADE_ASSERT(!info->pNext,
"Vk::CommandBuffer::copyImageToBuffer(): disallowing extraction of CopyImageToBufferInfo with non-empty pNext to prevent information loss", );
return (**self._device).CmdCopyImageToBuffer(self, info->srcImage, info->srcImageLayout, info->dstBuffer, info->regionCount, info.vkBufferImageCopies());
}
void CommandBuffer::copyImageToBufferImplementationKHR(CommandBuffer& self, const CopyImageToBufferInfo& info) {
return (**self._device).CmdCopyImageToBuffer2KHR(self, info);
}
}}

1056
src/Magnum/Vk/Image.h

File diff suppressed because it is too large Load Diff

12
src/Magnum/Vk/Implementation/DeviceState.cpp

@ -80,6 +80,18 @@ DeviceState::DeviceState(Device& device) {
cmdNextSubpassImplementation = &CommandBuffer::nextSubpassImplementationDefault;
cmdEndRenderPassImplementation = &CommandBuffer::endRenderPassImplementationDefault;
}
if(device.isExtensionEnabled<Extensions::KHR::copy_commands2>()) {
cmdCopyBufferImplementation = &CommandBuffer::copyBufferImplementationKHR;
cmdCopyImageImplementation = &CommandBuffer::copyImageImplementationKHR;
cmdCopyBufferToImageImplementation = &CommandBuffer::copyBufferToImageImplementationKHR;
cmdCopyImageToBufferImplementation = &CommandBuffer::copyImageToBufferImplementationKHR;
} else {
cmdCopyBufferImplementation = &CommandBuffer::copyBufferImplementationDefault;
cmdCopyImageImplementation = &CommandBuffer::copyImageImplementationDefault;
cmdCopyBufferToImageImplementation = &CommandBuffer::copyBufferToImageImplementationDefault;
cmdCopyImageToBufferImplementation = &CommandBuffer::copyImageToBufferImplementationDefault;
}
}
}}}

5
src/Magnum/Vk/Implementation/DeviceState.h

@ -53,6 +53,11 @@ struct DeviceState {
void(*cmdBeginRenderPassImplementation)(CommandBuffer&, const VkRenderPassBeginInfo&, const VkSubpassBeginInfo&);
void(*cmdNextSubpassImplementation)(CommandBuffer&, const VkSubpassEndInfo&, const VkSubpassBeginInfo&);
void(*cmdEndRenderPassImplementation)(CommandBuffer&, const VkSubpassEndInfo&);
void(*cmdCopyBufferImplementation)(CommandBuffer&, const CopyBufferInfo&);
void(*cmdCopyImageImplementation)(CommandBuffer&, const CopyImageInfo&);
void(*cmdCopyBufferToImageImplementation)(CommandBuffer&, const CopyBufferToImageInfo&);
void(*cmdCopyImageToBufferImplementation)(CommandBuffer&, const CopyImageToBufferInfo&);
};
}}}

10
src/Magnum/Vk/Pipeline.h

@ -401,7 +401,9 @@ CORRADE_ENUMSET_OPERATORS(DependencyFlags)
@m_since_latest
Wraps a @type_vk_keyword{MemoryBarrier}. This class is subsequently used in
@ref CommandBuffer::pipelineBarrier().
@ref CommandBuffer::pipelineBarrier(), see @ref Vk-Image-usage-copy and
@ref Vk-Buffer-usage-copy for usage examples.
@see @ref BufferMemoryBarrier, @ref ImageMemoryBarrier
*/
class MAGNUM_VK_EXPORT MemoryBarrier {
public:
@ -458,7 +460,8 @@ class MAGNUM_VK_EXPORT MemoryBarrier {
Wraps a @type_vk_keyword{BufferMemoryBarrier}. Compared to @ref MemoryBarrier
only affects a single buffer. This class is subsequently used in
@ref CommandBuffer::pipelineBarrier().
@ref CommandBuffer::pipelineBarrier(), see @ref Vk-Buffer-usage-copy for usage
examples.
*/
class MAGNUM_VK_EXPORT BufferMemoryBarrier {
public:
@ -525,7 +528,8 @@ class MAGNUM_VK_EXPORT BufferMemoryBarrier {
Wraps a @type_vk_keyword{ImageMemoryBarrier}. Compared to @ref MemoryBarrier
only affects a single image and additionally performs @ref ImageLayout
transitions. This class is subsequently used in
@ref CommandBuffer::pipelineBarrier().
@ref CommandBuffer::pipelineBarrier(), see @ref Vk-Image-usage-copy for usage
examples.
*/
class MAGNUM_VK_EXPORT ImageMemoryBarrier {
public:

14
src/Magnum/Vk/RenderPass.h

@ -312,7 +312,8 @@ class MAGNUM_VK_EXPORT RenderPassBeginInfo {
* @brief Clear a floating-point or normalized color attachment
* @return Reference to self (for method chaining)
*
* @see @ref AttachmentLoadOperation::Clear
* @see @ref AttachmentLoadOperation::Clear,
* @ref CommandBuffer::clearColorImage(VkImage, ImageLayout, const Color4&)
*/
RenderPassBeginInfo& clearColor(UnsignedInt attachment, const Color4& color);
@ -320,7 +321,8 @@ class MAGNUM_VK_EXPORT RenderPassBeginInfo {
* @brief Clear a signed integral color attachment
* @return Reference to self (for method chaining)
*
* @see @ref AttachmentLoadOperation::Clear
* @see @ref AttachmentLoadOperation::Clear,
* @ref CommandBuffer::clearColorImage(VkImage, ImageLayout, const Vector4i&)
*/
RenderPassBeginInfo& clearColor(UnsignedInt attachment, const Vector4i& color);
@ -328,7 +330,8 @@ class MAGNUM_VK_EXPORT RenderPassBeginInfo {
* @brief Clear an unsigned integral color attachment
* @return Reference to self (for method chaining)
*
* @see @ref AttachmentLoadOperation::Clear
* @see @ref AttachmentLoadOperation::Clear,
* @ref CommandBuffer::clearColorImage(VkImage, ImageLayout, const Vector4ui&)
*/
RenderPassBeginInfo& clearColor(UnsignedInt attachment, const Vector4ui& color);
@ -338,7 +341,10 @@ class MAGNUM_VK_EXPORT RenderPassBeginInfo {
*
* If the attachment is not a combined depth/stencil format, the unused
* value is ignored.
* @see @ref AttachmentLoadOperation::Clear
* @see @ref AttachmentLoadOperation::Clear,
* @ref CommandBuffer::clearDepthStencilImage(VkImage, ImageLayout, Float, UnsignedInt),
* @ref CommandBuffer::clearDepthImage(VkImage, ImageLayout, Float),
* @ref CommandBuffer::clearStencilImage(VkImage, ImageLayout, UnsignedInt)
*/
RenderPassBeginInfo& clearDepthStencil(UnsignedInt attachment, Float depth, UnsignedInt stencil);

157
src/Magnum/Vk/Test/BufferTest.cpp

@ -25,6 +25,7 @@
#include <new>
#include <sstream>
#include <Corrade/Containers/Array.h>
#include <Corrade/TestSuite/Tester.h>
#include <Corrade/Utility/DebugStl.h>
@ -43,6 +44,23 @@ struct BufferTest: TestSuite::Tester {
void constructCopy();
void dedicatedMemoryNotDedicated();
/* While *ConstructFromVk() tests that going from VkFromThing -> Vk::Thing
-> VkToThing doesn't result in information loss, the *ConvertToVk()
tests additionally check that all calls both on our APIs and by editing
the contained structure are correctly propagated to the resulting
structures. */
void bufferCopyConstruct();
void bufferCopyConstructNoInit();
template<class From, class To> void bufferCopyConstructFromVk();
template<class T> void bufferCopyConvertToVk();
void bufferCopyConvertDisallowed();
void copyBufferInfoConstruct();
void copyBufferInfoConstructNoInit();
void copyBufferInfoConstructFromVk();
void copyBufferInfoConvertToVk();
};
BufferTest::BufferTest() {
@ -53,9 +71,41 @@ BufferTest::BufferTest() {
&BufferTest::constructNoCreate,
&BufferTest::constructCopy,
&BufferTest::dedicatedMemoryNotDedicated});
&BufferTest::dedicatedMemoryNotDedicated,
&BufferTest::bufferCopyConstruct,
&BufferTest::bufferCopyConstructNoInit,
&BufferTest::bufferCopyConstructFromVk<VkBufferCopy2KHR, VkBufferCopy2KHR>,
&BufferTest::bufferCopyConstructFromVk<VkBufferCopy, VkBufferCopy2KHR>,
&BufferTest::bufferCopyConstructFromVk<VkBufferCopy2KHR, VkBufferCopy>,
&BufferTest::bufferCopyConstructFromVk<VkBufferCopy, VkBufferCopy>,
&BufferTest::bufferCopyConvertToVk<VkBufferCopy2KHR>,
&BufferTest::bufferCopyConvertToVk<VkBufferCopy>,
&BufferTest::bufferCopyConvertDisallowed,
&BufferTest::copyBufferInfoConstruct,
&BufferTest::copyBufferInfoConstructNoInit,
&BufferTest::copyBufferInfoConstructFromVk,
&BufferTest::copyBufferInfoConvertToVk});
}
template<class> struct Traits;
#define _c(type) \
template<> struct Traits<Vk ## type> { \
static const char* name() { return #type; } \
static Vk ## type convert(const type& instance) { \
return instance.vk ## type (); \
} \
}; \
template<> struct Traits<Vk ## type ## 2KHR> { \
static const char* name() { return #type "2KHR"; } \
static Vk ## type ## 2KHR convert(const type& instance) { \
return instance; \
} \
};
_c(BufferCopy)
#undef _c
void BufferTest::createInfoConstruct() {
/** @todo use a real flag once at least one is exposed */
BufferCreateInfo info{BufferUsage::UniformBuffer, 1024, BufferCreateInfo::Flag(VK_BUFFER_CREATE_PROTECTED_BIT)};
@ -113,6 +163,111 @@ void BufferTest::dedicatedMemoryNotDedicated() {
CORRADE_COMPARE(out.str(), "Vk::Buffer::dedicatedMemory(): buffer doesn't have a dedicated memory\n");
}
void BufferTest::bufferCopyConstruct() {
BufferCopy copy{3, 5, 7};
CORRADE_COMPARE(copy->srcOffset, 3);
CORRADE_COMPARE(copy->dstOffset, 5);
CORRADE_COMPARE(copy->size, 7);
}
void BufferTest::bufferCopyConstructNoInit() {
BufferCopy copy{NoInit};
copy->sType = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2;
new(&copy) BufferCopy{NoInit};
CORRADE_COMPARE(copy->sType, VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2);
CORRADE_VERIFY((std::is_nothrow_constructible<BufferCopy, NoInitT>::value));
/* Implicit construction is not allowed */
CORRADE_VERIFY(!(std::is_convertible<NoInitT, BufferCopy>::value));
}
template<class From, class To> void BufferTest::bufferCopyConstructFromVk() {
setTestCaseTemplateName({Traits<From>::name(), Traits<To>::name()});
From from{};
from.srcOffset = 3;
from.dstOffset = 5;
from.size = 7;
BufferCopy copy{from};
To to = Traits<To>::convert(copy);
CORRADE_COMPARE(to.srcOffset, 3);
CORRADE_COMPARE(to.dstOffset, 5);
CORRADE_COMPARE(to.size, 7);
}
template<class T> void BufferTest::bufferCopyConvertToVk() {
BufferCopy copy{3, 5, 7};
T out = Traits<T>::convert(copy);
CORRADE_COMPARE(out.srcOffset, 3);
CORRADE_COMPARE(out.dstOffset, 5);
CORRADE_COMPARE(out.size, 7);
}
void BufferTest::bufferCopyConvertDisallowed() {
#ifdef CORRADE_NO_ASSERT
CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions");
#endif
BufferCopy copy{0, 0, 0};
copy->pNext = &copy;
std::ostringstream out;
Error redirectError{&out};
copy.vkBufferCopy();
CORRADE_COMPARE(out.str(), "Vk::BufferCopy: disallowing conversion to VkBufferCopy with non-empty pNext to prevent information loss\n");
}
void BufferTest::copyBufferInfoConstruct() {
auto a = reinterpret_cast<VkBuffer>(0xdead);
auto b = reinterpret_cast<VkBuffer>(0xcafe);
CopyBufferInfo info{a, b, {
{3, 0, 0},
{0, 5, 0}
}};
CORRADE_COMPARE(info->srcBuffer, a);
CORRADE_COMPARE(info->dstBuffer, b);
CORRADE_COMPARE(info->regionCount, 2);
CORRADE_VERIFY(info->pRegions);
CORRADE_COMPARE(info->pRegions[0].srcOffset, 3);
CORRADE_COMPARE(info->pRegions[1].dstOffset, 5);
}
void BufferTest::copyBufferInfoConstructNoInit() {
CopyBufferInfo info{NoInit};
info->sType = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2;
new(&info) CopyBufferInfo{NoInit};
CORRADE_COMPARE(info->sType, VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2);
CORRADE_VERIFY((std::is_nothrow_constructible<CopyBufferInfo, NoInitT>::value));
/* Implicit construction is not allowed */
CORRADE_VERIFY(!(std::is_convertible<NoInitT, CopyBufferInfo>::value));
}
void BufferTest::copyBufferInfoConstructFromVk() {
VkCopyBufferInfo2KHR vkInfo;
vkInfo.sType = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2;
CopyBufferInfo info{vkInfo};
CORRADE_COMPARE(info->sType, VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2);
}
void BufferTest::copyBufferInfoConvertToVk() {
CopyBufferInfo info{VkBuffer{}, VkBuffer{}, {
{3, 0, 0},
{0, 5, 0}
}};
Containers::Array<VkBufferCopy> copies = info.vkBufferCopies();
CORRADE_COMPARE(copies.size(), 2);
CORRADE_COMPARE(copies[0].srcOffset, 3);
CORRADE_COMPARE(copies[1].dstOffset, 5);
}
}}}}
CORRADE_TEST_MAIN(Magnum::Vk::Test::BufferTest)

72
src/Magnum/Vk/Test/BufferVkTest.cpp

@ -23,15 +23,18 @@
DEALINGS IN THE SOFTWARE.
*/
#include <sstream>
#include <Corrade/Containers/Array.h>
#include <Corrade/Containers/StringView.h>
#include <Corrade/TestSuite/Compare/Numeric.h>
#include <Corrade/Utility/Algorithms.h>
#include <Corrade/Utility/DebugStl.h>
#include "Magnum/Vk/BufferCreateInfo.h"
#include "Magnum/Vk/CommandBuffer.h"
#include "Magnum/Vk/CommandPoolCreateInfo.h"
#include "Magnum/Vk/DeviceProperties.h"
#include "Magnum/Vk/Extensions.h"
#include "Magnum/Vk/Fence.h"
#include "Magnum/Vk/Handle.h"
#include "Magnum/Vk/MemoryAllocateInfo.h"
@ -57,6 +60,8 @@ struct BufferVkTest: VulkanTester {
void directAllocation();
void cmdFillBuffer();
void cmdCopyBuffer();
void cmdCopyBufferDisallowedConversion();
};
BufferVkTest::BufferVkTest() {
@ -72,7 +77,9 @@ BufferVkTest::BufferVkTest() {
&BufferVkTest::directAllocation,
&BufferVkTest::cmdFillBuffer});
&BufferVkTest::cmdFillBuffer,
&BufferVkTest::cmdCopyBuffer,
&BufferVkTest::cmdCopyBufferDisallowedConversion});
}
using namespace Containers::Literals;
@ -194,10 +201,9 @@ void BufferVkTest::cmdFillBuffer() {
cmd.begin()
.fillBuffer(a, 4, 8, 0x2e2e2e2e)
.pipelineBarrier(
PipelineStage::Transfer, PipelineStage::Host,
{{Access::TransferWrite, Access::HostRead}},
{}, {})
.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);
@ -206,15 +212,63 @@ void BufferVkTest::cmdFillBuffer() {
pool.reset();
cmd.begin()
.fillBuffer(a, 0x2e2e2e2e)
.pipelineBarrier(
PipelineStage::Transfer, PipelineStage::Host,
{{Access::TransferWrite, Access::HostRead}},
{}, {})
.pipelineBarrier(PipelineStage::Transfer, PipelineStage::Host, {
{Access::TransferWrite, Access::HostRead}
}, {}, {})
.end();
queue().submit({SubmitInfo{}.setCommandBuffers({cmd})}).wait();
CORRADE_COMPARE(arrayView(a.dedicatedMemory().mapRead()), "................"_s);
}
void BufferVkTest::cmdCopyBuffer() {
CommandPool pool{device(), CommandPoolCreateInfo{
device().properties().pickQueueFamily(QueueFlag::Graphics)}};
CommandBuffer cmd = pool.allocate();
/* Source buffer */
Buffer a{device(), BufferCreateInfo{BufferUsage::TransferSource, 7}, MemoryFlag::HostVisible};
Utility::copy("__ABCD_"_s, a.dedicatedMemory().map());
/* Destination buffer, clear it to have predictable output */
Buffer b{device(), BufferCreateInfo{BufferUsage::TransferDestination, 10}, MemoryFlag::HostVisible};
Utility::copy(".........."_s, b.dedicatedMemory().map());
cmd.begin()
.copyBuffer({a, b, {{2, 5, 4}}})
.pipelineBarrier(PipelineStage::Transfer, PipelineStage::Host, {
{Access::TransferWrite, Access::HostRead}
}, {}, {})
.end();
queue().submit({SubmitInfo{}.setCommandBuffers({cmd})}).wait();
CORRADE_COMPARE(arrayView(b.dedicatedMemory().mapRead()),
".....ABCD."_s);
}
void BufferVkTest::cmdCopyBufferDisallowedConversion() {
#ifdef CORRADE_NO_ASSERT
CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions");
#endif
if(device().isExtensionEnabled<Extensions::KHR::copy_commands2>())
CORRADE_SKIP("KHR_copy_commands2 enabled on the device, can't test");
CommandPool pool{device(), CommandPoolCreateInfo{
device().properties().pickQueueFamily(QueueFlag::Graphics)}};
CommandBuffer cmd = pool.allocate();
CopyBufferInfo a{{}, {}, {}};
a->pNext = &a;
/* The commands shouldn't do anything, so it should be fine to just call
them without any render pass set up */
std::ostringstream out;
Error redirectError{&out};
cmd.copyBuffer(a);
CORRADE_COMPARE(out.str(),
"Vk::CommandBuffer::copyBuffer(): disallowing extraction of CopyBufferInfo with non-empty pNext to prevent information loss\n");
}
}}}}
CORRADE_TEST_MAIN(Magnum::Vk::Test::BufferVkTest)

4
src/Magnum/Vk/Test/CMakeLists.txt

@ -156,7 +156,7 @@ if(BUILD_VK_TESTS)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/configure.h.cmake
${CMAKE_CURRENT_BINARY_DIR}/configure.h)
corrade_add_test(VkBufferVkTest BufferVkTest.cpp LIBRARIES MagnumVulkanTester)
corrade_add_test(VkBufferVkTest BufferVkTest.cpp LIBRARIES MagnumVkTestLib MagnumVulkanTester)
corrade_add_test(VkCommandBufferVkTest CommandBufferVkTest.cpp LIBRARIES MagnumVulkanTester)
corrade_add_test(VkCommandPoolVkTest CommandPoolVkTest.cpp LIBRARIES MagnumVulkanTester)
corrade_add_test(VkDeviceVkTest DeviceVkTest.cpp LIBRARIES MagnumVkTestLib MagnumVulkanTester)
@ -165,7 +165,7 @@ if(BUILD_VK_TESTS)
corrade_add_test(VkFenceVkTest FenceVkTest.cpp LIBRARIES MagnumVk MagnumVulkanTester)
corrade_add_test(VkFramebufferVkTest FramebufferVkTest.cpp LIBRARIES MagnumVk MagnumVulkanTester)
corrade_add_test(VkLayerPropertiesVkTest LayerPropertiesVkTest.cpp LIBRARIES MagnumVkTestLib)
corrade_add_test(VkImageVkTest ImageVkTest.cpp LIBRARIES MagnumVk MagnumVulkanTester)
corrade_add_test(VkImageVkTest ImageVkTest.cpp LIBRARIES MagnumVkTestLib MagnumVulkanTester)
corrade_add_test(VkImageViewVkTest ImageViewVkTest.cpp LIBRARIES MagnumVk MagnumVulkanTester)
corrade_add_test(VkInstanceVkTest InstanceVkTest.cpp LIBRARIES MagnumVkTestLib)
corrade_add_test(VkMemoryVkTest MemoryVkTest.cpp LIBRARIES MagnumVk MagnumVulkanTester)

533
src/Magnum/Vk/Test/ImageTest.cpp

@ -25,6 +25,7 @@
#include <new>
#include <sstream>
#include <Corrade/Containers/Array.h>
#include <Corrade/TestSuite/Tester.h>
#include <Corrade/Utility/DebugStl.h>
@ -60,6 +61,46 @@ struct ImageTest: TestSuite::Tester {
void dedicatedMemoryNotDedicated();
/* While *ConstructFromVk() tests that going from VkFromThing -> Vk::Thing
-> VkToThing doesn't result in information loss, the *ConvertToVk()
tests additionally check that all calls both on our APIs and by editing
the contained structure are correctly propagated to the resulting
structures. */
void imageCopyConstruct();
void imageCopyConstructNoInit();
template<class From, class To> void imageCopyConstructFromVk();
template<class T> void imageCopyConvertToVk();
void imageCopyConvertDisallowed();
void copyImageInfoConstruct();
void copyImageInfoConstructNoInit();
void copyImageInfoConstructFromVk();
void copyImageInfoConvertToVk();
void bufferImageCopyConstruct();
void bufferImageCopyConstruct1D();
void bufferImageCopyConstruct2D();
void bufferImageCopyConstruct3D();
void bufferImageCopyConstruct1DArray();
void bufferImageCopyConstruct2DArray();
void bufferImageCopyConstructCubeMap();
void bufferImageCopyConstructCubeMapArray();
void bufferImageCopyConstructNoInit();
template<class From, class To> void bufferImageCopyConstructFromVk();
template<class T> void bufferImageCopyConvertToVk();
void bufferImageCopyConvertDisallowed();
void copyBufferToImageInfoConstruct();
void copyBufferToImageInfoConstructNoInit();
void copyBufferToImageInfoConstructFromVk();
void copyBufferToImageInfoConvertToVk();
void copyImageToBufferInfoConstruct();
void copyImageToBufferInfoConstructNoInit();
void copyImageToBufferInfoConstructFromVk();
void copyImageToBufferInfoConvertToVk();
void debugAspect();
void debugAspects();
};
@ -101,10 +142,70 @@ ImageTest::ImageTest() {
&ImageTest::dedicatedMemoryNotDedicated,
&ImageTest::imageCopyConstruct,
&ImageTest::imageCopyConstructNoInit,
&ImageTest::imageCopyConstructFromVk<VkImageCopy2KHR, VkImageCopy2KHR>,
&ImageTest::imageCopyConstructFromVk<VkImageCopy, VkImageCopy2KHR>,
&ImageTest::imageCopyConstructFromVk<VkImageCopy2KHR, VkImageCopy>,
&ImageTest::imageCopyConstructFromVk<VkImageCopy, VkImageCopy>,
&ImageTest::imageCopyConvertToVk<VkImageCopy2KHR>,
&ImageTest::imageCopyConvertToVk<VkImageCopy>,
&ImageTest::imageCopyConvertDisallowed,
&ImageTest::copyImageInfoConstruct,
&ImageTest::copyImageInfoConstructNoInit,
&ImageTest::copyImageInfoConstructFromVk,
&ImageTest::copyImageInfoConvertToVk,
&ImageTest::bufferImageCopyConstruct,
&ImageTest::bufferImageCopyConstruct1D,
&ImageTest::bufferImageCopyConstruct2D,
&ImageTest::bufferImageCopyConstruct3D,
&ImageTest::bufferImageCopyConstruct1DArray,
&ImageTest::bufferImageCopyConstruct2DArray,
&ImageTest::bufferImageCopyConstructCubeMap,
&ImageTest::bufferImageCopyConstructCubeMapArray,
&ImageTest::bufferImageCopyConstructNoInit,
&ImageTest::bufferImageCopyConstructFromVk<VkBufferImageCopy2KHR, VkBufferImageCopy2KHR>,
&ImageTest::bufferImageCopyConstructFromVk<VkBufferImageCopy, VkBufferImageCopy2KHR>,
&ImageTest::bufferImageCopyConstructFromVk<VkBufferImageCopy2KHR, VkBufferImageCopy>,
&ImageTest::bufferImageCopyConstructFromVk<VkBufferImageCopy, VkBufferImageCopy>,
&ImageTest::bufferImageCopyConvertToVk<VkBufferImageCopy2KHR>,
&ImageTest::bufferImageCopyConvertToVk<VkBufferImageCopy>,
&ImageTest::bufferImageCopyConvertDisallowed,
&ImageTest::copyBufferToImageInfoConstruct,
&ImageTest::copyBufferToImageInfoConstructNoInit,
&ImageTest::copyBufferToImageInfoConstructFromVk,
&ImageTest::copyBufferToImageInfoConvertToVk,
&ImageTest::copyImageToBufferInfoConstruct,
&ImageTest::copyImageToBufferInfoConstructNoInit,
&ImageTest::copyImageToBufferInfoConstructFromVk,
&ImageTest::copyImageToBufferInfoConvertToVk,
&ImageTest::debugAspect,
&ImageTest::debugAspects});
}
template<class> struct Traits;
#define _c(type) \
template<> struct Traits<Vk ## type> { \
static const char* name() { return #type; } \
static Vk ## type convert(const type& instance) { \
return instance.vk ## type (); \
} \
}; \
template<> struct Traits<Vk ## type ## 2KHR> { \
static const char* name() { return #type "2KHR"; } \
static Vk ## type ## 2KHR convert(const type& instance) { \
return instance; \
} \
};
_c(ImageCopy)
_c(BufferImageCopy)
#undef _c
template<class T> void ImageTest::createInfoConstruct() {
setTestCaseTemplateName(PixelFormatTraits<T>::name());
@ -292,6 +393,438 @@ void ImageTest::dedicatedMemoryNotDedicated() {
CORRADE_COMPARE(out.str(), "Vk::Image::dedicatedMemory(): image doesn't have a dedicated memory\n");
}
void ImageTest::imageCopyConstruct() {
ImageCopy copy{ImageAspect::Color|ImageAspect::Depth, 3, 5, 7, {9, 11, 13}, 4, 6, 8, {10, 12, 14}, {1, 2, 15}};
CORRADE_COMPARE(copy->srcSubresource.aspectMask, VK_IMAGE_ASPECT_COLOR_BIT|VK_IMAGE_ASPECT_DEPTH_BIT);
CORRADE_COMPARE(copy->srcSubresource.mipLevel, 3);
CORRADE_COMPARE(copy->srcSubresource.baseArrayLayer, 5);
CORRADE_COMPARE(copy->srcSubresource.layerCount, 7);
CORRADE_COMPARE(Vector3i{copy->srcOffset}, (Vector3i{9, 11, 13}));
CORRADE_COMPARE(copy->dstSubresource.aspectMask, VK_IMAGE_ASPECT_COLOR_BIT|VK_IMAGE_ASPECT_DEPTH_BIT);
CORRADE_COMPARE(copy->dstSubresource.mipLevel, 4);
CORRADE_COMPARE(copy->dstSubresource.baseArrayLayer, 6);
CORRADE_COMPARE(copy->dstSubresource.layerCount, 8);
CORRADE_COMPARE(Vector3i{copy->dstOffset}, (Vector3i{10, 12, 14}));
CORRADE_COMPARE(Vector3i{copy->extent}, (Vector3i{1, 2, 15}));
}
void ImageTest::imageCopyConstructNoInit() {
ImageCopy copy{NoInit};
copy->sType = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2;
new(&copy) ImageCopy{NoInit};
CORRADE_COMPARE(copy->sType, VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2);
CORRADE_VERIFY((std::is_nothrow_constructible<ImageCopy, NoInitT>::value));
/* Implicit construction is not allowed */
CORRADE_VERIFY(!(std::is_convertible<NoInitT, ImageCopy>::value));
}
template<class From, class To> void ImageTest::imageCopyConstructFromVk() {
setTestCaseTemplateName({Traits<From>::name(), Traits<To>::name()});
From from{};
from.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
from.srcSubresource.mipLevel = 3;
from.srcSubresource.baseArrayLayer = 5;
from.srcSubresource.layerCount = 7;
from.srcOffset = {9, 11, 13};
/* Deliberately using a different src/dst aspect to verify it's not
conflated */
from.dstSubresource.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
from.dstSubresource.mipLevel = 4;
from.dstSubresource.baseArrayLayer = 6;
from.dstSubresource.layerCount = 8;
from.dstOffset = {10, 12, 14};
from.extent = {1, 2, 15};
ImageCopy copy{from};
To to = Traits<To>::convert(copy);
CORRADE_COMPARE(to.srcSubresource.aspectMask, VK_IMAGE_ASPECT_COLOR_BIT);
CORRADE_COMPARE(to.srcSubresource.mipLevel, 3);
CORRADE_COMPARE(to.srcSubresource.baseArrayLayer, 5);
CORRADE_COMPARE(to.srcSubresource.layerCount, 7);
CORRADE_COMPARE(Vector3i{to.srcOffset}, (Vector3i{9, 11, 13}));
CORRADE_COMPARE(to.dstSubresource.aspectMask, VK_IMAGE_ASPECT_DEPTH_BIT);
CORRADE_COMPARE(to.dstSubresource.mipLevel, 4);
CORRADE_COMPARE(to.dstSubresource.baseArrayLayer, 6);
CORRADE_COMPARE(to.dstSubresource.layerCount, 8);
CORRADE_COMPARE(Vector3i{to.dstOffset}, (Vector3i{10, 12, 14}));
CORRADE_COMPARE(Vector3i{to.extent}, (Vector3i{1, 2, 15}));
}
template<class T> void ImageTest::imageCopyConvertToVk() {
ImageCopy copy{ImageAspect::Color|ImageAspect::Depth, 3, 5, 7, {9, 11, 13}, 4, 6, 8, {10, 12, 14}, {1, 2, 15}};
T out = Traits<T>::convert(copy);
CORRADE_COMPARE(out.srcSubresource.aspectMask, VK_IMAGE_ASPECT_COLOR_BIT|VK_IMAGE_ASPECT_DEPTH_BIT);
CORRADE_COMPARE(out.srcSubresource.mipLevel, 3);
CORRADE_COMPARE(out.srcSubresource.baseArrayLayer, 5);
CORRADE_COMPARE(out.srcSubresource.layerCount, 7);
CORRADE_COMPARE(Vector3i{out.srcOffset}, (Vector3i{9, 11, 13}));
CORRADE_COMPARE(out.dstSubresource.aspectMask, VK_IMAGE_ASPECT_COLOR_BIT|VK_IMAGE_ASPECT_DEPTH_BIT);
CORRADE_COMPARE(out.dstSubresource.mipLevel, 4);
CORRADE_COMPARE(out.dstSubresource.baseArrayLayer, 6);
CORRADE_COMPARE(out.dstSubresource.layerCount, 8);
CORRADE_COMPARE(Vector3i{out.dstOffset}, (Vector3i{10, 12, 14}));
CORRADE_COMPARE(Vector3i{out.extent}, (Vector3i{1, 2, 15}));
}
void ImageTest::imageCopyConvertDisallowed() {
#ifdef CORRADE_NO_ASSERT
CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions");
#endif
ImageCopy copy{ImageAspect{}, 0, 0, 0, {}, 0, 0, 0, {}, {}};
copy->pNext = &copy;
std::ostringstream out;
Error redirectError{&out};
copy.vkImageCopy();
CORRADE_COMPARE(out.str(), "Vk::ImageCopy: disallowing conversion to VkImageCopy with non-empty pNext to prevent information loss\n");
}
void ImageTest::copyImageInfoConstruct() {
auto a = reinterpret_cast<VkImage>(0xdead);
auto b = reinterpret_cast<VkImage>(0xcafe);
CopyImageInfo info{a, ImageLayout::Preinitialized, b, ImageLayout::General, {
{ImageAspect::Color, 3, 0, 0, {}, 0, 0, 0, {}, {}},
{ImageAspect::Depth, 0, 5, 0, {}, 0, 0, 0, {}, {}}
}};
CORRADE_COMPARE(info->srcImage, a);
CORRADE_COMPARE(info->srcImageLayout, VK_IMAGE_LAYOUT_PREINITIALIZED);
CORRADE_COMPARE(info->dstImage, b);
CORRADE_COMPARE(info->dstImageLayout, VK_IMAGE_LAYOUT_GENERAL);
CORRADE_COMPARE(info->regionCount, 2);
CORRADE_VERIFY(info->pRegions);
CORRADE_COMPARE(info->pRegions[0].srcSubresource.aspectMask, VK_IMAGE_ASPECT_COLOR_BIT);
CORRADE_COMPARE(info->pRegions[0].srcSubresource.mipLevel, 3);
CORRADE_COMPARE(info->pRegions[1].dstSubresource.aspectMask, VK_IMAGE_ASPECT_DEPTH_BIT);
CORRADE_COMPARE(info->pRegions[1].srcSubresource.baseArrayLayer, 5);
}
void ImageTest::copyImageInfoConstructNoInit() {
CopyImageInfo info{NoInit};
info->sType = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2;
new(&info) CopyImageInfo{NoInit};
CORRADE_COMPARE(info->sType, VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2);
CORRADE_VERIFY((std::is_nothrow_constructible<CopyImageInfo, NoInitT>::value));
/* Implicit construction is not allowed */
CORRADE_VERIFY(!(std::is_convertible<NoInitT, CopyImageInfo>::value));
}
void ImageTest::copyImageInfoConstructFromVk() {
VkCopyImageInfo2KHR vkInfo;
vkInfo.sType = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2;
CopyImageInfo info{vkInfo};
CORRADE_COMPARE(info->sType, VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2);
}
void ImageTest::copyImageInfoConvertToVk() {
CopyImageInfo info{VkImage{}, ImageLayout{}, VkImage{}, ImageLayout{}, {
{ImageAspect::Color, 3, 0, 0, {}, 0, 0, 0, {}, {}},
{ImageAspect::Depth, 0, 5, 0, {}, 0, 0, 0, {}, {}}
}};
Containers::Array<VkImageCopy> copies = info.vkImageCopies();
CORRADE_COMPARE(copies.size(), 2);
CORRADE_COMPARE(copies[0].srcSubresource.aspectMask, VK_IMAGE_ASPECT_COLOR_BIT);
CORRADE_COMPARE(copies[0].srcSubresource.mipLevel, 3);
CORRADE_COMPARE(copies[1].dstSubresource.aspectMask, VK_IMAGE_ASPECT_DEPTH_BIT);
CORRADE_COMPARE(copies[1].srcSubresource.baseArrayLayer, 5);
}
void ImageTest::bufferImageCopyConstruct() {
/* It's min/max, not offset + size in the default Range constructor */
BufferImageCopy copy{3, 5, 7, ImageAspect::Stencil, 9, 11, 13, {{2, 4, 6}, {10, 14, 18}}};
CORRADE_COMPARE(copy->bufferOffset, 3);
CORRADE_COMPARE(copy->bufferRowLength, 5);
CORRADE_COMPARE(copy->bufferImageHeight, 7);
CORRADE_COMPARE(copy->imageSubresource.aspectMask, VK_IMAGE_ASPECT_STENCIL_BIT);
CORRADE_COMPARE(copy->imageSubresource.mipLevel, 9);
CORRADE_COMPARE(copy->imageSubresource.baseArrayLayer, 11);
CORRADE_COMPARE(copy->imageSubresource.layerCount, 13);
CORRADE_COMPARE(Vector3i{copy->imageOffset}, (Vector3i{2, 4, 6}));
CORRADE_COMPARE(Vector3i{copy->imageExtent}, (Vector3i{8, 10, 12}));
}
void ImageTest::bufferImageCopyConstruct1D() {
/* It's min/max, not offset + size in the default Range constructor */
BufferImageCopy1D copy{3, ImageAspect::Stencil, 9, {2, 10}};
CORRADE_COMPARE(copy->bufferOffset, 3);
CORRADE_COMPARE(copy->bufferRowLength, 0);
CORRADE_COMPARE(copy->bufferImageHeight, 0);
CORRADE_COMPARE(copy->imageSubresource.aspectMask, VK_IMAGE_ASPECT_STENCIL_BIT);
CORRADE_COMPARE(copy->imageSubresource.mipLevel, 9);
CORRADE_COMPARE(copy->imageSubresource.baseArrayLayer, 0);
CORRADE_COMPARE(copy->imageSubresource.layerCount, 1);
CORRADE_COMPARE(Vector3i{copy->imageOffset}, (Vector3i{2, 0, 0}));
CORRADE_COMPARE(Vector3i{copy->imageExtent}, (Vector3i{8, 1, 1}));
}
void ImageTest::bufferImageCopyConstruct2D() {
/* It's min/max, not offset + size in the default Range constructor */
BufferImageCopy2D copy{3, 5, ImageAspect::Stencil, 9, {{2, 4}, {10, 14}}};
CORRADE_COMPARE(copy->bufferOffset, 3);
CORRADE_COMPARE(copy->bufferRowLength, 5);
CORRADE_COMPARE(copy->bufferImageHeight, 0);
CORRADE_COMPARE(copy->imageSubresource.aspectMask, VK_IMAGE_ASPECT_STENCIL_BIT);
CORRADE_COMPARE(copy->imageSubresource.mipLevel, 9);
CORRADE_COMPARE(copy->imageSubresource.baseArrayLayer, 0);
CORRADE_COMPARE(copy->imageSubresource.layerCount, 1);
CORRADE_COMPARE(Vector3i{copy->imageOffset}, (Vector3i{2, 4, 0}));
CORRADE_COMPARE(Vector3i{copy->imageExtent}, (Vector3i{8, 10, 1}));
}
void ImageTest::bufferImageCopyConstruct3D() {
/* It's min/max, not offset + size in the default Range constructor */
BufferImageCopy3D copy{3, 5, 7, ImageAspect::Stencil, 9, {{2, 4, 6}, {10, 14, 18}}};
CORRADE_COMPARE(copy->bufferOffset, 3);
CORRADE_COMPARE(copy->bufferRowLength, 5);
CORRADE_COMPARE(copy->bufferImageHeight, 7);
CORRADE_COMPARE(copy->imageSubresource.aspectMask, VK_IMAGE_ASPECT_STENCIL_BIT);
CORRADE_COMPARE(copy->imageSubresource.mipLevel, 9);
CORRADE_COMPARE(copy->imageSubresource.baseArrayLayer, 0);
CORRADE_COMPARE(copy->imageSubresource.layerCount, 1);
CORRADE_COMPARE(Vector3i{copy->imageOffset}, (Vector3i{2, 4, 6}));
CORRADE_COMPARE(Vector3i{copy->imageExtent}, (Vector3i{8, 10, 12}));
}
void ImageTest::bufferImageCopyConstruct1DArray() {
/* It's min/max, not offset + size in the default Range constructor */
BufferImageCopy1DArray copy{3, 5, ImageAspect::Stencil, 9, {{2, 11}, {10, 24}}};
CORRADE_COMPARE(copy->bufferOffset, 3);
CORRADE_COMPARE(copy->bufferRowLength, 5);
CORRADE_COMPARE(copy->bufferImageHeight, 0);
CORRADE_COMPARE(copy->imageSubresource.aspectMask, VK_IMAGE_ASPECT_STENCIL_BIT);
CORRADE_COMPARE(copy->imageSubresource.mipLevel, 9);
CORRADE_COMPARE(copy->imageSubresource.baseArrayLayer, 11);
CORRADE_COMPARE(copy->imageSubresource.layerCount, 13);
CORRADE_COMPARE(Vector3i{copy->imageOffset}, (Vector3i{2, 0, 0}));
CORRADE_COMPARE(Vector3i{copy->imageExtent}, (Vector3i{8, 1, 1}));
}
void ImageTest::bufferImageCopyConstruct2DArray() {
/* It's min/max, not offset + size in the default Range constructor */
BufferImageCopy2DArray copy{3, 5, 7, ImageAspect::Stencil, 9, {{2, 4, 11}, {10, 14, 24}}};
CORRADE_COMPARE(copy->bufferOffset, 3);
CORRADE_COMPARE(copy->bufferRowLength, 5);
CORRADE_COMPARE(copy->bufferImageHeight, 7);
CORRADE_COMPARE(copy->imageSubresource.aspectMask, VK_IMAGE_ASPECT_STENCIL_BIT);
CORRADE_COMPARE(copy->imageSubresource.mipLevel, 9);
CORRADE_COMPARE(copy->imageSubresource.baseArrayLayer, 11);
CORRADE_COMPARE(copy->imageSubresource.layerCount, 13);
CORRADE_COMPARE(Vector3i{copy->imageOffset}, (Vector3i{2, 4, 0}));
CORRADE_COMPARE(Vector3i{copy->imageExtent}, (Vector3i{8, 10, 1}));
}
void ImageTest::bufferImageCopyConstructCubeMap() {
/* It's min/max, not offset + size in the default Range constructor */
BufferImageCopyCubeMap copy{3, 5, 7, ImageAspect::Stencil, 9, {{2, 4}, {10, 14}}};
CORRADE_COMPARE(copy->bufferOffset, 3);
CORRADE_COMPARE(copy->bufferRowLength, 5);
CORRADE_COMPARE(copy->bufferImageHeight, 7);
CORRADE_COMPARE(copy->imageSubresource.aspectMask, VK_IMAGE_ASPECT_STENCIL_BIT);
CORRADE_COMPARE(copy->imageSubresource.mipLevel, 9);
CORRADE_COMPARE(copy->imageSubresource.baseArrayLayer, 0);
CORRADE_COMPARE(copy->imageSubresource.layerCount, 6);
CORRADE_COMPARE(Vector3i{copy->imageOffset}, (Vector3i{2, 4, 0}));
CORRADE_COMPARE(Vector3i{copy->imageExtent}, (Vector3i{8, 10, 1}));
}
void ImageTest::bufferImageCopyConstructCubeMapArray() {
/* It's min/max, not offset + size in the default Range constructor */
BufferImageCopyCubeMapArray copy{3, 5, 7, ImageAspect::Stencil, 9, {{2, 4, 11}, {10, 14, 24}}};
CORRADE_COMPARE(copy->bufferOffset, 3);
CORRADE_COMPARE(copy->bufferRowLength, 5);
CORRADE_COMPARE(copy->bufferImageHeight, 7);
CORRADE_COMPARE(copy->imageSubresource.aspectMask, VK_IMAGE_ASPECT_STENCIL_BIT);
CORRADE_COMPARE(copy->imageSubresource.mipLevel, 9);
CORRADE_COMPARE(copy->imageSubresource.baseArrayLayer, 11);
CORRADE_COMPARE(copy->imageSubresource.layerCount, 13);
CORRADE_COMPARE(Vector3i{copy->imageOffset}, (Vector3i{2, 4, 0}));
CORRADE_COMPARE(Vector3i{copy->imageExtent}, (Vector3i{8, 10, 1}));
}
void ImageTest::bufferImageCopyConstructNoInit() {
BufferImageCopy copy{NoInit};
copy->sType = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2;
new(&copy) BufferImageCopy{NoInit};
CORRADE_COMPARE(copy->sType, VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2);
CORRADE_VERIFY((std::is_nothrow_constructible<BufferImageCopy, NoInitT>::value));
/* Implicit construction is not allowed */
CORRADE_VERIFY(!(std::is_convertible<NoInitT, BufferImageCopy>::value));
}
template<class From, class To> void ImageTest::bufferImageCopyConstructFromVk() {
setTestCaseTemplateName({Traits<From>::name(), Traits<To>::name()});
From from{};
from.bufferOffset = 3;
from.bufferRowLength = 5;
from.bufferImageHeight = 7;
from.imageSubresource.aspectMask = VK_IMAGE_ASPECT_STENCIL_BIT;
from.imageSubresource.mipLevel = 9;
from.imageSubresource.baseArrayLayer = 11;
from.imageSubresource.layerCount = 13;
from.imageOffset = {2, 4, 6};
from.imageExtent = {8, 10, 12};
BufferImageCopy copy{from};
To to = Traits<To>::convert(copy);
CORRADE_COMPARE(to.bufferOffset, 3);
CORRADE_COMPARE(to.bufferRowLength, 5);
CORRADE_COMPARE(to.bufferImageHeight, 7);
CORRADE_COMPARE(to.imageSubresource.aspectMask, VK_IMAGE_ASPECT_STENCIL_BIT);
CORRADE_COMPARE(to.imageSubresource.mipLevel, 9);
CORRADE_COMPARE(to.imageSubresource.baseArrayLayer, 11);
CORRADE_COMPARE(to.imageSubresource.layerCount, 13);
CORRADE_COMPARE(Vector3i{to.imageOffset}, (Vector3i{2, 4, 6}));
CORRADE_COMPARE(Vector3i{to.imageExtent}, (Vector3i{8, 10, 12}));
}
template<class T> void ImageTest::bufferImageCopyConvertToVk() {
/* It's min/max, not offset + size in the default Range constructor */
BufferImageCopy copy{3, 5, 7, ImageAspect::Stencil, 9, 11, 13, {{2, 4, 6}, {10, 14, 18}}};
T out = Traits<T>::convert(copy);
CORRADE_COMPARE(out.bufferOffset, 3);
CORRADE_COMPARE(out.bufferRowLength, 5);
CORRADE_COMPARE(out.bufferImageHeight, 7);
CORRADE_COMPARE(out.imageSubresource.aspectMask, VK_IMAGE_ASPECT_STENCIL_BIT);
CORRADE_COMPARE(out.imageSubresource.mipLevel, 9);
CORRADE_COMPARE(out.imageSubresource.baseArrayLayer, 11);
CORRADE_COMPARE(out.imageSubresource.layerCount, 13);
CORRADE_COMPARE(Vector3i{out.imageOffset}, (Vector3i{2, 4, 6}));
CORRADE_COMPARE(Vector3i{out.imageExtent}, (Vector3i{8, 10, 12}));
}
void ImageTest::bufferImageCopyConvertDisallowed() {
#ifdef CORRADE_NO_ASSERT
CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions");
#endif
BufferImageCopy copy{0, 0, 0, ImageAspect{}, 0, 0, 0, {}};
copy->pNext = &copy;
std::ostringstream out;
Error redirectError{&out};
copy.vkBufferImageCopy();
CORRADE_COMPARE(out.str(), "Vk::BufferImageCopy: disallowing conversion to VkBufferImageCopy with non-empty pNext to prevent information loss\n");
}
void ImageTest::copyBufferToImageInfoConstruct() {
auto a = reinterpret_cast<VkBuffer>(0xdead);
auto b = reinterpret_cast<VkImage>(0xcafe);
CopyBufferToImageInfo info{a, b, ImageLayout::TransferDestination, {
BufferImageCopy1D{5, ImageAspect::Color, 0, {}},
BufferImageCopy1D{0, ImageAspect::Stencil, 3, {}}
}};
CORRADE_COMPARE(info->srcBuffer, a);
CORRADE_COMPARE(info->dstImage, b);
CORRADE_COMPARE(info->dstImageLayout, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
CORRADE_COMPARE(info->regionCount, 2);
CORRADE_VERIFY(info->pRegions);
CORRADE_COMPARE(info->pRegions[0].bufferOffset, 5);
CORRADE_COMPARE(info->pRegions[0].imageSubresource.aspectMask, VK_IMAGE_ASPECT_COLOR_BIT);
CORRADE_COMPARE(info->pRegions[1].imageSubresource.aspectMask, VK_IMAGE_ASPECT_STENCIL_BIT);
CORRADE_COMPARE(info->pRegions[1].imageSubresource.mipLevel, 3);
}
void ImageTest::copyBufferToImageInfoConstructNoInit() {
CopyBufferToImageInfo info{NoInit};
info->sType = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2;
new(&info) CopyBufferToImageInfo{NoInit};
CORRADE_COMPARE(info->sType, VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2);
CORRADE_VERIFY((std::is_nothrow_constructible<CopyBufferToImageInfo, NoInitT>::value));
/* Implicit construction is not allowed */
CORRADE_VERIFY(!(std::is_convertible<NoInitT, CopyBufferToImageInfo>::value));
}
void ImageTest::copyBufferToImageInfoConstructFromVk() {
VkCopyBufferToImageInfo2KHR vkInfo;
vkInfo.sType = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2;
CopyBufferToImageInfo info{vkInfo};
CORRADE_COMPARE(info->sType, VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2);
}
void ImageTest::copyBufferToImageInfoConvertToVk() {
CopyBufferToImageInfo info{VkBuffer{}, VkImage{}, ImageLayout{}, {
BufferImageCopy1D{5, ImageAspect::Color, 0, {}},
BufferImageCopy1D{0, ImageAspect::Stencil, 3, {}},
}};
Containers::Array<VkBufferImageCopy> copies = info.vkBufferImageCopies();
CORRADE_COMPARE(copies.size(), 2);
CORRADE_COMPARE(copies[0].bufferOffset, 5);
CORRADE_COMPARE(copies[0].imageSubresource.aspectMask, VK_IMAGE_ASPECT_COLOR_BIT);
CORRADE_COMPARE(copies[1].imageSubresource.aspectMask, VK_IMAGE_ASPECT_STENCIL_BIT);
CORRADE_COMPARE(copies[1].imageSubresource.mipLevel, 3);
}
void ImageTest::copyImageToBufferInfoConstruct() {
auto a = reinterpret_cast<VkImage>(0xcafe);
auto b = reinterpret_cast<VkBuffer>(0xdead);
CopyImageToBufferInfo info{a, ImageLayout::TransferSource, b, {
BufferImageCopy1D{5, ImageAspect::Color, 0, {}},
BufferImageCopy1D{0, ImageAspect::Stencil, 3, {}}
}};
CORRADE_COMPARE(info->srcImage, a);
CORRADE_COMPARE(info->srcImageLayout, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
CORRADE_COMPARE(info->dstBuffer, b);
CORRADE_COMPARE(info->regionCount, 2);
CORRADE_VERIFY(info->pRegions);
CORRADE_COMPARE(info->pRegions[0].bufferOffset, 5);
CORRADE_COMPARE(info->pRegions[0].imageSubresource.aspectMask, VK_IMAGE_ASPECT_COLOR_BIT);
CORRADE_COMPARE(info->pRegions[1].imageSubresource.aspectMask, VK_IMAGE_ASPECT_STENCIL_BIT);
CORRADE_COMPARE(info->pRegions[1].imageSubresource.mipLevel, 3);
}
void ImageTest::copyImageToBufferInfoConstructNoInit() {
CopyImageToBufferInfo info{NoInit};
info->sType = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2;
new(&info) CopyImageToBufferInfo{NoInit};
CORRADE_COMPARE(info->sType, VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2);
CORRADE_VERIFY((std::is_nothrow_constructible<CopyImageToBufferInfo, NoInitT>::value));
/* Implicit construction is not allowed */
CORRADE_VERIFY(!(std::is_convertible<NoInitT, CopyImageToBufferInfo>::value));
}
void ImageTest::copyImageToBufferInfoConstructFromVk() {
VkCopyImageToBufferInfo2KHR vkInfo;
vkInfo.sType = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2;
CopyImageToBufferInfo info{vkInfo};
CORRADE_COMPARE(info->sType, VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2);
}
void ImageTest::copyImageToBufferInfoConvertToVk() {
CopyImageToBufferInfo info{VkImage{}, ImageLayout{}, VkBuffer{}, {
BufferImageCopy1D{5, ImageAspect::Color, 0, {}},
BufferImageCopy1D{0, ImageAspect::Stencil, 3, {}},
}};
Containers::Array<VkBufferImageCopy> copies = info.vkBufferImageCopies();
CORRADE_COMPARE(copies.size(), 2);
CORRADE_COMPARE(copies[0].bufferOffset, 5);
CORRADE_COMPARE(copies[0].imageSubresource.aspectMask, VK_IMAGE_ASPECT_COLOR_BIT);
CORRADE_COMPARE(copies[1].imageSubresource.aspectMask, VK_IMAGE_ASPECT_STENCIL_BIT);
CORRADE_COMPARE(copies[1].imageSubresource.mipLevel, 3);
}
void ImageTest::debugAspect() {
std::ostringstream out;
Debug{&out} << ImageAspect::Depth << ImageAspect(0xdeadcafe);

955
src/Magnum/Vk/Test/ImageVkTest.cpp

@ -23,13 +23,26 @@
DEALINGS IN THE SOFTWARE.
*/
#include <sstream>
#include <Corrade/Containers/Array.h>
#include <Corrade/Containers/StringView.h>
#include <Corrade/TestSuite/Compare/Container.h>
#include <Corrade/TestSuite/Compare/Numeric.h>
#include <Corrade/Utility/Algorithms.h>
#include <Corrade/Utility/DebugStl.h>
#include "Magnum/Math/Color.h"
#include "Magnum/Math/Range.h"
#include "Magnum/Vk/BufferCreateInfo.h"
#include "Magnum/Vk/CommandPoolCreateInfo.h"
#include "Magnum/Vk/CommandBuffer.h"
#include "Magnum/Vk/DeviceProperties.h"
#include "Magnum/Vk/Extensions.h"
#include "Magnum/Vk/Fence.h"
#include "Magnum/Vk/Handle.h"
#include "Magnum/Vk/ImageCreateInfo.h"
#include "Magnum/Vk/MemoryAllocateInfo.h"
#include "Magnum/Vk/Pipeline.h"
#include "Magnum/Vk/Result.h"
#include "Magnum/Vk/VulkanTester.h"
@ -57,6 +70,25 @@ struct ImageVkTest: VulkanTester {
void bindDedicatedMemory();
void directAllocation();
void cmdClearColorImageFloat();
void cmdClearColorImageSignedIntegral();
void cmdClearColorImageUnsignedIntegral();
void cmdClearDepthStencilImage();
void cmdClearDepthImage();
void cmdClearStencilImage();
void cmdCopyImage2D();
void cmdCopyImageDisallowedConversion();
void cmdCopyBufferImage1D();
void cmdCopyBufferImage2D();
void cmdCopyBufferImage3D();
void cmdCopyBufferImage1DArray();
void cmdCopyBufferImage2DArray();
void cmdCopyBufferImageCubeMap();
void cmdCopyBufferImageCubeMapArray();
void cmdCopyBufferImageDisallowedConversion();
};
ImageVkTest::ImageVkTest() {
@ -78,9 +110,31 @@ ImageVkTest::ImageVkTest() {
&ImageVkTest::bindMemory,
&ImageVkTest::bindDedicatedMemory,
&ImageVkTest::directAllocation});
&ImageVkTest::directAllocation,
&ImageVkTest::cmdClearColorImageFloat,
&ImageVkTest::cmdClearColorImageSignedIntegral,
&ImageVkTest::cmdClearColorImageUnsignedIntegral,
&ImageVkTest::cmdClearDepthStencilImage,
&ImageVkTest::cmdClearDepthImage,
&ImageVkTest::cmdClearStencilImage,
&ImageVkTest::cmdCopyImage2D,
&ImageVkTest::cmdCopyImageDisallowedConversion,
&ImageVkTest::cmdCopyBufferImage1D,
&ImageVkTest::cmdCopyBufferImage2D,
&ImageVkTest::cmdCopyBufferImage3D,
&ImageVkTest::cmdCopyBufferImage1DArray,
&ImageVkTest::cmdCopyBufferImage2DArray,
&ImageVkTest::cmdCopyBufferImageCubeMap,
&ImageVkTest::cmdCopyBufferImageCubeMapArray,
&ImageVkTest::cmdCopyBufferImageDisallowedConversion});
}
using namespace Containers::Literals;
using namespace Math::Literals;
void ImageVkTest::construct1D() {
{
Image image{device(), ImageCreateInfo1D{ImageUsage::Sampled,
@ -289,6 +343,905 @@ void ImageVkTest::directAllocation() {
CORRADE_VERIFY(image.dedicatedMemory().handle());
}
void ImageVkTest::cmdClearColorImageFloat() {
CommandPool pool{device(), CommandPoolCreateInfo{
device().properties().pickQueueFamily(QueueFlag::Graphics)}};
CommandBuffer cmd = pool.allocate();
/* To avoid going through a buffer which can guarantee the packing we want,
the tests uses a linear tiling image. These are poorly supported, have
weird paddings and the required allocation size is usually much larger
than expected. To prevent issues as much as possible, we'll thus create
images with non-insane sizes, 4-byte-aligned pixel format and explicitly
slice the mapped memory. */
/* Source image */
ImageCreateInfo2D aInfo{ImageUsage::TransferDestination,
PixelFormat::RGBA8Unorm, {4, 4}, 1, 1, ImageLayout::Undefined};
aInfo->tiling = VK_IMAGE_TILING_LINEAR;
Image a{device(), aInfo, MemoryFlag::HostVisible};
cmd.begin()
.pipelineBarrier(PipelineStage::TopOfPipe, PipelineStage::Transfer, {
{{}, Access::TransferWrite,
ImageLayout::Undefined, ImageLayout::TransferDestination, a},
})
.clearColorImage(a, ImageLayout::TransferDestination, 0xdeadc0de_rgbaf)
.pipelineBarrier(PipelineStage::Transfer, PipelineStage::Host, {
{Access::TransferWrite, Access::HostRead}
})
.end();
queue().submit({SubmitInfo{}.setCommandBuffers({cmd})}).wait();
CORRADE_COMPARE_AS(Containers::arrayCast<const Color4ub>(a.dedicatedMemory().mapRead().prefix(4*4*4)), Containers::arrayView({
0xdeadc0de_rgba, 0xdeadc0de_rgba, 0xdeadc0de_rgba, 0xdeadc0de_rgba,
0xdeadc0de_rgba, 0xdeadc0de_rgba, 0xdeadc0de_rgba, 0xdeadc0de_rgba,
0xdeadc0de_rgba, 0xdeadc0de_rgba, 0xdeadc0de_rgba, 0xdeadc0de_rgba,
0xdeadc0de_rgba, 0xdeadc0de_rgba, 0xdeadc0de_rgba, 0xdeadc0de_rgba
}), TestSuite::Compare::Container);
}
void ImageVkTest::cmdClearColorImageSignedIntegral() {
CommandPool pool{device(), CommandPoolCreateInfo{
device().properties().pickQueueFamily(QueueFlag::Graphics)}};
CommandBuffer cmd = pool.allocate();
/* To avoid going through a buffer which can guarantee the packing we want,
the tests uses a linear tiling image. These are poorly supported, have
weird paddings and the required allocation size is usually much larger
than expected. To prevent issues as much as possible, we'll thus create
images with non-insane sizes, 4-byte pixel format and explicitly slice
the mapped memory. */
/* Source image */
ImageCreateInfo2D aInfo{ImageUsage::TransferDestination,
PixelFormat::RGBA8I, {4, 4}, 1, 1, ImageLayout::Undefined};
aInfo->tiling = VK_IMAGE_TILING_LINEAR;
Image a{device(), aInfo, MemoryFlag::HostVisible};
cmd.begin()
.pipelineBarrier(PipelineStage::TopOfPipe, PipelineStage::Transfer, {
{{}, Access::TransferWrite,
ImageLayout::Undefined, ImageLayout::TransferDestination, a},
})
.clearColorImage(a, ImageLayout::TransferDestination, Vector4i{15, -7, 2, -1})
.pipelineBarrier(PipelineStage::Transfer, PipelineStage::Host, {
{Access::TransferWrite, Access::HostRead}
})
.end();
queue().submit({SubmitInfo{}.setCommandBuffers({cmd})}).wait();
CORRADE_COMPARE_AS(Containers::arrayCast<const Vector4b>(a.dedicatedMemory().mapRead().prefix(4*4*4)), Containers::arrayView<Vector4b>({
{15, -7, 2, -1}, {15, -7, 2, -1}, {15, -7, 2, -1}, {15, -7, 2, -1},
{15, -7, 2, -1}, {15, -7, 2, -1}, {15, -7, 2, -1}, {15, -7, 2, -1},
{15, -7, 2, -1}, {15, -7, 2, -1}, {15, -7, 2, -1}, {15, -7, 2, -1},
{15, -7, 2, -1}, {15, -7, 2, -1}, {15, -7, 2, -1}, {15, -7, 2, -1},
}), TestSuite::Compare::Container);
}
void ImageVkTest::cmdClearColorImageUnsignedIntegral() {
CommandPool pool{device(), CommandPoolCreateInfo{
device().properties().pickQueueFamily(QueueFlag::Graphics)}};
CommandBuffer cmd = pool.allocate();
/* To avoid going through a buffer which can guarantee the packing we want,
the tests uses a linear tiling image. These are poorly supported, have
weird paddings and the required allocation size is usually much larger
than expected. To prevent issues as much as possible, we'll thus create
images with non-insane sizes, 4-byte pixel format and explicitly slice
the mapped memory. */
/* Source image */
ImageCreateInfo2D aInfo{ImageUsage::TransferDestination,
PixelFormat::RGBA8UI, {4, 4}, 1, 1, ImageLayout::Undefined};
aInfo->tiling = VK_IMAGE_TILING_LINEAR;
Image a{device(), aInfo, MemoryFlag::HostVisible};
cmd.begin()
.pipelineBarrier(PipelineStage::TopOfPipe, PipelineStage::Transfer, {
{{}, Access::TransferWrite,
ImageLayout::Undefined, ImageLayout::TransferDestination, a},
})
.clearColorImage(a, ImageLayout::TransferDestination, Vector4ui{15, 37, 2, 1})
.pipelineBarrier(PipelineStage::Transfer, PipelineStage::Host, {
{Access::TransferWrite, Access::HostRead}
})
.end();
queue().submit({SubmitInfo{}.setCommandBuffers({cmd})}).wait();
CORRADE_COMPARE_AS(Containers::arrayCast<const Vector4ub>(a.dedicatedMemory().mapRead().prefix(4*4*4)), Containers::arrayView<Vector4ub>({
{15, 37, 2, 1}, {15, 37, 2, 1}, {15, 37, 2, 1}, {15, 37, 2, 1},
{15, 37, 2, 1}, {15, 37, 2, 1}, {15, 37, 2, 1}, {15, 37, 2, 1},
{15, 37, 2, 1}, {15, 37, 2, 1}, {15, 37, 2, 1}, {15, 37, 2, 1},
{15, 37, 2, 1}, {15, 37, 2, 1}, {15, 37, 2, 1}, {15, 37, 2, 1},
}), TestSuite::Compare::Container);
}
void ImageVkTest::cmdClearDepthStencilImage() {
CommandPool pool{device(), CommandPoolCreateInfo{
device().properties().pickQueueFamily(QueueFlag::Graphics)}};
CommandBuffer cmd = pool.allocate();
/* Depth/stencil images aren't supported in a linear tiling, so do the
verification through a buffer copy */
/* Source image */
Image a{device(), ImageCreateInfo2D{
ImageUsage::TransferDestination|ImageUsage::TransferSource,
PixelFormat::Depth32FStencil8UI, {4, 4}, 1, 1, ImageLayout::Undefined
}, MemoryFlag::DeviceLocal};
/* Destination buffers */
Buffer depth{device(), BufferCreateInfo{
BufferUsage::TransferDestination, 4*4*4
}, MemoryFlag::HostVisible};
Buffer stencil{device(), BufferCreateInfo{
BufferUsage::TransferDestination, 4*4
}, MemoryFlag::HostVisible};
cmd.begin()
.pipelineBarrier(PipelineStage::TopOfPipe, PipelineStage::Transfer, {
{{}, Access::TransferWrite,
ImageLayout::Undefined, ImageLayout::TransferDestination, a},
})
.clearDepthStencilImage(a, ImageLayout::TransferDestination, 0.75f, 133)
.pipelineBarrier(PipelineStage::Transfer, PipelineStage::Transfer, {
{Access::TransferWrite, Access::TransferRead,
ImageLayout::TransferDestination, ImageLayout::TransferSource, a},
})
.copyImageToBuffer(CopyImageToBufferInfo2D{a, ImageLayout::TransferSource, depth, {
{0, ImageAspect::Depth, 0, {{}, {4, 4}}}
}})
.copyImageToBuffer(CopyImageToBufferInfo2D{a, ImageLayout::TransferSource, stencil, {
{0, ImageAspect::Stencil, 0, {{}, {4, 4}}}
}})
.pipelineBarrier(PipelineStage::Transfer, PipelineStage::Host, {
{Access::TransferWrite, Access::HostRead}
})
.end();
queue().submit({SubmitInfo{}.setCommandBuffers({cmd})}).wait();
CORRADE_COMPARE_AS((Containers::arrayCast<const Float>(depth.dedicatedMemory().mapRead().prefix(4*4*4))), (Containers::arrayView<Float>({
0.75f, 0.75f, 0.75f, 0.75f,
0.75f, 0.75f, 0.75f, 0.75f,
0.75f, 0.75f, 0.75f, 0.75f,
0.75f, 0.75f, 0.75f, 0.75f
})), TestSuite::Compare::Container);
CORRADE_COMPARE_AS((Containers::arrayCast<const UnsignedByte>(stencil.dedicatedMemory().mapRead().prefix(4*4))), (Containers::arrayView<UnsignedByte>({
133, 133, 133, 133,
133, 133, 133, 133,
133, 133, 133, 133,
133, 133, 133, 133
})), TestSuite::Compare::Container);
}
void ImageVkTest::cmdClearDepthImage() {
CommandPool pool{device(), CommandPoolCreateInfo{
device().properties().pickQueueFamily(QueueFlag::Graphics)}};
CommandBuffer cmd = pool.allocate();
/* Depth/stencil images aren't supported in a linear tiling, so do the
verification through a buffer copy */
/* Source image */
Image a{device(), ImageCreateInfo2D{
ImageUsage::TransferDestination|ImageUsage::TransferSource,
PixelFormat::Depth32F, {4, 4}, 1, 1, ImageLayout::Undefined
}, MemoryFlag::DeviceLocal};
/* Destination buffers */
Buffer depth{device(), BufferCreateInfo{
BufferUsage::TransferDestination, 4*4*4
}, MemoryFlag::HostVisible};
cmd.begin()
.pipelineBarrier(PipelineStage::TopOfPipe, PipelineStage::Transfer, {
{{}, Access::TransferWrite,
ImageLayout::Undefined, ImageLayout::TransferDestination, a},
})
.clearDepthImage(a, ImageLayout::TransferDestination, 0.75f)
.pipelineBarrier(PipelineStage::Transfer, PipelineStage::Transfer, {
{Access::TransferWrite, Access::TransferRead,
ImageLayout::TransferDestination, ImageLayout::TransferSource, a},
})
.copyImageToBuffer(CopyImageToBufferInfo2D{a, ImageLayout::TransferSource, depth, {
{0, ImageAspect::Depth, 0, {{}, {4, 4}}}
}})
.pipelineBarrier(PipelineStage::Transfer, PipelineStage::Host, {
{Access::TransferWrite, Access::HostRead}
})
.end();
queue().submit({SubmitInfo{}.setCommandBuffers({cmd})}).wait();
CORRADE_COMPARE_AS((Containers::arrayCast<const Float>(depth.dedicatedMemory().mapRead().prefix(4*4*4))), (Containers::arrayView<Float>({
0.75f, 0.75f, 0.75f, 0.75f,
0.75f, 0.75f, 0.75f, 0.75f,
0.75f, 0.75f, 0.75f, 0.75f,
0.75f, 0.75f, 0.75f, 0.75f
})), TestSuite::Compare::Container);
}
void ImageVkTest::cmdClearStencilImage() {
CommandPool pool{device(), CommandPoolCreateInfo{
device().properties().pickQueueFamily(QueueFlag::Graphics)}};
CommandBuffer cmd = pool.allocate();
/* Depth/stencil images aren't supported in a linear tiling, so do the
verification through a buffer copy */
/* Source image */
Image a{device(), ImageCreateInfo2D{
ImageUsage::TransferDestination|ImageUsage::TransferSource,
PixelFormat::Stencil8UI, {4, 4}, 1, 1, ImageLayout::Undefined
}, MemoryFlag::DeviceLocal};
/* Destination buffers */
Buffer stencil{device(), BufferCreateInfo{
BufferUsage::TransferDestination, 4*4
}, MemoryFlag::HostVisible};
cmd.begin()
.pipelineBarrier(PipelineStage::TopOfPipe, PipelineStage::Transfer, {
{{}, Access::TransferWrite,
ImageLayout::Undefined, ImageLayout::TransferDestination, a},
})
.clearStencilImage(a, ImageLayout::TransferDestination, 133)
.pipelineBarrier(PipelineStage::Transfer, PipelineStage::Transfer, {
{Access::TransferWrite, Access::TransferRead,
ImageLayout::TransferDestination, ImageLayout::TransferSource, a},
})
.copyImageToBuffer(CopyImageToBufferInfo2D{a, ImageLayout::TransferSource, stencil, {
{0, ImageAspect::Stencil, 0, {{}, {4, 4}}}
}})
.pipelineBarrier(PipelineStage::Transfer, PipelineStage::Host, {
{Access::TransferWrite, Access::HostRead}
})
.end();
queue().submit({SubmitInfo{}.setCommandBuffers({cmd})}).wait();
CORRADE_COMPARE_AS((Containers::arrayCast<const UnsignedByte>(stencil.dedicatedMemory().mapRead().prefix(4*4))), (Containers::arrayView<UnsignedByte>({
133, 133, 133, 133,
133, 133, 133, 133,
133, 133, 133, 133,
133, 133, 133, 133
})), TestSuite::Compare::Container);
}
void ImageVkTest::cmdCopyImage2D() {
CommandPool pool{device(), CommandPoolCreateInfo{
device().properties().pickQueueFamily(QueueFlag::Graphics)}};
CommandBuffer cmd = pool.allocate();
/* To avoid going through a buffer which can guarantee the packing we want,
the tests uses a linear tiling image. These are poorly supported, have
weird paddings and the required allocation size is usually much larger
than expected. To prevent issues as much as possible, we'll thus create
images with non-insane sizes (so not 6 or 7 pixels wide, but 8), 4-byte
pixel format and explicitly slice the mapped memory. */
/* Source image */
ImageCreateInfo2D aInfo{ImageUsage::TransferSource,
PixelFormat::RGBA8UI, {8, 10}, 1, 1, ImageLayout::Preinitialized};
aInfo->tiling = VK_IMAGE_TILING_LINEAR;
Image a{device(), aInfo, MemoryFlag::HostVisible};
Utility::copy("________________________________"
"________________________________"
"________________________________"
"________________________________"
"____________AaaaAaaaAaaaAaaa____"
"____________BbbbBbbbBbbbBbbb____"
"____________CcccCcccCcccCccc____"
"____________DdddDdddDdddDddd____"
"________________________________"
"________________________________"_s, a.dedicatedMemory().map().prefix(8*10*4));
/* Destination image */
ImageCreateInfo2D bInfo{ImageUsage::TransferDestination,
PixelFormat::RGBA8UI, {8, 5}, 1};
bInfo->tiling = VK_IMAGE_TILING_LINEAR;
Image b{device(), bInfo, MemoryFlag::HostVisible};
cmd.begin()
.pipelineBarrier(PipelineStage::TopOfPipe, PipelineStage::Transfer, {
{Accesses{}, Access::TransferRead,
ImageLayout::Preinitialized, ImageLayout::TransferSource, a},
{Accesses{}, Access::TransferWrite,
ImageLayout::Undefined, ImageLayout::TransferDestination, b},
})
.clearColorImage(b, ImageLayout::TransferDestination, Vector4ui{'-'})
.pipelineBarrier(PipelineStage::Transfer, PipelineStage::Transfer, {
{Access::TransferWrite, Access::TransferWrite,
ImageLayout::TransferDestination, ImageLayout::TransferDestination, b}
})
.copyImage({a, ImageLayout::TransferSource, b, ImageLayout::TransferDestination, {
{ImageAspect::Color, 0, 0, 1, {3, 4, 0}, 0, 0, 1, {1, 1, 0}, {4, 4, 1}}
}})
.pipelineBarrier(PipelineStage::Transfer, PipelineStage::Host, {
{Access::TransferWrite, Access::HostRead,
ImageLayout::TransferDestination, ImageLayout::TransferDestination, b}
})
.end();
queue().submit({SubmitInfo{}.setCommandBuffers({cmd})}).wait();
CORRADE_COMPARE(b.dedicatedMemory().mapRead().prefix(8*5*4),
"--------------------------------"
"----AaaaAaaaAaaaAaaa------------"
"----BbbbBbbbBbbbBbbb------------"
"----CcccCcccCcccCccc------------"
"----DdddDdddDdddDddd------------"_s);
}
void ImageVkTest::cmdCopyImageDisallowedConversion() {
#ifdef CORRADE_NO_ASSERT
CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions");
#endif
if(device().isExtensionEnabled<Extensions::KHR::copy_commands2>())
CORRADE_SKIP("KHR_copy_commands2 enabled on the device, can't test");
CommandPool pool{device(), CommandPoolCreateInfo{
device().properties().pickQueueFamily(QueueFlag::Graphics)}};
CommandBuffer cmd = pool.allocate();
CopyImageInfo a{{}, {}, {}, {}, {}};
a->pNext = &a;
/* The commands shouldn't do anything, so it should be fine to just call
them without any render pass set up */
std::ostringstream out;
Error redirectError{&out};
cmd.copyImage(a);
CORRADE_COMPARE(out.str(),
"Vk::CommandBuffer::copyImage(): disallowing extraction of CopyImageInfo with non-empty pNext to prevent information loss\n");
}
void ImageVkTest::cmdCopyBufferImage1D() {
CommandPool pool{device(), CommandPoolCreateInfo{
device().properties().pickQueueFamily(QueueFlag::Graphics)}};
CommandBuffer cmd = pool.allocate();
/* Source buffer */
Buffer a{device(), BufferCreateInfo{
BufferUsage::TransferSource, 7*4
}, MemoryFlag::HostVisible};
Utility::copy("________AaaaBbbbCcccDddd____"_s, a.dedicatedMemory().map());
/* Destination & source image */
Image b{device(), ImageCreateInfo1D{
ImageUsage::TransferDestination|ImageUsage::TransferSource,
PixelFormat::RGBA8UI, 6, 1
}, MemoryFlag::HostVisible};
/* Destination buffer, clear as well */
Buffer c{device(), BufferCreateInfo{
BufferUsage::TransferDestination, 7*4
}, MemoryFlag::HostVisible};
Utility::copy("............................"_s, c.dedicatedMemory().map());
cmd.begin()
.pipelineBarrier(PipelineStage::TopOfPipe, PipelineStage::Transfer, {
{Accesses{}, Access::TransferWrite,
ImageLayout::Undefined, ImageLayout::TransferDestination, b}
})
.fillBuffer(c, 0x2e2e2e2e)
.pipelineBarrier(PipelineStage::Transfer, PipelineStage::Transfer, {
{Access::TransferWrite, Access::TransferRead, c}
})
.copyBufferToImage(CopyBufferToImageInfo1D{a, b, ImageLayout::TransferDestination, {
{2*4, ImageAspect::Color, 0, Range1Di::fromSize(2, 4)}
}})
.pipelineBarrier(PipelineStage::Transfer, PipelineStage::Transfer, {
{Access::TransferWrite, Access::TransferRead,
ImageLayout::TransferDestination, ImageLayout::TransferSource, b}
})
.copyImageToBuffer(CopyImageToBufferInfo1D{b, ImageLayout::TransferSource, c, {
{2*4, ImageAspect::Color, 0, Range1Di::fromSize(2, 4)}
}})
.pipelineBarrier(PipelineStage::Transfer, PipelineStage::Host, {
{Access::TransferWrite, Access::HostRead, c}
})
.end();
queue().submit({SubmitInfo{}.setCommandBuffers({cmd})}).wait();
CORRADE_COMPARE(arrayView(c.dedicatedMemory().mapRead()),
"........AaaaBbbbCcccDddd...."_s);
}
void ImageVkTest::cmdCopyBufferImage2D() {
CommandPool pool{device(), CommandPoolCreateInfo{
device().properties().pickQueueFamily(QueueFlag::Graphics)}};
CommandBuffer cmd = pool.allocate();
/* Source buffer */
Buffer a{device(), BufferCreateInfo{
BufferUsage::TransferSource, 7*10*4
}, MemoryFlag::HostVisible};
Utility::copy("____________________________"
"____________________________"
"____________________________"
"____________________________"
"________AaaaAaaaAaaaAaaa____"
"________BbbbBbbbBbbbBbbb____"
"________CcccCcccCcccCccc____"
"________DdddDdddDdddDddd____"
"____________________________"
"____________________________"_s, a.dedicatedMemory().map());
/* Destination & source image */
Image b{device(), ImageCreateInfo2D{
ImageUsage::TransferDestination|ImageUsage::TransferSource,
PixelFormat::RGBA8UI, {6, 5}, 1
}, MemoryFlag::HostVisible};
/* Destination buffer */
Buffer c{device(), BufferCreateInfo{
BufferUsage::TransferDestination, 7*10*4
}, MemoryFlag::HostVisible};
cmd.begin()
.pipelineBarrier(PipelineStage::TopOfPipe, PipelineStage::Transfer, {
{Accesses{}, Access::TransferWrite,
ImageLayout::Undefined, ImageLayout::TransferDestination, b}
})
.fillBuffer(c, 0x2e2e2e2e)
.pipelineBarrier(PipelineStage::Transfer, PipelineStage::Transfer, {
{Access::TransferWrite, Access::TransferRead, c}
})
.copyBufferToImage(CopyBufferToImageInfo2D{a, b, ImageLayout::TransferDestination, {
{(4*7 + 2)*4, 7, ImageAspect::Color, 0, Range2Di::fromSize({2, 1}, {4, 4})}
}})
.pipelineBarrier(PipelineStage::Transfer, PipelineStage::Transfer, {
{Access::TransferWrite, Access::TransferRead,
ImageLayout::TransferDestination, ImageLayout::TransferSource, b}
})
.copyImageToBuffer(CopyImageToBufferInfo2D{b, ImageLayout::TransferSource, c, {
{(4*7 + 2)*4, 7, ImageAspect::Color, 0, Range2Di::fromSize({2, 1}, {4, 4})}
}})
.pipelineBarrier(PipelineStage::Transfer, PipelineStage::Host, {
{Access::TransferWrite, Access::HostRead, c}
})
.end();
queue().submit({SubmitInfo{}.setCommandBuffers({cmd})}).wait();
CORRADE_COMPARE(arrayView(c.dedicatedMemory().mapRead()),
"............................"
"............................"
"............................"
"............................"
"........AaaaAaaaAaaaAaaa...."
"........BbbbBbbbBbbbBbbb...."
"........CcccCcccCcccCccc...."
"........DdddDdddDdddDddd...."
"............................"
"............................"_s);
}
void ImageVkTest::cmdCopyBufferImage3D() {
CommandPool pool{device(), CommandPoolCreateInfo{
device().properties().pickQueueFamily(QueueFlag::Graphics)}};
CommandBuffer cmd = pool.allocate();
/* Source buffer */
Buffer a{device(), BufferCreateInfo{
BufferUsage::TransferSource, 6*7*2*4
}, MemoryFlag::HostVisible};
Utility::copy("________________________"
"________________________"
"________________________"
"________AaaaAaaaAaaa____"
"________BbbbBbbbBbbb____"
"________CcccCcccCccc____"
"________________________"
"________________________"
"________________________"
"________________________"
"________DdddDdddDddd____"
"________EeeeEeeeEeee____"
"________FfffFfffFfff____"
"________________________"_s, a.dedicatedMemory().map());
/* Destination & source image */
Image b{device(), ImageCreateInfo3D{
ImageUsage::TransferDestination|ImageUsage::TransferSource,
PixelFormat::RGBA8UI, {5, 4, 3}, 1
}, MemoryFlag::HostVisible};
/* Destination buffer */
Buffer c{device(), BufferCreateInfo{
BufferUsage::TransferDestination, 6*7*2*4
}, MemoryFlag::HostVisible};
cmd.begin()
.pipelineBarrier(PipelineStage::TopOfPipe, PipelineStage::Transfer, {
{Accesses{}, Access::TransferWrite,
ImageLayout::Undefined, ImageLayout::TransferDestination, b}
})
.fillBuffer(c, 0x2e2e2e2e)
.pipelineBarrier(PipelineStage::Transfer, PipelineStage::Transfer, {
{Access::TransferWrite, Access::TransferRead, c}
})
.copyBufferToImage(CopyBufferToImageInfo3D{a, b, ImageLayout::TransferDestination, {
{(3*6 + 2)*4, 6, 7, ImageAspect::Color, 0, Range3Di::fromSize({2, 1, 1}, {3, 3, 2})}
}})
.pipelineBarrier(PipelineStage::Transfer, PipelineStage::Transfer, {
{Access::TransferWrite, Access::TransferRead,
ImageLayout::TransferDestination, ImageLayout::TransferSource, b}
})
.copyImageToBuffer(CopyImageToBufferInfo3D{b, ImageLayout::TransferSource, c, {
{(3*6 + 2)*4, 6, 7, ImageAspect::Color, 0, Range3Di::fromSize({2, 1, 1}, {3, 3, 2})}
}})
.pipelineBarrier(PipelineStage::Transfer, PipelineStage::Host, {
{Access::TransferWrite, Access::HostRead, c}
})
.end();
queue().submit({SubmitInfo{}.setCommandBuffers({cmd})}).wait();
CORRADE_COMPARE(arrayView(c.dedicatedMemory().mapRead()),
"........................"
"........................"
"........................"
"........AaaaAaaaAaaa...."
"........BbbbBbbbBbbb...."
"........CcccCcccCccc...."
"........................"
"........................"
"........................"
"........................"
"........DdddDdddDddd...."
"........EeeeEeeeEeee...."
"........FfffFfffFfff...."
"........................"_s);
}
void ImageVkTest::cmdCopyBufferImage1DArray() {
CommandPool pool{device(), CommandPoolCreateInfo{
device().properties().pickQueueFamily(QueueFlag::Graphics)}};
CommandBuffer cmd = pool.allocate();
/* Source buffer */
Buffer a{device(), BufferCreateInfo{
BufferUsage::TransferSource, 6*5*4
}, MemoryFlag::HostVisible};
Utility::copy("________________________"
"________________________"
"________AaaaAaaaAaaa____"
"________BbbbBbbbBbbb____"
"________________________"_s, a.dedicatedMemory().map());
/* Destination & source image */
Image b{device(), ImageCreateInfo1DArray{
ImageUsage::TransferDestination|ImageUsage::TransferSource,
PixelFormat::RGBA8UI, {4, 3}, 1
}, MemoryFlag::HostVisible};
/* Destination buffer */
Buffer c{device(), BufferCreateInfo{BufferUsage::TransferDestination, 6*5*4}, MemoryFlag::HostVisible};
cmd.begin()
.pipelineBarrier(PipelineStage::TopOfPipe, PipelineStage::Transfer, {
{Accesses{}, Access::TransferWrite,
ImageLayout::Undefined, ImageLayout::TransferDestination, b}
})
.fillBuffer(c, 0x2e2e2e2e)
.pipelineBarrier(PipelineStage::Transfer, PipelineStage::Transfer, {
{Access::TransferWrite, Access::TransferRead, c}
})
.copyBufferToImage(CopyBufferToImageInfo1DArray{a, b, ImageLayout::TransferDestination, {
{(2*6 + 2)*4, 6, ImageAspect::Color, 0, Range2Di::fromSize({1, 1}, {3, 2})}
}})
.pipelineBarrier(PipelineStage::Transfer, PipelineStage::Transfer, {
{Access::TransferWrite, Access::TransferRead,
ImageLayout::TransferDestination, ImageLayout::TransferSource, b}
})
.copyImageToBuffer(CopyImageToBufferInfo1DArray{b, ImageLayout::TransferSource, c, {
{(2*6 + 2)*4, 6, ImageAspect::Color, 0, Range2Di::fromSize({1, 1}, {3, 2})}
}})
.pipelineBarrier(PipelineStage::Transfer, PipelineStage::Host, {
{Access::TransferWrite, Access::HostRead, c}
})
.end();
queue().submit({SubmitInfo{}.setCommandBuffers({cmd})}).wait();
CORRADE_COMPARE(arrayView(c.dedicatedMemory().mapRead()),
"........................"
"........................"
"........AaaaAaaaAaaa...."
"........BbbbBbbbBbbb...."
"........................"_s);
}
void ImageVkTest::cmdCopyBufferImage2DArray() {
CommandPool pool{device(), CommandPoolCreateInfo{
device().properties().pickQueueFamily(QueueFlag::Graphics)}};
CommandBuffer cmd = pool.allocate();
/* Source buffer */
Buffer a{device(), BufferCreateInfo{
BufferUsage::TransferSource, 4*5*2*4
}, MemoryFlag::HostVisible};
Utility::copy("____________________"
"________AaaaAaaa____"
"________BbbbBbbb____"
"____________________"
"____________________"
"________CcccCccc____"
"________DdddDddd____"
"____________________"_s, a.dedicatedMemory().map());
/* Destination & source image */
Image b{device(), ImageCreateInfo2DArray{
ImageUsage::TransferDestination|ImageUsage::TransferSource,
PixelFormat::RGBA8UI, {4, 4, 3}, 1
}, MemoryFlag::HostVisible};
/* Destination buffer */
Buffer c{device(), BufferCreateInfo{BufferUsage::TransferDestination, 4*5*2*4}, MemoryFlag::HostVisible};
cmd.begin()
.pipelineBarrier(PipelineStage::TopOfPipe, PipelineStage::Transfer, {
{Accesses{}, Access::TransferWrite,
ImageLayout::Undefined, ImageLayout::TransferDestination, b}
})
.fillBuffer(c, 0x2e2e2e2e)
.pipelineBarrier(PipelineStage::Transfer, PipelineStage::Transfer, {
{Access::TransferWrite, Access::TransferRead, c}
})
.copyBufferToImage(CopyBufferToImageInfo2DArray{a, b, ImageLayout::TransferDestination, {
{(1*5 + 2)*4, 5, 4, ImageAspect::Color, 0, Range3Di::fromSize({2, 1, 1}, {2, 2, 2})}
}})
.pipelineBarrier(PipelineStage::Transfer, PipelineStage::Transfer, {
{Access::TransferWrite, Access::TransferRead,
ImageLayout::TransferDestination, ImageLayout::TransferSource, b}
})
.copyImageToBuffer(CopyImageToBufferInfo2DArray{b, ImageLayout::TransferSource, c, {
{(1*5 + 2)*4, 5, 4, ImageAspect::Color, 0, Range3Di::fromSize({2, 1, 1}, {2, 2, 2})}
}})
.pipelineBarrier(PipelineStage::Transfer, PipelineStage::Host, {
{Access::TransferWrite, Access::HostRead, c}
})
.end();
queue().submit({SubmitInfo{}.setCommandBuffers({cmd})}).wait();
CORRADE_COMPARE(arrayView(c.dedicatedMemory().mapRead()),
"...................."
"........AaaaAaaa...."
"........BbbbBbbb...."
"...................."
"...................."
"........CcccCccc...."
"........DdddDddd...."
"...................."_s);
}
void ImageVkTest::cmdCopyBufferImageCubeMap() {
CommandPool pool{device(), CommandPoolCreateInfo{
device().properties().pickQueueFamily(QueueFlag::Graphics)}};
CommandBuffer cmd = pool.allocate();
/* Source buffer */
Buffer a{device(), BufferCreateInfo{
BufferUsage::TransferSource, 3*4*6*4
}, MemoryFlag::HostVisible};
Utility::copy("________________"
"________Aaaa____"
"________Bbbb____"
"________________"
"________Cccc____"
"________Dddd____"
"________________"
"________Eeee____"
"________Ffff____"
"________________"
"________Gggg____"
"________Hhhh____"
"________________"
"________Iiii____"
"________Jjjj____"
"________________"
"________Kkkk____"
"________Llll____"_s, a.dedicatedMemory().map());
/* Destination & source image */
Image b{device(), ImageCreateInfoCubeMap{
ImageUsage::TransferDestination|ImageUsage::TransferSource,
PixelFormat::RGBA8UI, {4, 4}, 1
}, MemoryFlag::HostVisible};
/* Destination buffer */
Buffer c{device(), BufferCreateInfo{
BufferUsage::TransferDestination, 3*4*6*4
}, MemoryFlag::HostVisible};
cmd.begin()
.pipelineBarrier(PipelineStage::TopOfPipe, PipelineStage::Transfer, {
{Accesses{}, Access::TransferWrite,
ImageLayout::Undefined, ImageLayout::TransferDestination, b}
})
.fillBuffer(c, 0x2e2e2e2e)
.pipelineBarrier(PipelineStage::Transfer, PipelineStage::Transfer, {
{Access::TransferWrite, Access::TransferRead, c}
})
.copyBufferToImage(CopyBufferToImageInfoCubeMap{a, b, ImageLayout::TransferDestination, {
{(1*4 + 2)*4, 4, 3, ImageAspect::Color, 0, Range2Di::fromSize({3, 1}, {1, 2})}
}})
.pipelineBarrier(PipelineStage::Transfer, PipelineStage::Transfer, {
{Access::TransferWrite, Access::TransferRead,
ImageLayout::TransferDestination, ImageLayout::TransferSource, b}
})
.copyImageToBuffer(CopyImageToBufferInfoCubeMap{b, ImageLayout::TransferSource, c, {
{(1*4 + 2)*4, 4, 3, ImageAspect::Color, 0, Range2Di::fromSize({3, 1}, {1, 2})}
}})
.pipelineBarrier(PipelineStage::Transfer, PipelineStage::Host, {
{Access::TransferWrite, Access::HostRead, c}
})
.end();
queue().submit({SubmitInfo{}.setCommandBuffers({cmd})}).wait();
CORRADE_COMPARE(arrayView(c.dedicatedMemory().mapRead()),
"................"
"........Aaaa...."
"........Bbbb...."
"................"
"........Cccc...."
"........Dddd...."
"................"
"........Eeee...."
"........Ffff...."
"................"
"........Gggg...."
"........Hhhh...."
"................"
"........Iiii...."
"........Jjjj...."
"................"
"........Kkkk...."
"........Llll...."_s);
}
void ImageVkTest::cmdCopyBufferImageCubeMapArray() {
CommandPool pool{device(), CommandPoolCreateInfo{
device().properties().pickQueueFamily(QueueFlag::Graphics)}};
CommandBuffer cmd = pool.allocate();
/* Source buffer */
Buffer a{device(), BufferCreateInfo{
BufferUsage::TransferSource, 3*4*7*4
}, MemoryFlag::HostVisible};
Utility::copy("________________"
"________Aaaa____"
"________Bbbb____"
"________________"
"________Cccc____"
"________Dddd____"
"________________"
"________Eeee____"
"________Ffff____"
"________________"
"________Gggg____"
"________Hhhh____"
"________________"
"________Iiii____"
"________Jjjj____"
"________________"
"________Kkkk____"
"________Llll____"
"________________"
"________Mmmm____"
"________Nnnn____"_s, a.dedicatedMemory().map());
/* Destination & source image */
Image b{device(), ImageCreateInfoCubeMapArray{
ImageUsage::TransferDestination|ImageUsage::TransferSource,
PixelFormat::RGBA8UI, {4, 4, 8}, 1
}, MemoryFlag::HostVisible};
/* Destination buffer */
Buffer c{device(), BufferCreateInfo{BufferUsage::TransferDestination, 3*4*7*4}, MemoryFlag::HostVisible};
cmd.begin()
.pipelineBarrier(PipelineStage::TopOfPipe, PipelineStage::Transfer, {
{Accesses{}, Access::TransferWrite,
ImageLayout::Undefined, ImageLayout::TransferDestination, b}
})
.fillBuffer(c, 0x2e2e2e2e)
.pipelineBarrier(PipelineStage::Transfer, PipelineStage::Transfer, {
{Access::TransferWrite, Access::TransferRead, c}
})
.copyBufferToImage(CopyBufferToImageInfoCubeMapArray{a, b, ImageLayout::TransferDestination, {
{(1*4 + 2)*4, 4, 3, ImageAspect::Color, 0, Range3Di::fromSize({3, 1, 1}, {1, 2, 7})}
}})
.pipelineBarrier(PipelineStage::Transfer, PipelineStage::Transfer, {
{Access::TransferWrite, Access::TransferRead,
ImageLayout::TransferDestination, ImageLayout::TransferSource, b}
})
.copyImageToBuffer(CopyImageToBufferInfoCubeMapArray{b, ImageLayout::TransferSource, c, {
{(1*4 + 2)*4, 4, 3, ImageAspect::Color, 0, Range3Di::fromSize({3, 1, 1}, {1, 2, 7})}
}})
.pipelineBarrier(PipelineStage::Transfer, PipelineStage::Host, {
{Access::TransferWrite, Access::HostRead, c}
})
.end();
queue().submit({SubmitInfo{}.setCommandBuffers({cmd})}).wait();
CORRADE_COMPARE(arrayView(c.dedicatedMemory().mapRead()),
"................"
"........Aaaa...."
"........Bbbb...."
"................"
"........Cccc...."
"........Dddd...."
"................"
"........Eeee...."
"........Ffff...."
"................"
"........Gggg...."
"........Hhhh...."
"................"
"........Iiii...."
"........Jjjj...."
"................"
"........Kkkk...."
"........Llll...."
"................"
"........Mmmm...."
"........Nnnn...."_s);
}
void ImageVkTest::cmdCopyBufferImageDisallowedConversion() {
#ifdef CORRADE_NO_ASSERT
CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions");
#endif
if(device().isExtensionEnabled<Extensions::KHR::copy_commands2>())
CORRADE_SKIP("KHR_copy_commands2 enabled on the device, can't test");
CommandPool pool{device(), CommandPoolCreateInfo{
device().properties().pickQueueFamily(QueueFlag::Graphics)}};
CommandBuffer cmd = pool.allocate();
CopyBufferToImageInfo a{{}, {}, {}, {}};
a->pNext = &a;
CopyImageToBufferInfo b{{}, {}, {}, {}};
b->pNext = &b;
/* The commands shouldn't do anything, so it should be fine to just call
them without any render pass set up */
std::ostringstream out;
Error redirectError{&out};
cmd.copyBufferToImage(a)
.copyImageToBuffer(b);
CORRADE_COMPARE(out.str(),
"Vk::CommandBuffer::copyBufferToImage(): disallowing extraction of CopyBufferToImageInfo with non-empty pNext to prevent information loss\n"
"Vk::CommandBuffer::copyImageToBuffer(): disallowing extraction of CopyImageToBufferInfo with non-empty pNext to prevent information loss\n");
}
}}}}
CORRADE_TEST_MAIN(Magnum::Vk::Test::ImageVkTest)

9
src/Magnum/Vk/Vk.h

@ -45,6 +45,15 @@ class CommandBuffer;
/* CommandBufferBeginInfo is useful only in combination with CommandBuffer */
class CommandPool;
class CommandPoolCreateInfo;
/* BufferCopy used only directly inside CopyBufferInfo */
class CopyBufferInfo;
/* ImageCopy used only directly inside CopyImageInfo */
class CopyImageInfo;
/* BufferImageCopy used only directly inside CopyBufferToImageInfo /
CopyImageToBufferInfo */
class CopyBufferToImageInfo;
class CopyImageToBufferInfo;
/* Not forward-declaring CopyBufferToImageInfo1D etc right now, I see no need */
enum class DependencyFlag: UnsignedInt;
typedef Containers::EnumSet<DependencyFlag> DependencyFlags;
class Device;

Loading…
Cancel
Save