mirror of https://github.com/mosra/magnum.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
370 lines
14 KiB
370 lines
14 KiB
#ifndef Magnum_Vk_Image_h |
|
#define Magnum_Vk_Image_h |
|
/* |
|
This file is part of Magnum. |
|
|
|
Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, |
|
2020 Vladimír Vondruš <mosra@centrum.cz> |
|
|
|
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::Image, enum @ref Magnum::Vk::ImageLayout |
|
* @m_since_latest |
|
*/ |
|
|
|
#include "Magnum/Magnum.h" |
|
#include "Magnum/Vk/Memory.h" |
|
#include "Magnum/Vk/Vk.h" |
|
#include "Magnum/Vk/Vulkan.h" |
|
#include "Magnum/Vk/visibility.h" |
|
|
|
namespace Magnum { namespace Vk { |
|
|
|
namespace Implementation { struct DeviceState; } |
|
|
|
/** |
|
@brief Image layout |
|
@m_since_latest |
|
|
|
@see @ref ImageCreateInfo |
|
@m_enum_values_as_keywords |
|
*/ |
|
enum class ImageLayout: Int { |
|
/** |
|
* Undefined. Can only be used as the initial layout in |
|
* @ref ImageCreateInfo structures (and there it's the default). Images in |
|
* this layout are not accessible by the device, the image has to be |
|
* transitioned to a defined layout such as @ref ImageLayout::General |
|
* first; contents of the memory are not guaranteed to be preserved during |
|
* the transition. |
|
* @see @ref ImageLayout::Preinitialized |
|
*/ |
|
Undefined = VK_IMAGE_LAYOUT_UNDEFINED, |
|
|
|
/** |
|
* Preinitialized. Can only be used as the initial layout in |
|
* @ref ImageCreateInfo structures. Compared to |
|
* @ref ImageLayout::Undefined, contents of the memory are guaranteed to be |
|
* preserved during a transition to a defined layout and thus this layout |
|
* is intended for populating image contents by the host. |
|
* |
|
* Usable only for images created with |
|
* @val_vk{IMAGE_TILING_LINEAR,ImageTiling}, usually with just one sample |
|
* and possibly other restrictions. |
|
* |
|
* @m_class{m-note m-success} |
|
* |
|
* @par |
|
* In order to be populated from the host, such images need to be |
|
* allocated from @ref MemoryFlag::HostVisible memory, which on |
|
* discrete GPUs is not fast for device access and there's thus |
|
* recommended to go through a staging buffer instead. For integrated |
|
* GPUs however, going directly through a linear preinitialized image |
|
* *might* be better to avoid a memory usage spike and a potentially |
|
* expensive copy. |
|
*/ |
|
Preinitialized = VK_IMAGE_LAYOUT_PREINITIALIZED, |
|
|
|
/** |
|
* General layout, supports all types of device access. This is the |
|
* conservative default used everywhere except the @ref ImageCreateInfo |
|
* structures, which uses @ref ImageLayout::Undefined. |
|
* |
|
* @m_class{m-note m-success} |
|
* |
|
* @par |
|
* While this layout will always work, it's recommended to pick a |
|
* stricter layout where appropriate, as it may result in better |
|
* performance. |
|
*/ |
|
General = VK_IMAGE_LAYOUT_GENERAL, |
|
|
|
/* The _OPTIMAL suffixes are dropped because it doesn't seem that there |
|
would be any _UNOPTIMAL or whatever variants anytime soon, so this is |
|
redundant. If that time comes, we can always deprecate and rename. */ |
|
|
|
/** |
|
* Layout optimal for a color or resolve attachment, not guaranteed to be |
|
* usable for anything else. |
|
* |
|
* Only valid for images created with @ref ImageUsage::ColorAttachment. |
|
*/ |
|
ColorAttachment = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, |
|
|
|
/** |
|
* Layout optimal for a read/write depth/stencil attachment, not guaranteed |
|
* to be usable for anything else. |
|
* |
|
* Only valid for images created with |
|
* @ref ImageUsage::DepthStencilAttachment. |
|
*/ |
|
DepthStencilAttachment = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, |
|
|
|
/** |
|
* Layout optimal for read-only access in a shader sampler, combined |
|
* image/sampler or input attachment; not guaranteed to be usable for |
|
* anything else. |
|
* |
|
* Only valid for images created with @ref ImageUsage::Sampled or |
|
* @ref ImageUsage::InputAttachment. |
|
*/ |
|
ShaderReadOnly = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, |
|
|
|
/** |
|
* Layout optimal for transfer sources; not guaranteed to be usable for |
|
* anything else. |
|
* |
|
* Only valid for images created with @ref ImageUsage::TransferSource. |
|
*/ |
|
TransferSource = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, |
|
|
|
/** |
|
* Layout optimal for transfer destination; not guaranteed to be usable for |
|
* anything else. |
|
* |
|
* Only valid for images created with @ref ImageUsage::TransferDestination. |
|
*/ |
|
TransferDestination = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, |
|
|
|
/** @todo remaining ones from @vk_extension{KHR,maintenance2} (1.1), |
|
@vk_extension{KHR,separate_depth_stencil_layouts} (1.2) */ |
|
}; |
|
|
|
/** |
|
@brief Image |
|
@m_since_latest |
|
|
|
Wraps a @type_vk_keyword{Image} and its memory. |
|
|
|
@section Vk-Image-creation Image creation |
|
|
|
Pass one of the @ref ImageCreateInfo subclasses depending on desired image type |
|
with desired usage, format, size and other propoerties to the @ref Image |
|
constructor together with specifying @ref MemoryFlags for memory allocation. |
|
|
|
@snippet MagnumVk.cpp Image-creation |
|
|
|
@attention At this point, a dedicated allocation is used, subsequently |
|
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 |
|
be created without any memory attached. Image memory requirements can be |
|
subsequently queried using @ref memoryRequirements() and an allocated memory |
|
bound with @ref bindMemory(). See @ref Memory for further details about memory allocation. |
|
|
|
@snippet MagnumVk.cpp Image-creation-custom-allocation |
|
|
|
Using @ref bindDedicatedMemory() instead of @ref bindMemory() will transfer |
|
ownership of the @ref Memory to the image instance, making it subsequently |
|
available through @ref dedicatedMemory(). This matches current behavior of the |
|
@ref Image(Device&, const ImageCreateInfo&, MemoryFlags) constructor shown |
|
above, except that you have more control over choosing and allocating the |
|
memory. |
|
|
|
@see @ref Buffer |
|
*/ |
|
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 format Image format. Available through |
|
* @ref format() afterwards. |
|
* @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. |
|
* |
|
* 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, VkFormat format, HandleFlags flags = {}); |
|
|
|
/** |
|
* @brief Construct an image without allocating |
|
* @param device Vulkan device to create the image on |
|
* @param info Image creation info |
|
* |
|
* Use @ref memoryRequirements(), @ref Memory and @ref bindMemory() to |
|
* bind a memory (sub)allocation to the image. |
|
* @see @ref Image(Device&, const ImageCreateInfo&, MemoryFlags), |
|
* @fn_vk_keyword{CreateImage} |
|
*/ |
|
explicit Image(Device& device, const ImageCreateInfo& info, NoAllocateT); |
|
|
|
/** |
|
* @brief Construct an image |
|
* @param device Vulkan device to create the image on |
|
* @param info Image creation info |
|
* @param memoryFlags Memory allocation flags |
|
* |
|
* Compared to @ref Image(Device&, const ImageCreateInfo&, NoAllocateT) |
|
* allocates a memory satisfying @p memoryFlags as well. |
|
* |
|
* @attention At this point, a dedicated allocation is used, |
|
* subsequently accessible through @ref dedicatedMemory(). This |
|
* behavior may change in the future. |
|
*/ |
|
explicit Image(Device& device, const ImageCreateInfo& info, MemoryFlags memoryFlags); |
|
|
|
/** |
|
* @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 Image(NoCreateT); |
|
|
|
/** @brief Copying is not allowed */ |
|
Image(const Image&) = delete; |
|
|
|
/** @brief Move constructor */ |
|
Image(Image&& other) noexcept; |
|
|
|
/** |
|
* @brief Destructor |
|
* |
|
* Destroys associated @type_vk{Image} handle, unless the instance |
|
* was created using @ref wrap() without @ref HandleFlag::DestroyOnDestruction |
|
* specified. |
|
* @see @fn_vk_keyword{DestroyImage}, @ref release() |
|
*/ |
|
~Image(); |
|
|
|
/** @brief Copying is not allowed */ |
|
Image& operator=(const Image&) = delete; |
|
|
|
/** @brief Move assignment */ |
|
Image& operator=(Image&& other) noexcept; |
|
|
|
/** @brief Underlying @type_vk{Image} handle */ |
|
VkImage handle() { return _handle; } |
|
/** @overload */ |
|
operator VkImage() { return _handle; } |
|
|
|
/** @brief Handle flags */ |
|
HandleFlags handleFlags() const { return _flags; } |
|
|
|
/** @brief Image format */ |
|
VkFormat format() const { return _format; } |
|
|
|
/** |
|
* @brief Image memory requirements |
|
* |
|
* @see @ref bindMemory(), @fn_vk_keyword{GetImageMemoryRequirements2}, |
|
* @fn_vk_keyword{GetImageMemoryRequirements} |
|
*/ |
|
MemoryRequirements memoryRequirements() const; |
|
|
|
/** |
|
* @brief Bind image memory |
|
* |
|
* Assumes that @p memory type, the amount of @p memory at @p offset |
|
* and @p offset alignment corresponds to image memory requirements. |
|
* @see @ref memoryRequirements(), @ref bindDedicatedMemory(), |
|
* @fn_vk_keyword{BindImageMemory2}, |
|
* @fn_vk_keyword{BindImageMemory} |
|
*/ |
|
void bindMemory(Memory& memory, UnsignedLong offset); |
|
|
|
/** |
|
* @brief Bind a dedicated image memory |
|
* |
|
* Equivalent to @ref bindMemory() with @p offset set to @cpp 0 @ce, |
|
* with the additional effect that @p memory ownership transfers to the |
|
* image and is then available through @ref dedicatedMemory(). |
|
*/ |
|
void bindDedicatedMemory(Memory&& memory); |
|
|
|
/** |
|
* @brief Whether the image has a dedicated memory |
|
* |
|
* Returns @cpp true @ce if the image memory was bound using |
|
* @ref bindDedicatedMemory(), @cpp false @ce otherwise. |
|
* @see @ref dedicatedMemory() |
|
*/ |
|
bool hasDedicatedMemory() const; |
|
|
|
/** |
|
* @brief Dedicated image memory |
|
* |
|
* Expects that the image has a dedicated memory. |
|
* @see @ref hasDedicatedMemory() |
|
*/ |
|
Memory& dedicatedMemory(); |
|
|
|
/** |
|
* @brief Release the underlying Vulkan image |
|
* |
|
* Releases ownership of the Vulkan image and returns its handle so |
|
* @fn_vk{DestroyImage} is not called on destruction. The internal |
|
* state is then equivalent to moved-from state. |
|
* @see @ref wrap() |
|
*/ |
|
VkImage release(); |
|
|
|
private: |
|
friend Implementation::DeviceState; |
|
|
|
MAGNUM_VK_LOCAL static void getMemoryRequirementsImplementationDefault(Device& device, const VkImageMemoryRequirementsInfo2& info, VkMemoryRequirements2& requirements); |
|
MAGNUM_VK_LOCAL static void getMemoryRequirementsImplementationKHR(Device& device, const VkImageMemoryRequirementsInfo2& info, VkMemoryRequirements2& requirements); |
|
MAGNUM_VK_LOCAL static void getMemoryRequirementsImplementation11(Device& device, const VkImageMemoryRequirementsInfo2& info, VkMemoryRequirements2& requirements); |
|
|
|
MAGNUM_VK_LOCAL static VkResult bindMemoryImplementationDefault(Device& device, UnsignedInt count, const VkBindImageMemoryInfo* infos); |
|
MAGNUM_VK_LOCAL static VkResult bindMemoryImplementationKHR(Device& device, UnsignedInt count, const VkBindImageMemoryInfo* infos); |
|
MAGNUM_VK_LOCAL static VkResult bindMemoryImplementation11(Device& device, UnsignedInt count, const VkBindImageMemoryInfo* infos); |
|
|
|
/* Can't be a reference because of the NoCreate constructor */ |
|
Device* _device; |
|
|
|
VkImage _handle; |
|
HandleFlags _flags; |
|
|
|
/* On 64-bit there would be a 7 byte padding after _flags anyway, 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; |
|
}; |
|
|
|
}} |
|
|
|
#endif
|
|
|