ImageVk.h#

The PVRVk Image class and related classes (SwapchainImage, ImageView).

Includes#

  • PVRVk/DeviceMemoryVk.h

  • PVRVk/DeviceVk.h

Included By#

Namespaces#

Classes#

Source Code#

#pragma once
#include "PVRVk/DeviceVk.h"
#include "PVRVk/DeviceMemoryVk.h"

namespace pvrvk {
namespace {
inline ImageViewType convertToPVRVkImageViewType(ImageType baseType, uint32_t numArrayLayers, bool isCubeMap)
{
    // if it is a cube map it has to be 2D Texture base
    if (isCubeMap && baseType != ImageType::e_2D)
    {
        assert(baseType == ImageType::e_2D && "Cubemap texture must be 2D");
        return ImageViewType::e_MAX_ENUM;
    }
    // array must be atleast 1
    if (!numArrayLayers)
    {
        assert(false && "Number of array layers must be greater than equal to 0");
        return ImageViewType::e_MAX_ENUM;
    }
    // if it is array it must be 1D or 2D texture base
    if ((numArrayLayers > 1) && (baseType > ImageType::e_2D))
    {
        assert(false && "1D and 2D image type supports array texture");
        return ImageViewType::e_MAX_ENUM;
    }

    ImageViewType vkType[] = { ImageViewType::e_1D, ImageViewType::e_1D_ARRAY, ImageViewType::e_2D, ImageViewType::e_2D_ARRAY, ImageViewType::e_3D, ImageViewType::e_CUBE,
        ImageViewType::e_CUBE_ARRAY };
    if (isCubeMap) { numArrayLayers = (numArrayLayers > 6u) * 6u; }
    return vkType[(static_cast<uint32_t>(baseType) * 2) + (isCubeMap ? 3 : 0) + (numArrayLayers > 1 ? 1 : 0)];
}

inline ImageAspectFlags formatToImageAspect(Format format)
{
    if (format == Format::e_UNDEFINED) { throw ErrorUnknown("Cannot retrieve VkImageAspectFlags from an undefined VkFormat"); }
    if (format < Format::e_D16_UNORM || format > Format::e_D32_SFLOAT_S8_UINT) { return ImageAspectFlags::e_COLOR_BIT; }
    const ImageAspectFlags formats[] = {
        ImageAspectFlags::e_DEPTH_BIT, // VkFormat::e_D16_UNORM
        ImageAspectFlags::e_DEPTH_BIT, // VkFormat::e_X8_D24_UNORM_PACK32
        ImageAspectFlags::e_DEPTH_BIT, // VkFormat::e_D32_SFLOAT
        ImageAspectFlags::e_STENCIL_BIT, // VkFormat::e_S8_UINT
        ImageAspectFlags::e_DEPTH_BIT | ImageAspectFlags::e_STENCIL_BIT, // VkFormat::e_D16_UNORM_S8_UINT
        ImageAspectFlags::e_DEPTH_BIT | ImageAspectFlags::e_STENCIL_BIT, // VkFormat::e_D24_UNORM_S8_UINT
        ImageAspectFlags::e_DEPTH_BIT | ImageAspectFlags::e_STENCIL_BIT, // VkFormat::e_D32_SFLOAT_S8_UINT
    };
    return formats[static_cast<uint32_t>(format) - static_cast<uint32_t>(Format::e_D16_UNORM)];
}
} // namespace

struct ImageCreateInfo
{
public:
    ImageCreateInfo()
        : _flags(ImageCreateFlags::e_NONE), _imageType(ImageType::e_2D), _extent(Extent3D()), _numMipLevels(1), _numArrayLayers(1), _numSamples(SampleCountFlags::e_1_BIT),
          _format(Format::e_UNDEFINED), _sharingMode(SharingMode::e_EXCLUSIVE), _usageFlags(ImageUsageFlags::e_NONE), _initialLayout(ImageLayout::e_UNDEFINED),
          _tiling(ImageTiling::e_OPTIMAL), _numQueueFamilyIndices(0), _queueFamilyIndices(nullptr)
    {}

    ImageCreateInfo(ImageType imageType, pvrvk::Format format, const pvrvk::Extent3D& extent, pvrvk::ImageUsageFlags usage, uint32_t numMipLevels = 1, uint32_t numArrayLayers = 1,
        pvrvk::SampleCountFlags samples = pvrvk::SampleCountFlags::e_1_BIT, pvrvk::ImageCreateFlags flags = pvrvk::ImageCreateFlags::e_NONE,
        ImageTiling tiling = ImageTiling::e_OPTIMAL, SharingMode sharingMode = SharingMode::e_EXCLUSIVE, ImageLayout initialLayout = ImageLayout::e_UNDEFINED,
        const uint32_t* queueFamilyIndices = nullptr, uint32_t numQueueFamilyIndices = 0)
        : _flags(flags), _imageType(imageType), _extent(extent), _numMipLevels(numMipLevels), _numArrayLayers(numArrayLayers), _numSamples(samples), _format(format),
          _sharingMode(sharingMode), _usageFlags(usage), _initialLayout(initialLayout), _tiling(tiling), _numQueueFamilyIndices(numQueueFamilyIndices),
          _queueFamilyIndices(queueFamilyIndices)
    {}

    inline ImageCreateFlags getFlags() const { return _flags; }
    inline void setFlags(ImageCreateFlags flags) { this->_flags = flags; }
    inline ImageType getImageType() const { return _imageType; }
    inline void setImageType(ImageType imageType) { this->_imageType = imageType; }
    inline const Extent3D& getExtent() const { return _extent; }
    inline void setExtent(Extent3D extent) { this->_extent = extent; }
    inline uint32_t getNumMipLevels() const { return _numMipLevels; }
    inline void setNumMipLevels(uint32_t numMipLevels) { this->_numMipLevels = numMipLevels; }
    inline uint32_t getNumArrayLayers() const { return _numArrayLayers; }
    inline void setNumArrayLayers(uint32_t numArrayLayers) { this->_numArrayLayers = numArrayLayers; }
    inline SampleCountFlags getNumSamples() const { return _numSamples; }
    inline void setNumSamples(SampleCountFlags numSamples) { this->_numSamples = numSamples; }
    inline Format getFormat() const { return _format; }
    inline void setFormat(Format format) { this->_format = format; }
    inline SharingMode getSharingMode() const { return _sharingMode; }
    inline void setSharingMode(SharingMode sharingMode) { this->_sharingMode = sharingMode; }
    inline ImageUsageFlags getUsageFlags() const { return _usageFlags; }
    inline void setUsageFlags(ImageUsageFlags usageFlags) { this->_usageFlags = usageFlags; }
    inline ImageLayout getInitialLayout() const { return _initialLayout; }
    inline void setInitialLayout(ImageLayout initialLayout) { this->_initialLayout = initialLayout; }
    inline ImageTiling getTiling() const { return _tiling; }
    inline void setTiling(ImageTiling tiling) { this->_tiling = tiling; }
    inline uint32_t getNumQueueFamilyIndices() const { return _numQueueFamilyIndices; }
    inline void setNumQueueFamilyIndices(uint32_t numQueueFamilyIndices) { this->_numQueueFamilyIndices = numQueueFamilyIndices; }
    inline const uint32_t* getQueueFamilyIndices() const { return _queueFamilyIndices; }
    inline void setQueueFamilyIndices(const uint32_t* queueFamilyIndices) { _queueFamilyIndices = queueFamilyIndices; }

private:
    ImageCreateFlags _flags;
    ImageType _imageType;
    Extent3D _extent;
    uint32_t _numMipLevels;
    uint32_t _numArrayLayers;
    SampleCountFlags _numSamples;
    Format _format;
    SharingMode _sharingMode;
    ImageUsageFlags _usageFlags;
    ImageLayout _initialLayout;
    ImageTiling _tiling;
    uint32_t _numQueueFamilyIndices;
    const uint32_t* _queueFamilyIndices;
};

namespace impl {
class Image_ : public PVRVkDeviceObjectBase<VkImage, ObjectType::e_IMAGE>, public DeviceObjectDebugUtils<Image_>
{
protected:
    friend class Device_;

    class make_shared_enabler
    {
    protected:
        make_shared_enabler() {}
        friend class Image_;
    };

    static Image constructShared(const DeviceWeakPtr& device, const ImageCreateInfo& createInfo) { return std::make_shared<Image_>(make_shared_enabler{}, device, createInfo); }

    static Image constructShared(const DeviceWeakPtr& device) { return std::make_shared<Image_>(make_shared_enabler{}, device); }

    pvrvk::MemoryRequirements _memReqs;
    DeviceMemory _memory;
    pvrvk::ImageCreateInfo _createInfo;

#ifdef DEBUG
    pvrvk::ImageLayout _currentLayout;
#endif

public:
    DECLARE_NO_COPY_SEMANTICS(Image_)
    virtual ~Image_();

    Image_(make_shared_enabler, const DeviceWeakPtr& device, const ImageCreateInfo& createInfo);

    Image_(make_shared_enabler, const DeviceWeakPtr& device) : PVRVkDeviceObjectBase(device), DeviceObjectDebugUtils() {}

    pvrvk::SubresourceLayout getSubresourceLayout(const pvrvk::ImageSubresource& subresource) const;

    pvrvk::ImageCreateInfo getCreateInfo() const { return _createInfo; }

    inline ImageCreateFlags getFlags() const { return _createInfo.getFlags(); }

    inline ImageType getImageType() const { return _createInfo.getImageType(); }

    inline Extent3D getExtent() const { return _createInfo.getExtent(); }

    inline uint32_t getNumMipLevels() const { return _createInfo.getNumMipLevels(); }

    inline uint32_t getNumArrayLayers() const { return _createInfo.getNumArrayLayers(); }

    inline SampleCountFlags getNumSamples() const { return _createInfo.getNumSamples(); }

    inline Format getFormat() const { return _createInfo.getFormat(); }

    inline SharingMode getSharingMode() const { return _createInfo.getSharingMode(); }

    inline ImageUsageFlags getUsageFlags() const { return _createInfo.getUsageFlags(); }

    inline ImageLayout getInitialLayout() const { return _createInfo.getInitialLayout(); }

    inline ImageTiling getTiling() const { return _createInfo.getTiling(); }

    inline uint32_t getNumQueueFamilyIndices() const { return _createInfo.getNumQueueFamilyIndices(); }

    inline const uint32_t* const getQueueFamilyIndices() const { return _createInfo.getQueueFamilyIndices(); }

    bool isCubeMap() const { return (_createInfo.getFlags() & pvrvk::ImageCreateFlags::e_CUBE_COMPATIBLE_BIT) == pvrvk::ImageCreateFlags::e_CUBE_COMPATIBLE_BIT; }

    bool isAllocated() const { return (getVkHandle() != VK_NULL_HANDLE); }

    uint16_t getWidth() const { return static_cast<uint16_t>(_createInfo.getExtent().getWidth()); }

    uint16_t getHeight() const { return static_cast<uint16_t>(_createInfo.getExtent().getHeight()); }

    uint16_t getDepth() const { return static_cast<uint16_t>(_createInfo.getExtent().getDepth()); }

    const DeviceMemory& getDeviceMemory() const { return _memory; }
    DeviceMemory& getDeviceMemory() { return _memory; }
    void bindMemoryNonSparse(DeviceMemory memory, VkDeviceSize offset = 0)
    {
        if ((_createInfo.getFlags() &
                (pvrvk::ImageCreateFlags::e_SPARSE_ALIASED_BIT | pvrvk::ImageCreateFlags::e_SPARSE_BINDING_BIT | pvrvk::ImageCreateFlags::e_SPARSE_RESIDENCY_BIT)) != 0)
        {
            throw ErrorValidationFailedEXT("Cannot bind memory: Image is Sparce so cannot have bound memory.");
        }
        if (_memory) { throw ErrorValidationFailedEXT("Cannot bind memory: A memory block is already bound"); }
        vkThrowIfFailed(getDevice()->getVkBindings().vkBindImageMemory(getDevice()->getVkHandle(), getVkHandle(), memory->getVkHandle(), offset),
            "Failed to bind a memory block to this image");
        _memory = memory;
    }

    const pvrvk::MemoryRequirements& getMemoryRequirement() const { return _memReqs; }

#ifdef DEBUG
    pvrvk::ImageLayout getImageLayout() { return _currentLayout; }

    void setImageLayout(pvrvk::ImageLayout imageLayout) { _currentLayout = imageLayout; }
#endif
};

class SwapchainImage_ : public Image_
{
private:
    friend class ::pvrvk::impl::Swapchain_;

    class make_shared_enabler : public Image_::make_shared_enabler
    {
    private:
        make_shared_enabler() : Image_::make_shared_enabler() {}
        friend class SwapchainImage_;
    };

    static SwapchainImage constructShared(const DeviceWeakPtr& device, const VkImage& swapchainImage, const Format& format, const Extent3D& extent, uint32_t numArrayLevels,
        uint32_t numMipLevels, const ImageUsageFlags& usage)
    {
        return std::make_shared<SwapchainImage_>(make_shared_enabler{}, device, swapchainImage, format, extent, numArrayLevels, numMipLevels, usage);
    }

public:
    DECLARE_NO_COPY_SEMANTICS(SwapchainImage_)
    ~SwapchainImage_();

    SwapchainImage_(make_shared_enabler, const DeviceWeakPtr& device, const VkImage& swapchainImage, const Format& format, const Extent3D& extent, uint32_t numArrayLevels,
        uint32_t numMipLevels, const ImageUsageFlags& usage);
};
} // namespace impl

struct ImageViewCreateInfo
{
public:
    ImageViewCreateInfo()
        : _viewType(ImageViewType::e_2D), _format(Format::e_UNDEFINED), _components(ComponentMapping()), _subresourceRange(ImageSubresourceRange()),
          _flags(ImageViewCreateFlags::e_NONE), _pNext(nullptr)
    {}

    ImageViewCreateInfo(const Image& image, const ComponentMapping& components = ComponentMapping(), const void* pNext = nullptr)
        : _image(image), _components(components), _flags(ImageViewCreateFlags::e_NONE), _pNext(pNext)
    {
        _viewType = convertToPVRVkImageViewType(_image->getImageType(), _image->getNumArrayLayers(), _image->isCubeMap());
        _format = _image->getFormat();
        _subresourceRange = ImageSubresourceRange(pvrvk::formatToImageAspect(_image->getFormat()), 0, _image->getNumMipLevels(), 0, _image->getNumArrayLayers());
    }

    ImageViewCreateInfo(const Image& image, pvrvk::ImageViewType viewType, pvrvk::Format format, const ImageSubresourceRange& subresourceRange,
        const ComponentMapping& components = ComponentMapping(), ImageViewCreateFlags flags = ImageViewCreateFlags::e_NONE, const void* pNext = nullptr)
        : _image(image), _viewType(viewType), _format(format), _components(components), _subresourceRange(subresourceRange), _flags(flags), _pNext(pNext)
    {}

    inline ImageViewCreateFlags getFlags() const { return _flags; }
    inline void setFlags(ImageViewCreateFlags flags) { this->_flags = flags; }
    inline Image& getImage() { return _image; }
    inline const Image& getImage() const { return _image; }
    inline void setImage(const Image& image) { this->_image = image; }
    inline ImageViewType getViewType() const { return _viewType; }
    inline void setViewType(ImageViewType viewType) { this->_viewType = viewType; }
    inline Format getFormat() const { return _format; }
    inline void setFormat(Format format) { this->_format = format; }
    inline const ComponentMapping& getComponents() const { return _components; }
    inline void setComponents(const ComponentMapping& components) { this->_components = components; }
    inline const ImageSubresourceRange& getSubresourceRange() const { return _subresourceRange; }
    inline void setSubresourceRange(const ImageSubresourceRange& subresourceRange) { this->_subresourceRange = subresourceRange; }
    inline const void* getpNext() const { return _pNext; }
    inline void setpNext(const void* pNext) { this->_pNext = pNext; }

private:
    Image _image;
    ImageViewType _viewType;
    Format _format;
    ComponentMapping _components;
    ImageSubresourceRange _subresourceRange;
    ImageViewCreateFlags _flags;
    const void* _pNext;
};

namespace impl {
class ImageView_ : public PVRVkDeviceObjectBase<VkImageView, ObjectType::e_IMAGE_VIEW>, public DeviceObjectDebugUtils<ImageView_>
{
private:
    friend class Device_;

    class make_shared_enabler
    {
    protected:
        make_shared_enabler() {}
        friend class ImageView_;
    };

    static ImageView constructShared(const DeviceWeakPtr& device, const ImageViewCreateInfo& createInfo)
    {
        return std::make_shared<ImageView_>(make_shared_enabler{}, device, createInfo);
    }

    ImageViewCreateInfo _createInfo;

public:
    DECLARE_NO_COPY_SEMANTICS(ImageView_)
    ImageView_(make_shared_enabler, const DeviceWeakPtr& device, const ImageViewCreateInfo& createInfo);

    ~ImageView_();

    inline ImageViewCreateFlags getFlags() const { return _createInfo.getFlags(); }
    inline Image& getImage() { return _createInfo.getImage(); }
    inline const Image& getImage() const { return _createInfo.getImage(); }
    inline ImageViewType getViewType() const { return _createInfo.getViewType(); }
    inline Format getFormat() const { return _createInfo.getFormat(); }
    inline const ComponentMapping& getComponents() const { return _createInfo.getComponents(); }
    inline const ImageSubresourceRange& getSubresourceRange() const { return _createInfo.getSubresourceRange(); }
    ImageViewCreateInfo getCreateInfo() const { return _createInfo; }
};
} // namespace impl
} // namespace pvrvk