diff --git a/doc/snippets/MagnumVk.cpp b/doc/snippets/MagnumVk.cpp index afa35a132..1f88b1846 100644 --- a/doc/snippets/MagnumVk.cpp +++ b/doc/snippets/MagnumVk.cpp @@ -41,6 +41,7 @@ #include "Magnum/Vk/InstanceCreateInfo.h" #include "Magnum/Vk/Integration.h" #include "Magnum/Vk/ImageCreateInfo.h" +#include "Magnum/Vk/ImageViewCreateInfo.h" #include "Magnum/Vk/LayerProperties.h" #include "Magnum/Vk/MemoryAllocateInfo.h" #include "Magnum/Vk/Queue.h" @@ -324,6 +325,23 @@ image.bindMemory(memory, 0); /* [Image-creation-custom-allocation] */ } +{ +Vk::Device device{NoCreate}; +/* The include should be a no-op here since it was already included above */ +/* [ImageView-creation] */ +#include + +DOXYGEN_IGNORE() + +Vk::Image image{device, Vk::ImageCreateInfo2DArray{ /* created before */ + DOXYGEN_IGNORE(Vk::ImageUsage::Sampled, {}, {}, 1) + }, DOXYGEN_IGNORE(Vk::MemoryFlag::DeviceLocal) +}; + +Vk::ImageView view{device, Vk::ImageViewCreateInfo2DArray{image}}; +/* [ImageView-creation] */ +} + { int argc{}; const char** argv{}; diff --git a/doc/vulkan-mapping.dox b/doc/vulkan-mapping.dox index 89180a174..d8f439e50 100644 --- a/doc/vulkan-mapping.dox +++ b/doc/vulkan-mapping.dox @@ -152,7 +152,7 @@ Vulkan function | Matching API @fn_vk{CreateFence}, \n @fn_vk{DestroyFence} | | @fn_vk{CreateFramebuffer}, \n @fn_vk{DestroyFramebuffer} | | @fn_vk{CreateImage}, \n @fn_vk{DestroyImage} | @ref Image constructor and destructor -@fn_vk{CreateImageView}, \n @fn_vk{DestroyImageView} | | +@fn_vk{CreateImageView}, \n @fn_vk{DestroyImageView} | @ref ImageView constructor and destructor @fn_vk{CreateInstance}, \n @fn_vk{DestroyInstance} | @ref Instance constructor and destructor @fn_vk{CreatePipeline}, \n @fn_vk{DestroyPipeline} | | @fn_vk{CreatePipelineCache}, \n @fn_vk{DestroyPipelineCache} | | @@ -492,14 +492,14 @@ Vulkan structure | Matching API @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** | | -@type_vk{ImageSubresourceRange} | | +@type_vk{ImageSubresourceRange} | not exposed, internal to @ref ImageViewCreateInfo @type_vk{ImageMemoryBarrier} | | @type_vk{ImageMemoryRequirementsInfo}, \n @type_vk{ImageMemoryRequirementsInfo2} @m_class{m-label m-flat m-success} **KHR, 1.1** | not exposed, internal to @ref Image::memoryRequirements() @type_vk{ImagePlaneMemoryRequirementsInfo} @m_class{m-label m-flat m-success} **KHR, 1.1** | | @type_vk{ImageResolve} | | @type_vk{ImageSparseMemoryRequirementsInfo2} @m_class{m-label m-flat m-success} **KHR, 1.1** | | @type_vk{ImageStencilUsageCreateInfo} @m_class{m-label m-flat m-success} **EXT, 1.2** | | -@type_vk{ImageViewCreateInfo} | | +@type_vk{ImageViewCreateInfo} | @ref ImageViewCreateInfo @type_vk{ImageViewUsageCreateInfo} @m_class{m-label m-flat m-success} **KHR, 1.1** | | @type_vk{InputAttachmentAspectReference} | | @type_vk{InstanceCreateInfo} | @ref InstanceCreateInfo diff --git a/src/Magnum/Vk/CMakeLists.txt b/src/Magnum/Vk/CMakeLists.txt index 3656adacb..03061c353 100644 --- a/src/Magnum/Vk/CMakeLists.txt +++ b/src/Magnum/Vk/CMakeLists.txt @@ -48,6 +48,7 @@ set(MagnumVk_GracefulAssert_SRCS Enums.cpp ExtensionProperties.cpp Image.cpp + ImageView.cpp LayerProperties.cpp Memory.cpp RenderPass.cpp) @@ -69,6 +70,8 @@ set(MagnumVk_HEADERS Handle.h Image.h ImageCreateInfo.h + ImageView.h + ImageViewCreateInfo.h Instance.h InstanceCreateInfo.h Integration.h diff --git a/src/Magnum/Vk/Image.cpp b/src/Magnum/Vk/Image.cpp index a97dd8923..a616c9097 100644 --- a/src/Magnum/Vk/Image.cpp +++ b/src/Magnum/Vk/Image.cpp @@ -60,15 +60,16 @@ ImageCreateInfo::ImageCreateInfo(const VkImageCreateInfo& info): member instead of doing a copy */ _info(info) {} -Image Image::wrap(Device& device, const VkImage handle, const HandleFlags flags) { +Image Image::wrap(Device& device, const VkImage handle, const VkFormat format, const HandleFlags flags) { Image out{NoCreate}; out._device = &device; out._handle = handle; out._flags = flags; + out._format = format; return out; } -Image::Image(Device& device, const ImageCreateInfo& info, NoAllocateT): _device{&device}, _flags{HandleFlag::DestroyOnDestruction}, _dedicatedMemory{NoCreate} { +Image::Image(Device& device, const ImageCreateInfo& info, NoAllocateT): _device{&device}, _flags{HandleFlag::DestroyOnDestruction}, _format{info->format}, _dedicatedMemory{NoCreate} { MAGNUM_VK_INTERNAL_ASSERT_SUCCESS(device->CreateImage(device, info, nullptr, &_handle)); } @@ -80,9 +81,9 @@ Image::Image(Device& device, const ImageCreateInfo& info, const MemoryFlags memo }}); } -Image::Image(NoCreateT): _device{}, _handle{}, _dedicatedMemory{NoCreate} {} +Image::Image(NoCreateT): _device{}, _handle{}, _format{}, _dedicatedMemory{NoCreate} {} -Image::Image(Image&& other) noexcept: _device{other._device}, _handle{other._handle}, _flags{other._flags}, _dedicatedMemory{std::move(other._dedicatedMemory)} { +Image::Image(Image&& other) noexcept: _device{other._device}, _handle{other._handle}, _flags{other._flags}, _format{other._format}, _dedicatedMemory{std::move(other._dedicatedMemory)} { other._handle = {}; } @@ -96,6 +97,7 @@ Image& Image::operator=(Image&& other) noexcept { swap(other._device, _device); swap(other._handle, _handle); swap(other._flags, _flags); + swap(other._format, _format); swap(other._dedicatedMemory, _dedicatedMemory); return *this; } diff --git a/src/Magnum/Vk/Image.h b/src/Magnum/Vk/Image.h index ce58b770d..2821589d1 100644 --- a/src/Magnum/Vk/Image.h +++ b/src/Magnum/Vk/Image.h @@ -166,6 +166,8 @@ constructor together with specifying @ref MemoryFlags for memory allocation. accessible through @ref dedicatedMemory(). This behavior may change in the future. +With an @ref Image ready, you may want to proceed to @ref ImageView creation. + @subsection Vk-Image-creation-custom-allocation Custom memory allocation Using @ref Image(Device&, const ImageCreateInfo&, NoAllocateT), the image will @@ -188,16 +190,23 @@ class MAGNUM_VK_EXPORT Image { public: /** * @brief Wrap existing Vulkan handle - * @param device Vulkan device the image is created on - * @param handle The @type_vk{Image} handle - * @param flags Handle flags + * @param device Vulkan device the image is created on + * @param handle The @type_vk{Image} handle + * @param format Image format + * @param flags Handle flags + * + * The @p handle is expected to be originating from @p device. The + * @p format parameter is used for convenience @ref ImageView creation. + * If it's unknown, use @val_vk{FORMAT_UNDEFINED,Format} --- you will + * then be able to only create image views by passing a concrete format + * to @ref ImageViewCreateInfo. * - * The @p handle is expected to be originating from @p device. Unlike - * an image created using a constructor, the Vulkan image is by default - * not deleted on destruction, use @p flags for different behavior. + * Unlike an image created using a constructor, the Vulkan image is by + * default not deleted on destruction, use @p flags for different + * behavior. * @see @ref release() */ - static Image wrap(Device& device, VkImage handle, HandleFlags flags = {}); + static Image wrap(Device& device, VkImage handle, VkFormat format, HandleFlags flags = {}); /** * @brief Construct an image without allocating @@ -265,6 +274,9 @@ class MAGNUM_VK_EXPORT Image { /** @brief Handle flags */ HandleFlags handleFlags() const { return _flags; } + /** @brief Image format */ + VkFormat format() const { return _format; } + /** * @brief Image memory requirements * @@ -336,6 +348,19 @@ class MAGNUM_VK_EXPORT Image { VkImage _handle; HandleFlags _flags; + + /* On 64-bit there would be a 7 byte padding after _flags otherwise, we + can use that to store information about image format for convenient + view creation. On 32-bit it won't fit, but the extra memory use is + still worth the advantages. + + Originally I wanted to store a desired VkImageViewType here as well, + but the logic to what actually should be the view type is rather + involved and not safe to rely on (e.g., implicit view type would be + 2D_ARRAY if there's more than one layer and then if you'd use just + one layer it suddenly becomes just 2D, breaking everything). */ + VkFormat _format; + Memory _dedicatedMemory; }; diff --git a/src/Magnum/Vk/ImageCreateInfo.h b/src/Magnum/Vk/ImageCreateInfo.h index b16cc6577..eda2a2341 100644 --- a/src/Magnum/Vk/ImageCreateInfo.h +++ b/src/Magnum/Vk/ImageCreateInfo.h @@ -239,7 +239,9 @@ CORRADE_ENUMSET_OPERATORS(ImageCreateInfo::Flags) Compared to the base @ref ImageCreateInfo constructor creates an image of type @val_vk{IMAGE_TYPE_1D,ImageType} with the last two `size` components and -`layers` set to @cpp 1 @ce. +`layers` set to @cpp 1 @ce. You can use both @ref ImageViewCreateInfo1D and +@ref ImageViewCreateInfo1DArray for view creation, although the array will need +to have only one layer. Note that same as with the @ref ImageCreateInfo::ImageCreateInfo(VkImageType, ImageUsages, VkFormat, const Vector3i&, Int, Int, Int, ImageLayout, Flags) @@ -264,7 +266,9 @@ class ImageCreateInfo1D: public ImageCreateInfo { Compared to the base @ref ImageCreateInfo constructor creates an image of type @val_vk{IMAGE_TYPE_2D,ImageType} with the last `size` component and `layers` -set to @cpp 1 @ce. +set to @cpp 1 @ce. You can use both @ref ImageViewCreateInfo2D and +@ref ImageViewCreateInfo2DArray for view creation, although the array will need +to have only one layer. Note that same as with the @ref ImageCreateInfo::ImageCreateInfo(VkImageType, ImageUsages, VkFormat, const Vector3i&, Int, Int, Int, ImageLayout, Flags) @@ -288,7 +292,8 @@ class ImageCreateInfo2D: public ImageCreateInfo { @m_since_latest Compared to the base @ref ImageCreateInfo constructor creates an image of type -@val_vk{IMAGE_TYPE_3D,ImageType} with `layers` set to @cpp 1 @ce. +@val_vk{IMAGE_TYPE_3D,ImageType} with `layers` set to @cpp 1 @ce. Use +@ref ImageViewCreateInfo3D for view creation. Note that same as with the @ref ImageCreateInfo::ImageCreateInfo(VkImageType, ImageUsages, VkFormat, const Vector3i&, Int, Int, Int, ImageLayout, Flags) @@ -313,7 +318,9 @@ class ImageCreateInfo3D: public ImageCreateInfo { Compared to the base @ref ImageCreateInfo constructor creates an image of type @val_vk{IMAGE_TYPE_1D,ImageType} with the last two `size` components set to -@cpp 1 @ce and `layers` set to @cpp size.y() @ce. +@cpp 1 @ce and `layers` set to @cpp size.y() @ce. You can use both +@ref ImageViewCreateInfo1D and @ref ImageViewCreateInfo1DArray for view +creation. Note that same as with the @ref ImageCreateInfo::ImageCreateInfo(VkImageType, ImageUsages, VkFormat, const Vector3i&, Int, Int, Int, ImageLayout, Flags) @@ -338,7 +345,11 @@ class ImageCreateInfo1DArray: public ImageCreateInfo { Compared to the base @ref ImageCreateInfo constructor creates an image of type @val_vk{IMAGE_TYPE_2D,ImageType} with the last `size` component set to -@cpp 1 @ce and `layers` set to @cpp size.z() @ce. +@cpp 1 @ce and `layers` set to @cpp size.z() @ce. You can use both +@ref ImageViewCreateInfo2D, @ref ImageViewCreateInfo2DArray for view creation +and if you set @ref Flag::CubeCompatible a @ref ImageViewCreateInfoCubeMap as +well, although in that case it's better to use @ref ImageCreateInfoCubeMap that +does this automatically. Note that same as with the @ref ImageCreateInfo::ImageCreateInfo(VkImageType, ImageUsages, VkFormat, const Vector3i&, Int, Int, Int, ImageLayout, Flags) @@ -364,7 +375,11 @@ class ImageCreateInfo2DArray: public ImageCreateInfo { Compared to the base @ref ImageCreateInfo constructor creates an image of type @val_vk{IMAGE_TYPE_2D,ImageType} with the last `size` component set to @cpp 1 @ce, `layers` set to @cpp 6 @ce and `flags` additionally having -@ref Flag::CubeCompatible. +@ref Flag::CubeCompatible. You can use any of @ref ImageViewCreateInfo2D, +@ref ImageViewCreateInfo2DArray, @ref ImageViewCreateInfoCubeMap or +@ref ImageViewCreateInfoCubeMapArray for view creation, although the last one +will need to have exactly six layers, and requires +@ref DeviceFeature::ImageCubeArray to be enabled. Note that same as with the @ref ImageCreateInfo::ImageCreateInfo(VkImageType, ImageUsages, VkFormat, const Vector3i&, Int, Int, Int, ImageLayout, Flags) @@ -390,7 +405,10 @@ class ImageCreateInfoCubeMap: public ImageCreateInfo { Compared to the base @ref ImageCreateInfo constructor creates an image of type @val_vk{IMAGE_TYPE_2D,ImageType} with the last `size` component set to @cpp 1 @ce, `layers` set to @cpp size.y() @ce and `flags` additionally having -@ref Flag::CubeCompatible. +@ref Flag::CubeCompatible. You can use any of @ref ImageViewCreateInfo2D, +@ref ImageViewCreateInfo2DArray, @ref ImageViewCreateInfoCubeMap or +@ref ImageViewCreateInfoCubeMapArray for view creation, note the last +requires @ref DeviceFeature::ImageCubeArray to be enabled. Note that same as with the @ref ImageCreateInfo::ImageCreateInfo(VkImageType, ImageUsages, VkFormat, const Vector3i&, Int, Int, Int, ImageLayout, Flags) diff --git a/src/Magnum/Vk/ImageView.cpp b/src/Magnum/Vk/ImageView.cpp new file mode 100644 index 000000000..abee6cb77 --- /dev/null +++ b/src/Magnum/Vk/ImageView.cpp @@ -0,0 +1,119 @@ +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, + 2020 Vladimír Vondruš + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +#include "ImageView.h" +#include "ImageViewCreateInfo.h" + +#include "Magnum/Vk/Assert.h" +#include "Magnum/Vk/Device.h" +#include "Magnum/Vk/Image.h" + +namespace Magnum { namespace Vk { + +namespace { + +/* Vulkan, it would kill you if 0 was a valid default, right?! ffs */ +/** @todo this might be useful elsewhere as well */ +VkImageAspectFlags aspectFor(const VkFormat format) { + if(format == VK_FORMAT_D16_UNORM_S8_UINT || + format == VK_FORMAT_D24_UNORM_S8_UINT || + format == VK_FORMAT_D32_SFLOAT_S8_UINT) + return VK_IMAGE_ASPECT_DEPTH_BIT|VK_IMAGE_ASPECT_STENCIL_BIT; + if(format == VK_FORMAT_D16_UNORM || + format == VK_FORMAT_D32_SFLOAT) + return VK_IMAGE_ASPECT_DEPTH_BIT; + if(format == VK_FORMAT_S8_UINT) + return VK_IMAGE_ASPECT_STENCIL_BIT; + + /** @todo planar formats */ + + return VK_IMAGE_ASPECT_COLOR_BIT; +} + +} + +ImageViewCreateInfo::ImageViewCreateInfo(const VkImageViewType type, const VkImage image, const VkFormat format, const UnsignedInt layerOffset, const UnsignedInt layerCount, const UnsignedInt levelOffset, const UnsignedInt levelCount, const Flags flags): _info{} { + _info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; + _info.flags = VkImageViewCreateFlags(flags); + _info.image = image; + _info.viewType = type; + _info.format = format; + _info.subresourceRange.aspectMask = aspectFor(format); + _info.subresourceRange.baseMipLevel = levelOffset; + _info.subresourceRange.levelCount = levelCount; + _info.subresourceRange.baseArrayLayer = layerOffset; + _info.subresourceRange.layerCount = layerCount; +} + +ImageViewCreateInfo::ImageViewCreateInfo(const VkImageViewType type, Image& image, const UnsignedInt layerOffset, const UnsignedInt layerCount, const UnsignedInt levelOffset, const UnsignedInt levelCount, const Flags flags): ImageViewCreateInfo{type, image, image.format(), layerOffset, layerCount, levelOffset, levelCount, flags} { + CORRADE_ASSERT(image.format(), + "Vk::ImageViewCreateInfo: the image has unknown format, you have to specify it explicitly", ); +} + +ImageViewCreateInfo::ImageViewCreateInfo(NoInitT) noexcept {} + +ImageViewCreateInfo::ImageViewCreateInfo(const VkImageViewCreateInfo& info): + /* Can't use {} with GCC 4.8 here because it tries to initialize the first + member instead of doing a copy */ + _info(info) {} + +ImageView ImageView::wrap(Device& device, const VkImageView handle, const HandleFlags flags) { + ImageView out{NoCreate}; + out._device = &device; + out._handle = handle; + out._flags = flags; + return out; +} + +ImageView::ImageView(Device& device, const ImageViewCreateInfo& info): _device{&device}, _flags{HandleFlag::DestroyOnDestruction} { + MAGNUM_VK_INTERNAL_ASSERT_SUCCESS(device->CreateImageView(device, info, nullptr, &_handle)); +} + +ImageView::ImageView(NoCreateT): _device{}, _handle{} {} + +ImageView::ImageView(ImageView&& other) noexcept: _device{other._device}, _handle{other._handle}, _flags{other._flags} { + other._handle = {}; +} + +ImageView::~ImageView() { + if(_handle && (_flags & HandleFlag::DestroyOnDestruction)) + (**_device).DestroyImageView(*_device, _handle, nullptr); +} + +ImageView& ImageView::operator=(ImageView&& other) noexcept { + using std::swap; + swap(other._device, _device); + swap(other._handle, _handle); + swap(other._flags, _flags); + return *this; +} + +VkImageView ImageView::release() { + const VkImageView handle = _handle; + _handle = {}; + return handle; +} + +}} diff --git a/src/Magnum/Vk/ImageView.h b/src/Magnum/Vk/ImageView.h new file mode 100644 index 000000000..43a404e66 --- /dev/null +++ b/src/Magnum/Vk/ImageView.h @@ -0,0 +1,148 @@ +#ifndef Magnum_Vk_ImageView_h +#define Magnum_Vk_ImageView_h +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, + 2020 Vladimír Vondruš + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +/** @file + * @brief Class @ref Magnum::Vk::ImageView + * @m_since_latest + */ + +#include "Magnum/Magnum.h" +#include "Magnum/Tags.h" +#include "Magnum/Vk/Handle.h" +#include "Magnum/Vk/Vk.h" +#include "Magnum/Vk/Vulkan.h" +#include "Magnum/Vk/visibility.h" + +namespace Magnum { namespace Vk { + +/** +@brief Image view +@m_since_latest + +View onto an @ref Image. Wraps a @type_vk_keyword{ImageView}. + +@section Vk-ImageView-creation Image view creation + +Similarly to @ref Image, a view is created by passing one of the +@ref ImageViewCreateInfo subclasses with desired layer/level range to the +@ref Image constructor. Commonly you'd use the same @ref ImageViewCreateInfo +subclass as @ref ImageCreateInfo, but other combinations are possible as well +--- see docs of each subclass for more information. + +@snippet MagnumVk.cpp ImageView-creation + +While it would be *technically* possible to infer a view type from the +originating @ref Image and thus avoid having to specify the type twice, the +mapping isn't crystal clear in all cases and could cause hard-to-detect issues +if you suddenly get an unexpected view type. Thus the view type is required to +be always explicitly specified. +*/ +class MAGNUM_VK_EXPORT ImageView { + public: + /** + * @brief Wrap existing Vulkan handle + * @param device Vulkan device the image view is created on + * @param handle The @type_vk{ImageView} handle + * @param flags Handle flags + * + * The @p handle is expected to be originating from @p device. Unlike + * an image view created using a constructor, the Vulkan image view is + * by default not deleted on destruction, use @p flags for different + * behavior. + * @see @ref release() + */ + static ImageView wrap(Device& device, VkImageView handle, HandleFlags flags = {}); + + /** + * @brief Constructor + * @param device Vulkan device to create the image on + * @param info Image creation info + * + * @see @fn_vk_keyword{CreateImageView} + */ + explicit ImageView(Device& device, const ImageViewCreateInfo& info); + + /** + * @brief Construct without creating the image + * + * The constructed instance is equivalent to moved-from state. Useful + * in cases where you will overwrite the instance later anyway. Move + * another object over it to make it useful. + */ + explicit ImageView(NoCreateT); + + /** @brief Copying is not allowed */ + ImageView(const ImageView&) = delete; + + /** @brief Move constructor */ + ImageView(ImageView&& other) noexcept; + + /** + * @brief Destructor + * + * Destroys associated @type_vk{ImageView} handle, unless the instance + * was created using @ref wrap() without + * @ref HandleFlag::DestroyOnDestruction specified. + * @see @fn_vk_keyword{DestroyImageView}, @ref release() + */ + ~ImageView(); + + /** @brief Copying is not allowed */ + ImageView& operator=(const ImageView&) = delete; + + /** @brief Move assignment */ + ImageView& operator=(ImageView&& other) noexcept; + + /** @brief Underlying @type_vk{ImageView} handle */ + VkImageView handle() { return _handle; } + /** @overload */ + operator VkImageView() { return _handle; } + + /** @brief Handle flags */ + HandleFlags handleFlags() const { return _flags; } + + /** + * @brief Release the underlying Vulkan image view + * + * Releases ownership of the Vulkan image view and returns its handle + * so @fn_vk{DestroyImageView} is not called on destruction. The + * internal state is then equivalent to moved-from state. + * @see @ref wrap() + */ + VkImageView release(); + + private: + /* Can't be a reference because of the NoCreate constructor */ + Device* _device; + + VkImageView _handle; + HandleFlags _flags; +}; + +}} + +#endif diff --git a/src/Magnum/Vk/ImageViewCreateInfo.h b/src/Magnum/Vk/ImageViewCreateInfo.h new file mode 100644 index 000000000..e494d1e19 --- /dev/null +++ b/src/Magnum/Vk/ImageViewCreateInfo.h @@ -0,0 +1,336 @@ +#ifndef Magnum_Vk_ImageViewCreateInfo_h +#define Magnum_Vk_ImageViewCreateInfo_h +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, + 2020 Vladimír Vondruš + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +/** @file + * @brief Class @ref Magnum::Vk::ImageViewCreateInfo, @ref Magnum::Vk::ImageViewCreateInfo1D, @ref Magnum::Vk::ImageViewCreateInfo2D, @ref Magnum::Vk::ImageViewCreateInfo3D, @ref Magnum::Vk::ImageViewCreateInfo1DArray, @ref Magnum::Vk::ImageViewCreateInfo2DArray, @ref Magnum::Vk::ImageViewCreateInfoCubeMap, @ref Magnum::Vk::ImageViewCreateInfoCubeMapArray + * @m_since_latest + */ + +#include + +#include "Magnum/Magnum.h" +#include "Magnum/Tags.h" +#include "Magnum/Vk/Vk.h" +#include "Magnum/Vk/Vulkan.h" +#include "Magnum/Vk/visibility.h" + +namespace Magnum { namespace Vk { + +/** +@brief Image view creation info +@m_since_latest + +Wraps a @type_vk_keyword{ImageViewCreateInfo}. See +@ref Vk-ImageView-creation "Image creation" for usage information. +@see @ref ImageViewCreateInfo1D, @ref ImageViewCreateInfo2D, + @ref ImageViewCreateInfo3D, @ref ImageViewCreateInfo1DArray, + @ref ImageViewCreateInfo2DArray, @ref ImageViewCreateInfoCubeMap, + @ref ImageViewCreateInfoCubeMapArray +*/ +class MAGNUM_VK_EXPORT ImageViewCreateInfo { + public: + /** + * @brief Image view creation flag + * + * Wraps @type_vk_keyword{ImageViewCreateFlagBits}. + * @see @ref Flags, @ref ImageViewCreateInfo(VkImageViewType, VkImage, VkFormat, UnsignedInt, UnsignedInt, UnsignedInt, UnsignedInt, Flags) + * @m_enum_values_as_keywords + */ + enum class Flag: UnsignedInt { + /** @todo @vk_extension{EXT,fragment_density_map}, @vk_extension{EXT,fragment_density_map2} */ + }; + + /** + * @brief ImageView creation flags + * + * Type-safe wrapper for @type_vk_keyword{ImageViewCreateFlags}. + * @see @ref ImageViewCreateInfo(VkImageViewType, VkImage, VkFormat, UnsignedInt, UnsignedInt, UnsignedInt, UnsignedInt, Flags) + */ + typedef Containers::EnumSet Flags; + + /** + * @brief Constructor + * @param type Image view type + * @param image Image to create a view on + * @param format View format + * @param layerOffset Layer offset + * @param layerCount Layer count + * @param levelOffset Mip level offset + * @param levelCount Mip level count + * @param flags Image view creation flags + * + * The following @type_vk{ImageViewCreateInfo} are pre-filled in + * addition to `sType`, everything else is zero-filled: + * + * - `flags` + * - `image` + * - `viewType` to @p type + * - `format` + * - `subresourceRange.aspectMask` to + * @val_vk{IMAGE_ASPECT_DEPTH_BIT,ImageAspectFlagBits} / + * @val_vk{IMAGE_ASPECT_STENCIL_BIT,ImageAspectFlagBits} if + * @p format is depth / stencil or both and + * @val_vk{IMAGE_ASPECT_COLOR_BIT,ImageAspectFlagBits} otherwise + * - `subresourceRange.levelOffset` to @p levelOffset + * - `subresourceRange.levelCount` to @p levelCount + * - `subresourceRange.baseArrayLayer` to @p layerOffset + * - `subresourceRange.layerCount` to @p layerCount + * + * The @p type and @p format has to be compatible with @p image and + * the mip level and layer sub-range has to be in bounds. For creating + * a view that exactly matches the image type and format, use the + * @ref ImageViewCreateInfo(VkImageViewType, Image&, UnsignedInt, UnsignedInt, UnsignedInt, UnsignedInt, Flags) + * constructor. Otherwise, similarly as with @ref ImageCreateInfo, for + * common view types you're encouraged to make use of + * @ref ImageViewCreateInfo1D, @ref ImageViewCreateInfo2D, + * @ref ImageViewCreateInfo3D, @ref ImageViewCreateInfo1DArray, + * @ref ImageViewCreateInfo2DArray, @ref ImageViewCreateInfoCubeMap and + * @ref ImageViewCreateInfoCubeMapArray convenience classes instead of + * this constructor. + */ + explicit ImageViewCreateInfo(VkImageViewType type, VkImage image, VkFormat format, UnsignedInt layerOffset = 0, UnsignedInt layerCount = VK_REMAINING_ARRAY_LAYERS, UnsignedInt levelOffset = 0, UnsignedInt levelCount = VK_REMAINING_MIP_LEVELS, Flags flags = {}); + + /** + * @brief Construct with format matching given image + * + * Compared to @ref ImageViewCreateInfo(VkImageViewType, VkImage, VkFormat, UnsignedInt, UnsignedInt, UnsignedInt, UnsignedInt, Flags) + * the @p format is taken from the passed @ref Image instance. + */ + explicit ImageViewCreateInfo(VkImageViewType type, Image& image, UnsignedInt layerOffset = 0, UnsignedInt layerCount = VK_REMAINING_ARRAY_LAYERS, UnsignedInt levelOffset = 0, UnsignedInt levelCount = VK_REMAINING_MIP_LEVELS, Flags flags = {}); + + /** + * @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 ImageViewCreateInfo(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 ImageViewCreateInfo(const VkImageViewCreateInfo& info); + + /** @brief Underlying @type_vk{BufferCreateInfo} structure */ + VkImageViewCreateInfo& operator*() { return _info; } + /** @overload */ + const VkImageViewCreateInfo& operator*() const { return _info; } + /** @overload */ + VkImageViewCreateInfo* operator->() { return &_info; } + /** @overload */ + const VkImageViewCreateInfo* operator->() const { return &_info; } + /** @overload */ + operator const VkImageViewCreateInfo*() const { return &_info; } + + private: + VkImageViewCreateInfo _info; +}; + +CORRADE_ENUMSET_OPERATORS(ImageViewCreateInfo::Flags) + +/** +@brief Convenience constructor for 1D image views +@m_since_latest + +Compared to the base @ref ImageViewCreateInfo constructor creates a view of +type @val_vk{IMAGE_VIEW_TYPE_1D,ImageViewType} with @p layerCount set to +@cpp 1 @ce. The original image is expected to be a +@val_vk{IMAGE_TYPE_1D,ImageType} (e.g., created using @ref ImageCreateInfo1D or +@ref ImageCreateInfo1DArray). +*/ +class ImageViewCreateInfo1D: public ImageViewCreateInfo { + public: + /** @brief Constructor */ + explicit ImageViewCreateInfo1D(VkImage image, VkFormat format, UnsignedInt layerOffset = 0, UnsignedInt levelOffset = 0, UnsignedInt levelCount = VK_REMAINING_MIP_LEVELS, Flags flags = {}): ImageViewCreateInfo{VK_IMAGE_VIEW_TYPE_1D, image, format, layerOffset, 1, levelOffset, levelCount, flags} {} + + /** @overload + * + * Compared to the above, @p format is taken from the passed @ref Image + * instance. + */ + explicit ImageViewCreateInfo1D(Image& image, UnsignedInt layerOffset = 0, UnsignedInt levelOffset = 0, UnsignedInt levelCount = VK_REMAINING_MIP_LEVELS, Flags flags = {}): ImageViewCreateInfo{VK_IMAGE_VIEW_TYPE_1D, image, layerOffset, 1, levelOffset, levelCount, flags} {} +}; + +/** +@brief Convenience constructor for 2D image views +@m_since_latest + +Compared to the base @ref ImageViewCreateInfo constructor creates a view of +type @val_vk{IMAGE_VIEW_TYPE_2D,ImageViewType} with @p layerCount set to +@cpp 1 @ce. The original image is expected to be a +@val_vk{IMAGE_TYPE_2D,ImageType} (e.g., created using @ref ImageCreateInfo2D, +@ref ImageCreateInfo2DArray, @ref ImageCreateInfoCubeMap or +@ref ImageCreateInfoCubeMapArray). +@todo also mention 3D once we have Flag::2DArrayCompatible + (@vk_extension{KHR,maintenance1}) exposed, restricted additionally with + @vk_extension{KHR,portability_subset} +*/ +class ImageViewCreateInfo2D: public ImageViewCreateInfo { + public: + /** @brief Constructor */ + explicit ImageViewCreateInfo2D(VkImage image, VkFormat format, UnsignedInt layerOffset = 0, UnsignedInt levelOffset = 0, UnsignedInt levelCount = VK_REMAINING_MIP_LEVELS, Flags flags = {}): ImageViewCreateInfo{VK_IMAGE_VIEW_TYPE_2D, image, format, layerOffset, 1, levelOffset, levelCount, flags} {} + + /** @overload + * + * Compared to the above, @p format is taken from the passed @ref Image + * instance. + */ + explicit ImageViewCreateInfo2D(Image& image, UnsignedInt layerOffset = 0, UnsignedInt levelOffset = 0, UnsignedInt levelCount = VK_REMAINING_MIP_LEVELS, Flags flags = {}): ImageViewCreateInfo{VK_IMAGE_VIEW_TYPE_2D, image, layerOffset, 1, levelOffset, levelCount, flags} {} +}; + +/** +@brief Convenience constructor for 3D image views +@m_since_latest + +Compared to the base @ref ImageViewCreateInfo constructor creates a view of +type @val_vk{IMAGE_VIEW_TYPE_3D,ImageViewType} with @p layerCount set to +@cpp 1 @ce. The original image is expected to be a +@val_vk{IMAGE_TYPE_2D,ImageType} (e.g., created using @ref ImageCreateInfo3D). +*/ +class ImageViewCreateInfo3D: public ImageViewCreateInfo { + public: + /** @brief Constructor */ + explicit ImageViewCreateInfo3D(VkImage image, VkFormat format, UnsignedInt layerOffset = 0, UnsignedInt levelOffset = 0, UnsignedInt levelCount = VK_REMAINING_MIP_LEVELS, Flags flags = {}): ImageViewCreateInfo{VK_IMAGE_VIEW_TYPE_3D, image, format, layerOffset, 1, levelOffset, levelCount, flags} {} + + /** @overload + * + * Compared to the above, @p format is taken from the passed @ref Image + * instance. + */ + explicit ImageViewCreateInfo3D(Image& image, UnsignedInt layerOffset = 0, UnsignedInt levelOffset = 0, UnsignedInt levelCount = VK_REMAINING_MIP_LEVELS, Flags flags = {}): ImageViewCreateInfo{VK_IMAGE_VIEW_TYPE_3D, image, layerOffset, 1, levelOffset, levelCount, flags} {} +}; + +/** +@brief Convenience constructor for 1D array image views +@m_since_latest + +Compared to the base @ref ImageViewCreateInfo constructor creates a view of +type @val_vk{IMAGE_VIEW_TYPE_1D_ARRAY,ImageViewType}. The original image is +expected to be a @val_vk{IMAGE_TYPE_1D,ImageType} (e.g., created using +@ref ImageCreateInfo1D or @ref ImageCreateInfo1DArray) with enough array layers +to fit the required subrange. +*/ +class ImageViewCreateInfo1DArray: public ImageViewCreateInfo { + public: + /** @brief Constructor */ + explicit ImageViewCreateInfo1DArray(VkImage image, VkFormat format, UnsignedInt layerOffset = 0, UnsignedInt layerCount = VK_REMAINING_ARRAY_LAYERS, UnsignedInt levelOffset = 0, UnsignedInt levelCount = VK_REMAINING_MIP_LEVELS, Flags flags = {}): ImageViewCreateInfo{VK_IMAGE_VIEW_TYPE_1D_ARRAY, image, format, layerOffset, layerCount, levelOffset, levelCount, flags} {} + + /** @overload + * + * Compared to the above, @p format is taken from the passed @ref Image + * instance. + */ + explicit ImageViewCreateInfo1DArray(Image& image, UnsignedInt layerOffset = 0, UnsignedInt layerCount = VK_REMAINING_ARRAY_LAYERS, UnsignedInt levelOffset = 0, UnsignedInt levelCount = VK_REMAINING_MIP_LEVELS, Flags flags = {}): ImageViewCreateInfo{VK_IMAGE_VIEW_TYPE_1D_ARRAY, image, layerOffset, layerCount, levelOffset, levelCount, flags} {} +}; + +/** +@brief Convenience constructor for 2D array image views +@m_since_latest + +Compared to the base @ref ImageViewCreateInfo constructor creates a view of +type @val_vk{IMAGE_VIEW_TYPE_2D_ARRAY,ImageViewType}. The original image is +expected to be a @val_vk{IMAGE_TYPE_2D,ImageType} (e.g., created using +@ref ImageCreateInfo2D, @ref ImageCreateInfoCubeMap or +@ref ImageCreateInfoCubeMapArray) with enough array layers to fit the required +subrange. +@todo also mention 3D once we have Flag::2DArrayCompatible + (@vk_extension{KHR,maintenance1}) exposed, restricted additionally with + @vk_extension{KHR,portability_subset} +*/ +class ImageViewCreateInfo2DArray: public ImageViewCreateInfo { + public: + /** @brief Constructor */ + explicit ImageViewCreateInfo2DArray(VkImage image, VkFormat format, UnsignedInt layerOffset = 0, UnsignedInt layerCount = VK_REMAINING_ARRAY_LAYERS, UnsignedInt levelOffset = 0, UnsignedInt levelCount = VK_REMAINING_MIP_LEVELS, Flags flags = {}): ImageViewCreateInfo{VK_IMAGE_VIEW_TYPE_2D_ARRAY, image, format, layerOffset, layerCount, levelOffset, levelCount, flags} {} + + /** @overload + * + * Compared to the above, @p format is taken from the passed @ref Image + * instance. + */ + explicit ImageViewCreateInfo2DArray(Image& image, UnsignedInt layerOffset = 0, UnsignedInt layerCount = VK_REMAINING_ARRAY_LAYERS, UnsignedInt levelOffset = 0, UnsignedInt levelCount = VK_REMAINING_MIP_LEVELS, Flags flags = {}): ImageViewCreateInfo{VK_IMAGE_VIEW_TYPE_2D_ARRAY, image, layerOffset, layerCount, levelOffset, levelCount, flags} {} +}; + +/** +@brief Convenience constructor for cube map image views +@m_since_latest + +Compared to the base @ref ImageViewCreateInfo constructor creates a view of +type @val_vk{IMAGE_VIEW_TYPE_CUBE,ImageViewType} with @p layerCount set to +@cpp 6 @ce. The original image is expected to be a +@val_vk{IMAGE_TYPE_2D,ImageType} with @ref ImageCreateInfo::Flag::CubeCompatible +set (e.g., created using @ref ImageCreateInfoCubeMap or +@ref ImageCreateInfoCubeMapArray). +*/ +class ImageViewCreateInfoCubeMap: public ImageViewCreateInfo { + public: + /** @brief Constructor */ + explicit ImageViewCreateInfoCubeMap(VkImage image, VkFormat format, UnsignedInt layerOffset = 0, UnsignedInt levelOffset = 0, UnsignedInt levelCount = VK_REMAINING_MIP_LEVELS, Flags flags = {}): ImageViewCreateInfo{VK_IMAGE_VIEW_TYPE_CUBE, image, format, layerOffset, 6, levelOffset, levelCount, flags} {} + + /** @overload + * + * Compared to the above, @p format is taken from the passed @ref Image + * instance. + */ + explicit ImageViewCreateInfoCubeMap(Image& image, UnsignedInt layerOffset = 0, UnsignedInt levelOffset = 0, UnsignedInt levelCount = VK_REMAINING_MIP_LEVELS, Flags flags = {}): ImageViewCreateInfo{VK_IMAGE_VIEW_TYPE_CUBE, image, layerOffset, 6, levelOffset, levelCount, flags} {} +}; + +/** +@brief Convenience constructor for cube map array image views +@m_since_latest + +Compared to the base @ref ImageViewCreateInfo constructor creates a view of +type @val_vk{IMAGE_VIEW_TYPE_CUBE_ARRAY,ImageViewType}. The original image is +expected to be a @val_vk{IMAGE_TYPE_2D,ImageType} with +@ref ImageCreateInfo::Flag::CubeCompatible set (e.g., created using +@ref ImageCreateInfoCubeMap or @ref ImageCreateInfoCubeMapArray) with enough +array layers to fit the required subrange. +@requires_vk_feature @ref DeviceFeature::ImageCubeArray +*/ +class ImageViewCreateInfoCubeMapArray: public ImageViewCreateInfo { + public: + /** @brief Constructor */ + explicit ImageViewCreateInfoCubeMapArray(VkImage image, VkFormat format, UnsignedInt layerOffset = 0, UnsignedInt layerCount = VK_REMAINING_ARRAY_LAYERS, UnsignedInt levelOffset = 0, UnsignedInt levelCount = VK_REMAINING_MIP_LEVELS, Flags flags = {}): ImageViewCreateInfo{VK_IMAGE_VIEW_TYPE_CUBE_ARRAY, image, format, layerOffset, layerCount, levelOffset, levelCount, flags} {} + + /** @overload + * + * Compared to the above, @p format is taken from the passed @ref Image + * instance. + */ + explicit ImageViewCreateInfoCubeMapArray(Image& image, UnsignedInt layerOffset = 0, UnsignedInt layerCount = VK_REMAINING_ARRAY_LAYERS, UnsignedInt levelOffset = 0, UnsignedInt levelCount = VK_REMAINING_MIP_LEVELS, Flags flags = {}): ImageViewCreateInfo{VK_IMAGE_VIEW_TYPE_CUBE_ARRAY, image, layerOffset, layerCount, levelOffset, levelCount, flags} {} +}; + +}} + +/* Make the definition complete -- it doesn't make sense to have a CreateInfo + without the corresponding object anyway. */ +#include "Magnum/Vk/ImageView.h" + +#endif diff --git a/src/Magnum/Vk/Test/CMakeLists.txt b/src/Magnum/Vk/Test/CMakeLists.txt index 5430790f3..0a371ce63 100644 --- a/src/Magnum/Vk/Test/CMakeLists.txt +++ b/src/Magnum/Vk/Test/CMakeLists.txt @@ -35,6 +35,7 @@ corrade_add_test(VkExtensionsTest ExtensionsTest.cpp LIBRARIES MagnumVk) corrade_add_test(VkExtensionPropertiesTest ExtensionPropertiesTest.cpp LIBRARIES MagnumVk) corrade_add_test(VkHandleTest HandleTest.cpp LIBRARIES MagnumVk) corrade_add_test(VkImageTest ImageTest.cpp LIBRARIES MagnumVkTestLib) +corrade_add_test(VkImageViewTest ImageViewTest.cpp LIBRARIES MagnumVkTestLib) corrade_add_test(VkInstanceTest InstanceTest.cpp LIBRARIES MagnumVk) corrade_add_test(VkIntegrationTest IntegrationTest.cpp LIBRARIES MagnumVk) corrade_add_test(VkLayerPropertiesTest LayerPropertiesTest.cpp LIBRARIES MagnumVk) @@ -123,6 +124,7 @@ set_target_properties( VkExtensionPropertiesTest VkHandleTest VkImageTest + VkImageViewTest VkInstanceTest VkIntegrationTest VkLayerPropertiesTest @@ -152,6 +154,7 @@ if(BUILD_VK_TESTS) corrade_add_test(VkExtensionPropertiesVkTest ExtensionPropertiesVkTest.cpp LIBRARIES MagnumVkTestLib) corrade_add_test(VkLayerPropertiesVkTest LayerPropertiesVkTest.cpp LIBRARIES MagnumVkTestLib) corrade_add_test(VkImageVkTest ImageVkTest.cpp LIBRARIES MagnumVk MagnumVulkanTester) + corrade_add_test(VkImageViewVkTest ImageViewVkTest.cpp LIBRARIES MagnumVk MagnumVulkanTester) corrade_add_test(VkInstanceVkTest InstanceVkTest.cpp LIBRARIES MagnumVk) corrade_add_test(VkMemoryVkTest MemoryVkTest.cpp LIBRARIES MagnumVk MagnumVulkanTester) corrade_add_test(VkRenderPassVkTest RenderPassVkTest.cpp LIBRARIES MagnumVkTestLib MagnumVulkanTester) @@ -168,6 +171,7 @@ if(BUILD_VK_TESTS) VkExtensionPropertiesVkTest VkLayerPropertiesVkTest VkImageVkTest + VkImageViewVkTest VkInstanceVkTest VkMemoryVkTest VkRenderPassVkTest diff --git a/src/Magnum/Vk/Test/ImageViewTest.cpp b/src/Magnum/Vk/Test/ImageViewTest.cpp new file mode 100644 index 000000000..5cfd3fb83 --- /dev/null +++ b/src/Magnum/Vk/Test/ImageViewTest.cpp @@ -0,0 +1,408 @@ +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, + 2020 Vladimír Vondruš + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +#include +#include +#include +#include + +#include "Magnum/Vk/Device.h" +#include "Magnum/Vk/Image.h" +#include "Magnum/Vk/ImageViewCreateInfo.h" + +namespace Magnum { namespace Vk { namespace Test { namespace { + +struct ImageViewTest: TestSuite::Tester { + explicit ImageViewTest(); + + void createInfoConstruct(); + void createInfoConstructFromImage(); + void createInfoConstructFromImageFormatUknown(); + void createInfoConstruct1D(); + void createInfoConstruct1DFromImage(); + void createInfoConstruct2D(); + void createInfoConstruct2DFromImage(); + void createInfoConstruct3D(); + void createInfoConstruct3DFromImage(); + void createInfoConstruct1DArray(); + void createInfoConstruct1DArrayFromImage(); + void createInfoConstruct2DArray(); + void createInfoConstruct2DArrayFromImage(); + void createInfoConstructCubeMap(); + void createInfoConstructCubeMapFromImage(); + void createInfoConstructCubeMapArray(); + void createInfoConstructCubeMapArrayFromImage(); + void createInfoConstructNoInit(); + void createInfoConstructFromVk(); + + void constructNoCreate(); + void constructCopy(); +}; + +const struct { + const char* name; + VkFormat format; + VkImageAspectFlags aspect; +} View2DFormatData[] { + {"color", VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_ASPECT_COLOR_BIT}, + {"depth + stencil", VK_FORMAT_D32_SFLOAT_S8_UINT, VK_IMAGE_ASPECT_DEPTH_BIT|VK_IMAGE_ASPECT_STENCIL_BIT}, + {"depth", VK_FORMAT_D16_UNORM, VK_IMAGE_ASPECT_DEPTH_BIT}, + {"stencil", VK_FORMAT_S8_UINT, VK_IMAGE_ASPECT_STENCIL_BIT} +}; + +ImageViewTest::ImageViewTest() { + addTests({&ImageViewTest::createInfoConstruct, + &ImageViewTest::createInfoConstructFromImage, + &ImageViewTest::createInfoConstructFromImageFormatUknown, + &ImageViewTest::createInfoConstruct1D, + &ImageViewTest::createInfoConstruct1DFromImage}); + + addInstancedTests({&ImageViewTest::createInfoConstruct2D}, + Containers::arraySize(View2DFormatData)); + + addTests({&ImageViewTest::createInfoConstruct2DFromImage, + &ImageViewTest::createInfoConstruct3D, + &ImageViewTest::createInfoConstruct3DFromImage, + &ImageViewTest::createInfoConstruct1DArray, + &ImageViewTest::createInfoConstruct1DArrayFromImage, + &ImageViewTest::createInfoConstruct2DArray, + &ImageViewTest::createInfoConstruct2DArrayFromImage, + &ImageViewTest::createInfoConstructCubeMap, + &ImageViewTest::createInfoConstructCubeMapFromImage, + &ImageViewTest::createInfoConstructCubeMapArray, + &ImageViewTest::createInfoConstructCubeMapArrayFromImage, + &ImageViewTest::createInfoConstructNoInit, + &ImageViewTest::createInfoConstructFromVk, + + &ImageViewTest::constructNoCreate, + &ImageViewTest::constructCopy}); +} + +const VkImage imageHandle{reinterpret_cast(0xdeadbeef)}; + +void ImageViewTest::createInfoConstruct() { + /** @todo use a real flag once it exists */ + ImageViewCreateInfo info{VK_IMAGE_VIEW_TYPE_2D, imageHandle, VK_FORMAT_R8G8B8A8_SRGB, 3, 5, 7, 9, ImageViewCreateInfo::Flag(VK_NOT_READY)}; + CORRADE_COMPARE(info->flags, VK_NOT_READY); + CORRADE_COMPARE(info->image, imageHandle); + CORRADE_COMPARE(info->viewType, VK_IMAGE_VIEW_TYPE_2D); + CORRADE_COMPARE(info->format, VK_FORMAT_R8G8B8A8_SRGB); + CORRADE_COMPARE(info->subresourceRange.aspectMask, VK_IMAGE_ASPECT_COLOR_BIT); + CORRADE_COMPARE(info->subresourceRange.baseArrayLayer, 3); + CORRADE_COMPARE(info->subresourceRange.layerCount, 5); + CORRADE_COMPARE(info->subresourceRange.baseMipLevel, 7); + CORRADE_COMPARE(info->subresourceRange.levelCount, 9); +} + +void ImageViewTest::createInfoConstructFromImage() { + Device device{NoCreate}; + Image image = Image::wrap(device, imageHandle, VK_FORMAT_R8G8B8A8_SRGB); + + /** @todo use a real flag once it exists */ + ImageViewCreateInfo info{VK_IMAGE_VIEW_TYPE_2D, image, 3, 5, 7, 9, ImageViewCreateInfo::Flag(VK_NOT_READY)}; + CORRADE_COMPARE(info->flags, VK_NOT_READY); + CORRADE_COMPARE(info->image, imageHandle); + CORRADE_COMPARE(info->viewType, VK_IMAGE_VIEW_TYPE_2D); + CORRADE_COMPARE(info->format, VK_FORMAT_R8G8B8A8_SRGB); + CORRADE_COMPARE(info->subresourceRange.aspectMask, VK_IMAGE_ASPECT_COLOR_BIT); + CORRADE_COMPARE(info->subresourceRange.baseArrayLayer, 3); + CORRADE_COMPARE(info->subresourceRange.layerCount, 5); + CORRADE_COMPARE(info->subresourceRange.baseMipLevel, 7); + CORRADE_COMPARE(info->subresourceRange.levelCount, 9); +} + +void ImageViewTest::createInfoConstructFromImageFormatUknown() { + #ifdef CORRADE_NO_ASSERT + CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions"); + #endif + + Device device{NoCreate}; + Image image = Image::wrap(device, imageHandle, VK_FORMAT_UNDEFINED); + + std::ostringstream out; + Error redirectError{&out}; + ImageViewCreateInfo{VK_IMAGE_VIEW_TYPE_2D, image}; + CORRADE_COMPARE(out.str(), + "Vk::ImageViewCreateInfo: the image has unknown format, you have to specify it explicitly\n"); +} + +void ImageViewTest::createInfoConstruct1D() { + /** @todo use a real flag once it exists */ + ImageViewCreateInfo1D info{imageHandle, VK_FORMAT_R8G8B8A8_SRGB, 3, 7, 9, ImageViewCreateInfo::Flag(VK_NOT_READY)}; + CORRADE_COMPARE(info->flags, VK_NOT_READY); + CORRADE_COMPARE(info->image, imageHandle); + CORRADE_COMPARE(info->viewType, VK_IMAGE_VIEW_TYPE_1D); + CORRADE_COMPARE(info->format, VK_FORMAT_R8G8B8A8_SRGB); + CORRADE_COMPARE(info->subresourceRange.aspectMask, VK_IMAGE_ASPECT_COLOR_BIT); + CORRADE_COMPARE(info->subresourceRange.baseArrayLayer, 3); + CORRADE_COMPARE(info->subresourceRange.layerCount, 1); + CORRADE_COMPARE(info->subresourceRange.baseMipLevel, 7); + CORRADE_COMPARE(info->subresourceRange.levelCount, 9); +} + +void ImageViewTest::createInfoConstruct1DFromImage() { + Device device{NoCreate}; + Image image = Image::wrap(device, imageHandle, VK_FORMAT_R8G8B8A8_SRGB); + + /** @todo use a real flag once it exists */ + ImageViewCreateInfo1D info{image, 3, 7, 9, ImageViewCreateInfo::Flag(VK_NOT_READY)}; + CORRADE_COMPARE(info->flags, VK_NOT_READY); + CORRADE_COMPARE(info->image, imageHandle); + CORRADE_COMPARE(info->viewType, VK_IMAGE_VIEW_TYPE_1D); + CORRADE_COMPARE(info->format, VK_FORMAT_R8G8B8A8_SRGB); + CORRADE_COMPARE(info->subresourceRange.aspectMask, VK_IMAGE_ASPECT_COLOR_BIT); + CORRADE_COMPARE(info->subresourceRange.baseArrayLayer, 3); + CORRADE_COMPARE(info->subresourceRange.layerCount, 1); + CORRADE_COMPARE(info->subresourceRange.baseMipLevel, 7); + CORRADE_COMPARE(info->subresourceRange.levelCount, 9); +} + +void ImageViewTest::createInfoConstruct2D() { + auto&& data = View2DFormatData[testCaseInstanceId()]; + setTestCaseDescription(data.name); + + /** @todo use a real flag once it exists */ + ImageViewCreateInfo2D info{imageHandle, data.format, 3, 7, 9, ImageViewCreateInfo::Flag(VK_NOT_READY)}; + CORRADE_COMPARE(info->flags, VK_NOT_READY); + CORRADE_COMPARE(info->image, imageHandle); + CORRADE_COMPARE(info->viewType, VK_IMAGE_VIEW_TYPE_2D); + CORRADE_COMPARE(info->format, data.format); + CORRADE_COMPARE(info->subresourceRange.aspectMask, data.aspect); + CORRADE_COMPARE(info->subresourceRange.baseArrayLayer, 3); + CORRADE_COMPARE(info->subresourceRange.layerCount, 1); + CORRADE_COMPARE(info->subresourceRange.baseMipLevel, 7); + CORRADE_COMPARE(info->subresourceRange.levelCount, 9); +} + +void ImageViewTest::createInfoConstruct2DFromImage() { + Device device{NoCreate}; + Image image = Image::wrap(device, imageHandle, VK_FORMAT_R8G8B8A8_SRGB); + + /** @todo use a real flag once it exists */ + ImageViewCreateInfo2D info{image, 3, 7, 9, ImageViewCreateInfo::Flag(VK_NOT_READY)}; + CORRADE_COMPARE(info->flags, VK_NOT_READY); + CORRADE_COMPARE(info->image, imageHandle); + CORRADE_COMPARE(info->viewType, VK_IMAGE_VIEW_TYPE_2D); + CORRADE_COMPARE(info->format, VK_FORMAT_R8G8B8A8_SRGB); + CORRADE_COMPARE(info->subresourceRange.aspectMask, VK_IMAGE_ASPECT_COLOR_BIT); + CORRADE_COMPARE(info->subresourceRange.baseArrayLayer, 3); + CORRADE_COMPARE(info->subresourceRange.layerCount, 1); + CORRADE_COMPARE(info->subresourceRange.baseMipLevel, 7); + CORRADE_COMPARE(info->subresourceRange.levelCount, 9); +} + +void ImageViewTest::createInfoConstruct3D() { + /** @todo use a real flag once it exists */ + ImageViewCreateInfo3D info{imageHandle, VK_FORMAT_R8G8B8A8_SRGB, 3, 7, 9, ImageViewCreateInfo::Flag(VK_NOT_READY)}; + CORRADE_COMPARE(info->flags, VK_NOT_READY); + CORRADE_COMPARE(info->image, imageHandle); + CORRADE_COMPARE(info->viewType, VK_IMAGE_VIEW_TYPE_3D); + CORRADE_COMPARE(info->format, VK_FORMAT_R8G8B8A8_SRGB); + CORRADE_COMPARE(info->subresourceRange.aspectMask, VK_IMAGE_ASPECT_COLOR_BIT); + CORRADE_COMPARE(info->subresourceRange.baseArrayLayer, 3); + CORRADE_COMPARE(info->subresourceRange.layerCount, 1); + CORRADE_COMPARE(info->subresourceRange.baseMipLevel, 7); + CORRADE_COMPARE(info->subresourceRange.levelCount, 9); +} + +void ImageViewTest::createInfoConstruct3DFromImage() { + Device device{NoCreate}; + Image image = Image::wrap(device, imageHandle, VK_FORMAT_R8G8B8A8_SRGB); + + /** @todo use a real flag once it exists */ + ImageViewCreateInfo3D info{image, 3, 7, 9, ImageViewCreateInfo::Flag(VK_NOT_READY)}; + CORRADE_COMPARE(info->flags, VK_NOT_READY); + CORRADE_COMPARE(info->image, imageHandle); + CORRADE_COMPARE(info->viewType, VK_IMAGE_VIEW_TYPE_3D); + CORRADE_COMPARE(info->format, VK_FORMAT_R8G8B8A8_SRGB); + CORRADE_COMPARE(info->subresourceRange.aspectMask, VK_IMAGE_ASPECT_COLOR_BIT); + CORRADE_COMPARE(info->subresourceRange.baseArrayLayer, 3); + CORRADE_COMPARE(info->subresourceRange.layerCount, 1); + CORRADE_COMPARE(info->subresourceRange.baseMipLevel, 7); + CORRADE_COMPARE(info->subresourceRange.levelCount, 9); +} + +void ImageViewTest::createInfoConstruct1DArray() { + /** @todo use a real flag once it exists */ + ImageViewCreateInfo1DArray info{imageHandle, VK_FORMAT_R8G8B8A8_SRGB, 3, 5, 7, 9, ImageViewCreateInfo::Flag(VK_NOT_READY)}; + CORRADE_COMPARE(info->flags, VK_NOT_READY); + CORRADE_COMPARE(info->image, imageHandle); + CORRADE_COMPARE(info->viewType, VK_IMAGE_VIEW_TYPE_1D_ARRAY); + CORRADE_COMPARE(info->format, VK_FORMAT_R8G8B8A8_SRGB); + CORRADE_COMPARE(info->subresourceRange.aspectMask, VK_IMAGE_ASPECT_COLOR_BIT); + CORRADE_COMPARE(info->subresourceRange.baseArrayLayer, 3); + CORRADE_COMPARE(info->subresourceRange.layerCount, 5); + CORRADE_COMPARE(info->subresourceRange.baseMipLevel, 7); + CORRADE_COMPARE(info->subresourceRange.levelCount, 9); +} + +void ImageViewTest::createInfoConstruct1DArrayFromImage() { + Device device{NoCreate}; + Image image = Image::wrap(device, imageHandle, VK_FORMAT_R8G8B8A8_SRGB); + + /** @todo use a real flag once it exists */ + ImageViewCreateInfo1DArray info{image, 3, 5, 7, 9, ImageViewCreateInfo::Flag(VK_NOT_READY)}; + CORRADE_COMPARE(info->flags, VK_NOT_READY); + CORRADE_COMPARE(info->image, imageHandle); + CORRADE_COMPARE(info->viewType, VK_IMAGE_VIEW_TYPE_1D_ARRAY); + CORRADE_COMPARE(info->format, VK_FORMAT_R8G8B8A8_SRGB); + CORRADE_COMPARE(info->subresourceRange.aspectMask, VK_IMAGE_ASPECT_COLOR_BIT); + CORRADE_COMPARE(info->subresourceRange.baseArrayLayer, 3); + CORRADE_COMPARE(info->subresourceRange.layerCount, 5); + CORRADE_COMPARE(info->subresourceRange.baseMipLevel, 7); + CORRADE_COMPARE(info->subresourceRange.levelCount, 9); +} + +void ImageViewTest::createInfoConstruct2DArray() { + /** @todo use a real flag once it exists */ + ImageViewCreateInfo2DArray info{imageHandle, VK_FORMAT_R8G8B8A8_SRGB, 3, 5, 7, 9, ImageViewCreateInfo::Flag(VK_NOT_READY)}; + CORRADE_COMPARE(info->flags, VK_NOT_READY); + CORRADE_COMPARE(info->image, imageHandle); + CORRADE_COMPARE(info->viewType, VK_IMAGE_VIEW_TYPE_2D_ARRAY); + CORRADE_COMPARE(info->format, VK_FORMAT_R8G8B8A8_SRGB); + CORRADE_COMPARE(info->subresourceRange.aspectMask, VK_IMAGE_ASPECT_COLOR_BIT); + CORRADE_COMPARE(info->subresourceRange.baseArrayLayer, 3); + CORRADE_COMPARE(info->subresourceRange.layerCount, 5); + CORRADE_COMPARE(info->subresourceRange.baseMipLevel, 7); + CORRADE_COMPARE(info->subresourceRange.levelCount, 9); +} + +void ImageViewTest::createInfoConstruct2DArrayFromImage() { + Device device{NoCreate}; + Image image = Image::wrap(device, imageHandle, VK_FORMAT_R8G8B8A8_SRGB); + + /** @todo use a real flag once it exists */ + ImageViewCreateInfo2DArray info{image, 3, 5, 7, 9, ImageViewCreateInfo::Flag(VK_NOT_READY)}; + CORRADE_COMPARE(info->flags, VK_NOT_READY); + CORRADE_COMPARE(info->image, imageHandle); + CORRADE_COMPARE(info->viewType, VK_IMAGE_VIEW_TYPE_2D_ARRAY); + CORRADE_COMPARE(info->format, VK_FORMAT_R8G8B8A8_SRGB); + CORRADE_COMPARE(info->subresourceRange.aspectMask, VK_IMAGE_ASPECT_COLOR_BIT); + CORRADE_COMPARE(info->subresourceRange.baseArrayLayer, 3); + CORRADE_COMPARE(info->subresourceRange.layerCount, 5); + CORRADE_COMPARE(info->subresourceRange.baseMipLevel, 7); + CORRADE_COMPARE(info->subresourceRange.levelCount, 9); +} + +void ImageViewTest::createInfoConstructCubeMap() { + /** @todo use a real flag once it exists */ + ImageViewCreateInfoCubeMap info{imageHandle, VK_FORMAT_R8G8B8A8_SRGB, 3, 7, 9, ImageViewCreateInfo::Flag(VK_NOT_READY)}; + CORRADE_COMPARE(info->flags, VK_NOT_READY); + CORRADE_COMPARE(info->image, imageHandle); + CORRADE_COMPARE(info->viewType, VK_IMAGE_VIEW_TYPE_CUBE); + CORRADE_COMPARE(info->format, VK_FORMAT_R8G8B8A8_SRGB); + CORRADE_COMPARE(info->subresourceRange.aspectMask, VK_IMAGE_ASPECT_COLOR_BIT); + CORRADE_COMPARE(info->subresourceRange.baseArrayLayer, 3); + CORRADE_COMPARE(info->subresourceRange.layerCount, 6); + CORRADE_COMPARE(info->subresourceRange.baseMipLevel, 7); + CORRADE_COMPARE(info->subresourceRange.levelCount, 9); +} + +void ImageViewTest::createInfoConstructCubeMapFromImage() { + Device device{NoCreate}; + Image image = Image::wrap(device, imageHandle, VK_FORMAT_R8G8B8A8_SRGB); + + /** @todo use a real flag once it exists */ + ImageViewCreateInfoCubeMap info{image, 3, 7, 9, ImageViewCreateInfo::Flag(VK_NOT_READY)}; + CORRADE_COMPARE(info->flags, VK_NOT_READY); + CORRADE_COMPARE(info->image, imageHandle); + CORRADE_COMPARE(info->viewType, VK_IMAGE_VIEW_TYPE_CUBE); + CORRADE_COMPARE(info->format, VK_FORMAT_R8G8B8A8_SRGB); + CORRADE_COMPARE(info->subresourceRange.aspectMask, VK_IMAGE_ASPECT_COLOR_BIT); + CORRADE_COMPARE(info->subresourceRange.baseArrayLayer, 3); + CORRADE_COMPARE(info->subresourceRange.layerCount, 6); + CORRADE_COMPARE(info->subresourceRange.baseMipLevel, 7); + CORRADE_COMPARE(info->subresourceRange.levelCount, 9); +} + +void ImageViewTest::createInfoConstructCubeMapArray() { + /** @todo use a real flag once it exists */ + ImageViewCreateInfoCubeMapArray info{imageHandle, VK_FORMAT_R8G8B8A8_SRGB, 3, 18, 7, 9, ImageViewCreateInfo::Flag(VK_NOT_READY)}; + CORRADE_COMPARE(info->flags, VK_NOT_READY); + CORRADE_COMPARE(info->image, imageHandle); + CORRADE_COMPARE(info->viewType, VK_IMAGE_VIEW_TYPE_CUBE_ARRAY); + CORRADE_COMPARE(info->format, VK_FORMAT_R8G8B8A8_SRGB); + CORRADE_COMPARE(info->subresourceRange.aspectMask, VK_IMAGE_ASPECT_COLOR_BIT); + CORRADE_COMPARE(info->subresourceRange.baseArrayLayer, 3); + CORRADE_COMPARE(info->subresourceRange.layerCount, 18); + CORRADE_COMPARE(info->subresourceRange.baseMipLevel, 7); + CORRADE_COMPARE(info->subresourceRange.levelCount, 9); +} + +void ImageViewTest::createInfoConstructCubeMapArrayFromImage() { + Device device{NoCreate}; + Image image = Image::wrap(device, imageHandle, VK_FORMAT_R8G8B8A8_SRGB); + + /** @todo use a real flag once it exists */ + ImageViewCreateInfoCubeMapArray info{image, 3, 18, 7, 9, ImageViewCreateInfo::Flag(VK_NOT_READY)}; + CORRADE_COMPARE(info->flags, VK_NOT_READY); + CORRADE_COMPARE(info->image, imageHandle); + CORRADE_COMPARE(info->viewType, VK_IMAGE_VIEW_TYPE_CUBE_ARRAY); + CORRADE_COMPARE(info->format, VK_FORMAT_R8G8B8A8_SRGB); + CORRADE_COMPARE(info->subresourceRange.aspectMask, VK_IMAGE_ASPECT_COLOR_BIT); + CORRADE_COMPARE(info->subresourceRange.baseArrayLayer, 3); + CORRADE_COMPARE(info->subresourceRange.layerCount, 18); + CORRADE_COMPARE(info->subresourceRange.baseMipLevel, 7); + CORRADE_COMPARE(info->subresourceRange.levelCount, 9); +} + +void ImageViewTest::createInfoConstructNoInit() { + ImageViewCreateInfo info{NoInit}; + info->sType = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2; + new(&info) ImageViewCreateInfo{NoInit}; + CORRADE_COMPARE(info->sType, VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2); + + CORRADE_VERIFY((std::is_nothrow_constructible::value)); + + /* Implicit construction is not allowed */ + CORRADE_VERIFY(!(std::is_convertible::value)); +} + +void ImageViewTest::createInfoConstructFromVk() { + VkImageViewCreateInfo vkInfo; + vkInfo.sType = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2; + + ImageViewCreateInfo info{vkInfo}; + CORRADE_COMPARE(info->sType, VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2); +} + +void ImageViewTest::constructNoCreate() { + { + ImageView view{NoCreate}; + CORRADE_VERIFY(!view.handle()); + } + + /* Implicit construction is not allowed */ + CORRADE_VERIFY(!(std::is_convertible::value)); +} + +void ImageViewTest::constructCopy() { + CORRADE_VERIFY(!std::is_copy_constructible{}); + CORRADE_VERIFY(!std::is_copy_assignable{}); +} + +}}}} + +CORRADE_TEST_MAIN(Magnum::Vk::Test::ImageViewTest) diff --git a/src/Magnum/Vk/Test/ImageViewVkTest.cpp b/src/Magnum/Vk/Test/ImageViewVkTest.cpp new file mode 100644 index 000000000..538995d41 --- /dev/null +++ b/src/Magnum/Vk/Test/ImageViewVkTest.cpp @@ -0,0 +1,213 @@ +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, + 2020 Vladimír Vondruš + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +#include "Magnum/Vk/DeviceCreateInfo.h" +#include "Magnum/Vk/DeviceFeatures.h" +#include "Magnum/Vk/DeviceProperties.h" +#include "Magnum/Vk/Handle.h" +#include "Magnum/Vk/ImageCreateInfo.h" +#include "Magnum/Vk/ImageViewCreateInfo.h" +#include "Magnum/Vk/Result.h" +#include "Magnum/Vk/VulkanTester.h" + +namespace Magnum { namespace Vk { namespace Test { namespace { + +struct ImageViewVkTest: VulkanTester { + explicit ImageViewVkTest(); + + void construct1D(); + void construct2D(); + void construct3D(); + void construct1DArray(); + void construct2DArray(); + void constructCubeMap(); + void constructCubeMapArray(); + void constructMove(); + + void wrap(); +}; + +ImageViewVkTest::ImageViewVkTest() { + addTests({&ImageViewVkTest::construct1D, + &ImageViewVkTest::construct2D, + &ImageViewVkTest::construct3D, + &ImageViewVkTest::construct1DArray, + &ImageViewVkTest::construct2DArray, + &ImageViewVkTest::constructCubeMap, + &ImageViewVkTest::constructCubeMapArray, + &ImageViewVkTest::constructMove, + + &ImageViewVkTest::wrap}); +} + +void ImageViewVkTest::construct1D() { + Image image{device(), ImageCreateInfo1D{ImageUsage::Sampled, + VK_FORMAT_R8G8B8A8_UNORM, 256, 1}, MemoryFlag::DeviceLocal}; + + { + ImageView view{device(), ImageViewCreateInfo1D{image}}; + CORRADE_VERIFY(image.handle()); + CORRADE_COMPARE(image.handleFlags(), HandleFlag::DestroyOnDestruction); + } + + /* Shouldn't crash or anything */ + CORRADE_VERIFY(true); +} + +void ImageViewVkTest::construct2D() { + Image image{device(), ImageCreateInfo2D{ImageUsage::Sampled, + VK_FORMAT_R8G8B8A8_UNORM, {256, 256}, 1}, MemoryFlag::DeviceLocal}; + + { + ImageView view{device(), ImageViewCreateInfo2D{image}}; + CORRADE_VERIFY(image.handle()); + CORRADE_COMPARE(image.handleFlags(), HandleFlag::DestroyOnDestruction); + } + + /* Shouldn't crash or anything */ + CORRADE_VERIFY(true); +} + +void ImageViewVkTest::construct3D() { + Image image{device(), ImageCreateInfo3D{ImageUsage::Sampled, + VK_FORMAT_R8G8B8A8_UNORM, {256, 256, 10}, 1}, MemoryFlag::DeviceLocal}; + + { + ImageView view{device(), ImageViewCreateInfo3D{image}}; + CORRADE_VERIFY(image.handle()); + CORRADE_COMPARE(image.handleFlags(), HandleFlag::DestroyOnDestruction); + } + + /* Shouldn't crash or anything */ + CORRADE_VERIFY(true); +} + +void ImageViewVkTest::construct1DArray() { + Image image{device(), ImageCreateInfo1DArray{ImageUsage::Sampled, + VK_FORMAT_R8G8B8A8_UNORM, {256, 10}, 1}, MemoryFlag::DeviceLocal}; + + { + ImageView view{device(), ImageViewCreateInfo1DArray{image}}; + CORRADE_VERIFY(image.handle()); + CORRADE_COMPARE(image.handleFlags(), HandleFlag::DestroyOnDestruction); + } + + /* Shouldn't crash or anything */ + CORRADE_VERIFY(true); +} + +void ImageViewVkTest::construct2DArray() { + Image image{device(), ImageCreateInfo2DArray{ImageUsage::Sampled, + VK_FORMAT_R8G8B8A8_UNORM, {256, 256, 10}, 1}, MemoryFlag::DeviceLocal}; + + { + ImageView view{device(), ImageViewCreateInfo2DArray{image}}; + CORRADE_VERIFY(image.handle()); + CORRADE_COMPARE(image.handleFlags(), HandleFlag::DestroyOnDestruction); + } + + /* Shouldn't crash or anything */ + CORRADE_VERIFY(true); +} + +void ImageViewVkTest::constructCubeMap() { + Image image{device(), ImageCreateInfoCubeMap{ImageUsage::Sampled, + VK_FORMAT_R8G8B8A8_UNORM, {256, 256}, 1}, MemoryFlag::DeviceLocal}; + + { + ImageView view{device(), ImageViewCreateInfoCubeMap{image}}; + CORRADE_VERIFY(image.handle()); + CORRADE_COMPARE(image.handleFlags(), HandleFlag::DestroyOnDestruction); + } + + /* Shouldn't crash or anything */ + CORRADE_VERIFY(true); +} + +void ImageViewVkTest::constructCubeMapArray() { + if(!(device().properties().features() & DeviceFeature::ImageCubeArray)) + CORRADE_SKIP("ImageCubeArray feature not supported, can't test."); + + /* Create the image on a new device with the feature enabled */ + Queue queue2{NoCreate}; + Device device2{instance(), DeviceCreateInfo{device().properties()} + .addQueues(0, {0.0f}, {queue2}) + .setEnabledFeatures(DeviceFeature::ImageCubeArray)}; + Image image{device2, ImageCreateInfoCubeMapArray{ImageUsage::Sampled, + VK_FORMAT_R8G8B8A8_UNORM, {256, 256, 18}, 1}, MemoryFlag::DeviceLocal}; + + { + ImageView view{device2, ImageViewCreateInfoCubeMapArray{image}}; + CORRADE_VERIFY(image.handle()); + CORRADE_COMPARE(image.handleFlags(), HandleFlag::DestroyOnDestruction); + } + + /* Shouldn't crash or anything */ + CORRADE_VERIFY(true); +} + +void ImageViewVkTest::constructMove() { + Image image{device(), ImageCreateInfo2D{ImageUsage::Sampled, + VK_FORMAT_R8G8B8A8_UNORM, {256, 256}, 1}, MemoryFlag::DeviceLocal}; + ImageView a{device(), ImageViewCreateInfo2D{image}}; + VkImageView handle = a.handle(); + + ImageView b = std::move(a); + CORRADE_VERIFY(!a.handle()); + CORRADE_COMPARE(b.handle(), handle); + CORRADE_COMPARE(b.handleFlags(), HandleFlag::DestroyOnDestruction); + + ImageView c{NoCreate}; + c = std::move(b); + CORRADE_VERIFY(!b.handle()); + CORRADE_COMPARE(b.handleFlags(), HandleFlags{}); + CORRADE_COMPARE(c.handle(), handle); + CORRADE_COMPARE(c.handleFlags(), HandleFlag::DestroyOnDestruction); + + CORRADE_VERIFY(std::is_nothrow_move_constructible::value); + CORRADE_VERIFY(std::is_nothrow_move_assignable::value); +} + +void ImageViewVkTest::wrap() { + Image image{device(), ImageCreateInfo2D{ImageUsage::Sampled, + VK_FORMAT_R8G8B8A8_UNORM, {256, 256}, 1}, MemoryFlag::DeviceLocal}; + + VkImageView view{}; + CORRADE_COMPARE(Result(device()->CreateImageView(device(), + ImageViewCreateInfo2D{image}, nullptr, &view)), Result::Success); + CORRADE_VERIFY(view); + + auto wrapped = ImageView::wrap(device(), view, HandleFlag::DestroyOnDestruction); + CORRADE_COMPARE(wrapped.handle(), view); + + /* Release the handle again, destroy by hand */ + CORRADE_COMPARE(wrapped.release(), view); + CORRADE_VERIFY(!wrapped.handle()); + device()->DestroyImageView(device(), view, nullptr); +} + +}}}} + +CORRADE_TEST_MAIN(Magnum::Vk::Test::ImageViewVkTest) diff --git a/src/Magnum/Vk/Test/ImageVkTest.cpp b/src/Magnum/Vk/Test/ImageVkTest.cpp index e68f94285..958d5578a 100644 --- a/src/Magnum/Vk/Test/ImageVkTest.cpp +++ b/src/Magnum/Vk/Test/ImageVkTest.cpp @@ -199,7 +199,7 @@ void ImageVkTest::wrap() { nullptr, &image)), Result::Success); CORRADE_VERIFY(image); - auto wrapped = Image::wrap(device(), image, HandleFlag::DestroyOnDestruction); + auto wrapped = Image::wrap(device(), image, VK_FORMAT_R8G8B8A8_UNORM, HandleFlag::DestroyOnDestruction); CORRADE_COMPARE(wrapped.handle(), image); /* Release the handle again, destroy by hand */ diff --git a/src/Magnum/Vk/Vk.h b/src/Magnum/Vk/Vk.h index 0fb38f833..c4ad1548d 100644 --- a/src/Magnum/Vk/Vk.h +++ b/src/Magnum/Vk/Vk.h @@ -55,6 +55,9 @@ class Image; enum class ImageLayout: Int; class ImageCreateInfo; /* Not forward-declaring ImageCreateInfo1D etc right now, I see no need */ +class ImageView; +class ImageViewCreateInfo; +/* Not forward-declaring ImageViewCreateInfo1D etc right now, I see no need */ class Instance; class InstanceCreateInfo; class InstanceExtension;