Edit

kc3-lang/angle/src/libANGLE/renderer/vulkan/vk_utils.h

Branch :

  • Show log

    Commit

  • Author : Luc Ferron
    Date : 2018-05-24 15:51:29
    Hash : 05cd6dfc
    Message : Vulkan: generateMipmaps with vkCmdBlitImage when possible Bug: angleproject:2502 Change-Id: Ib32a128a453749c59d751e996017a8a6e2a9972e Reviewed-on: https://chromium-review.googlesource.com/1072550 Reviewed-by: Corentin Wallez <cwallez@chromium.org> Commit-Queue: Luc Ferron <lucferron@chromium.org>

  • src/libANGLE/renderer/vulkan/vk_utils.h
  • //
    // Copyright 2016 The ANGLE Project Authors. All rights reserved.
    // Use of this source code is governed by a BSD-style license that can be
    // found in the LICENSE file.
    //
    // vk_utils:
    //    Helper functions for the Vulkan Renderer.
    //
    
    #ifndef LIBANGLE_RENDERER_VULKAN_VK_UTILS_H_
    #define LIBANGLE_RENDERER_VULKAN_VK_UTILS_H_
    
    #include <limits>
    
    #include <vulkan/vulkan.h>
    
    #include "common/Optional.h"
    #include "common/PackedEnums.h"
    #include "common/debug.h"
    #include "libANGLE/Error.h"
    #include "libANGLE/Observer.h"
    #include "libANGLE/renderer/renderer_utils.h"
    
    #define ANGLE_GL_OBJECTS_X(PROC) \
        PROC(Buffer)                 \
        PROC(Context)                \
        PROC(Framebuffer)            \
        PROC(Program)                \
        PROC(Texture)                \
        PROC(VertexArray)
    
    #define ANGLE_PRE_DECLARE_OBJECT(OBJ) class OBJ;
    
    namespace egl
    {
    class Display;
    }
    
    namespace gl
    {
    struct Box;
    class DrawCallParams;
    struct Extents;
    struct RasterizerState;
    struct Rectangle;
    struct SwizzleState;
    struct VertexAttribute;
    class VertexBinding;
    
    ANGLE_GL_OBJECTS_X(ANGLE_PRE_DECLARE_OBJECT);
    }
    
    #define ANGLE_PRE_DECLARE_VK_OBJECT(OBJ) class OBJ##Vk;
    
    namespace rx
    {
    class CommandGraphResource;
    class DisplayVk;
    class RenderTargetVk;
    class RendererVk;
    class RenderPassCache;
    
    ANGLE_GL_OBJECTS_X(ANGLE_PRE_DECLARE_VK_OBJECT);
    
    const char *VulkanResultString(VkResult result);
    // Verify that validation layers are available.
    bool GetAvailableValidationLayers(const std::vector<VkLayerProperties> &layerProps,
                                      bool mustHaveLayers,
                                      const char *const **enabledLayerNames,
                                      uint32_t *enabledLayerCount);
    
    uint32_t GetImageLayerCount(gl::TextureType textureType);
    
    extern const char *g_VkLoaderLayersPathEnv;
    extern const char *g_VkICDPathEnv;
    
    enum class TextureDimension
    {
        TEX_2D,
        TEX_CUBE,
        TEX_3D,
        TEX_2D_ARRAY,
    };
    
    namespace vk
    {
    struct Format;
    
    template <typename T>
    struct ImplTypeHelper;
    
    // clang-format off
    #define ANGLE_IMPL_TYPE_HELPER_GL(OBJ) \
    template<>                             \
    struct ImplTypeHelper<gl::OBJ>         \
    {                                      \
        using ImplType = OBJ##Vk;          \
    };
    // clang-format on
    
    ANGLE_GL_OBJECTS_X(ANGLE_IMPL_TYPE_HELPER_GL)
    
    template <>
    struct ImplTypeHelper<egl::Display>
    {
        using ImplType = DisplayVk;
    };
    
    template <typename T>
    using GetImplType = typename ImplTypeHelper<T>::ImplType;
    
    template <typename T>
    GetImplType<T> *GetImpl(const T *glObject)
    {
        return GetImplAs<GetImplType<T>>(glObject);
    }
    
    class Error final
    {
      public:
        Error(VkResult result);
        Error(VkResult result, const char *file, unsigned int line);
        ~Error();
    
        Error(const Error &other);
        Error &operator=(const Error &other);
    
        gl::Error toGL(GLenum glErrorCode) const;
        egl::Error toEGL(EGLint eglErrorCode) const;
    
        operator gl::Error() const;
        operator egl::Error() const;
    
        template <typename T>
        operator gl::ErrorOrResult<T>() const
        {
            return operator gl::Error();
        }
    
        bool isError() const;
    
        std::string toString() const;
    
      private:
        VkResult mResult;
        const char *mFile;
        unsigned int mLine;
    };
    
    template <typename ResultT>
    using ErrorOrResult = angle::ErrorOrResultBase<Error, ResultT, VkResult, VK_SUCCESS>;
    
    // Avoid conflicting with X headers which define "Success".
    inline Error NoError()
    {
        return Error(VK_SUCCESS);
    }
    
    // Unimplemented handle types:
    // Instance
    // PhysicalDevice
    // Device
    // Queue
    // Event
    // QueryPool
    // BufferView
    // DescriptorSet
    // PipelineCache
    
    #define ANGLE_HANDLE_TYPES_X(FUNC) \
        FUNC(Semaphore)                \
        FUNC(CommandBuffer)            \
        FUNC(Fence)                    \
        FUNC(DeviceMemory)             \
        FUNC(Buffer)                   \
        FUNC(Image)                    \
        FUNC(ImageView)                \
        FUNC(ShaderModule)             \
        FUNC(PipelineLayout)           \
        FUNC(RenderPass)               \
        FUNC(Pipeline)                 \
        FUNC(DescriptorSetLayout)      \
        FUNC(Sampler)                  \
        FUNC(DescriptorPool)           \
        FUNC(Framebuffer)              \
        FUNC(CommandPool)
    
    #define ANGLE_COMMA_SEP_FUNC(TYPE) TYPE,
    
    enum class HandleType
    {
        Invalid,
        ANGLE_HANDLE_TYPES_X(ANGLE_COMMA_SEP_FUNC)
    };
    
    #undef ANGLE_COMMA_SEP_FUNC
    
    #define ANGLE_PRE_DECLARE_CLASS_FUNC(TYPE) class TYPE;
    ANGLE_HANDLE_TYPES_X(ANGLE_PRE_DECLARE_CLASS_FUNC)
    #undef ANGLE_PRE_DECLARE_CLASS_FUNC
    
    // Returns the HandleType of a Vk Handle.
    template <typename T>
    struct HandleTypeHelper;
    
    // clang-format off
    #define ANGLE_HANDLE_TYPE_HELPER_FUNC(TYPE)                     \
    template<> struct HandleTypeHelper<TYPE>                        \
    {                                                               \
        constexpr static HandleType kHandleType = HandleType::TYPE; \
    };
    // clang-format on
    
    ANGLE_HANDLE_TYPES_X(ANGLE_HANDLE_TYPE_HELPER_FUNC)
    
    #undef ANGLE_HANDLE_TYPE_HELPER_FUNC
    
    class GarbageObject final
    {
      public:
        template <typename ObjectT>
        GarbageObject(Serial serial, const ObjectT &object)
            : mSerial(serial),
              mHandleType(HandleTypeHelper<ObjectT>::kHandleType),
              mHandle(reinterpret_cast<VkDevice>(object.getHandle()))
        {
        }
    
        GarbageObject();
        GarbageObject(const GarbageObject &other);
        GarbageObject &operator=(const GarbageObject &other);
    
        bool destroyIfComplete(VkDevice device, Serial completedSerial);
        void destroy(VkDevice device);
    
      private:
        // TODO(jmadill): Since many objects will have the same serial, it might be more efficient to
        // store the serial outside of the garbage object itself. We could index ranges of garbage
        // objects in the Renderer, using a circular buffer.
        Serial mSerial;
        HandleType mHandleType;
        VkDevice mHandle;
    };
    
    template <typename DerivedT, typename HandleT>
    class WrappedObject : angle::NonCopyable
    {
      public:
        HandleT getHandle() const { return mHandle; }
        bool valid() const { return (mHandle != VK_NULL_HANDLE); }
    
        const HandleT *ptr() const { return &mHandle; }
    
        void dumpResources(Serial serial, std::vector<GarbageObject> *garbageQueue)
        {
            if (valid())
            {
                garbageQueue->emplace_back(serial, *static_cast<DerivedT *>(this));
                mHandle = VK_NULL_HANDLE;
            }
        }
    
      protected:
        WrappedObject() : mHandle(VK_NULL_HANDLE) {}
        ~WrappedObject() { ASSERT(!valid()); }
    
        WrappedObject(WrappedObject &&other) : mHandle(other.mHandle)
        {
            other.mHandle = VK_NULL_HANDLE;
        }
    
        // Only works to initialize empty objects, since we don't have the device handle.
        WrappedObject &operator=(WrappedObject &&other)
        {
            ASSERT(!valid());
            std::swap(mHandle, other.mHandle);
            return *this;
        }
    
        HandleT mHandle;
    };
    
    class MemoryProperties final : angle::NonCopyable
    {
      public:
        MemoryProperties();
    
        void init(VkPhysicalDevice physicalDevice);
        Error findCompatibleMemoryIndex(const VkMemoryRequirements &memoryRequirements,
                                        VkMemoryPropertyFlags memoryPropertyFlags,
                                        uint32_t *indexOut) const;
    
      private:
        VkPhysicalDeviceMemoryProperties mMemoryProperties;
    };
    
    class CommandPool final : public WrappedObject<CommandPool, VkCommandPool>
    {
      public:
        CommandPool();
    
        void destroy(VkDevice device);
    
        Error init(VkDevice device, const VkCommandPoolCreateInfo &createInfo);
    };
    
    // Helper class that wraps a Vulkan command buffer.
    class CommandBuffer : public WrappedObject<CommandBuffer, VkCommandBuffer>
    {
      public:
        CommandBuffer();
    
        VkCommandBuffer releaseHandle();
        void destroy(VkDevice device, const CommandPool &commandPool);
        Error init(VkDevice device, const VkCommandBufferAllocateInfo &createInfo);
        void blitImage(const Image &srcImage,
                       VkImageLayout srcImageLayout,
                       const Image &dstImage,
                       VkImageLayout dstImageLayout,
                       uint32_t regionCount,
                       VkImageBlit *pRegions,
                       VkFilter filter);
        using WrappedObject::operator=;
    
        Error begin(const VkCommandBufferBeginInfo &info);
    
        Error end();
        Error reset();
    
        void singleImageBarrier(VkPipelineStageFlags srcStageMask,
                                VkPipelineStageFlags dstStageMask,
                                VkDependencyFlags dependencyFlags,
                                const VkImageMemoryBarrier &imageMemoryBarrier);
    
        void singleBufferBarrier(VkPipelineStageFlags srcStageMask,
                                 VkPipelineStageFlags dstStageMask,
                                 VkDependencyFlags dependencyFlags,
                                 const VkBufferMemoryBarrier &bufferBarrier);
    
        void clearColorImage(const Image &image,
                             VkImageLayout imageLayout,
                             const VkClearColorValue &color,
                             uint32_t rangeCount,
                             const VkImageSubresourceRange *ranges);
        void clearDepthStencilImage(const Image &image,
                                    VkImageLayout imageLayout,
                                    const VkClearDepthStencilValue &depthStencil,
                                    uint32_t rangeCount,
                                    const VkImageSubresourceRange *ranges);
    
        void clearAttachments(uint32_t attachmentCount,
                              const VkClearAttachment *attachments,
                              uint32_t rectCount,
                              const VkClearRect *rects);
    
        void copyBuffer(const Buffer &srcBuffer,
                        const Buffer &destBuffer,
                        uint32_t regionCount,
                        const VkBufferCopy *regions);
    
        void copyBuffer(const VkBuffer &srcBuffer,
                        const VkBuffer &destBuffer,
                        uint32_t regionCount,
                        const VkBufferCopy *regions);
    
        void copyBufferToImage(VkBuffer srcBuffer,
                               const Image &dstImage,
                               VkImageLayout dstImageLayout,
                               uint32_t regionCount,
                               const VkBufferImageCopy *regions);
        void copyImageToBuffer(const Image &srcImage,
                               VkImageLayout srcImageLayout,
                               VkBuffer dstBuffer,
                               uint32_t regionCount,
                               const VkBufferImageCopy *regions);
        void copyImage(const Image &srcImage,
                       VkImageLayout srcImageLayout,
                       const Image &dstImage,
                       VkImageLayout dstImageLayout,
                       uint32_t regionCount,
                       const VkImageCopy *regions);
    
        void beginRenderPass(const VkRenderPassBeginInfo &beginInfo, VkSubpassContents subpassContents);
        void endRenderPass();
    
        void draw(uint32_t vertexCount,
                  uint32_t instanceCount,
                  uint32_t firstVertex,
                  uint32_t firstInstance);
    
        void drawIndexed(uint32_t indexCount,
                         uint32_t instanceCount,
                         uint32_t firstIndex,
                         int32_t vertexOffset,
                         uint32_t firstInstance);
    
        void bindPipeline(VkPipelineBindPoint pipelineBindPoint, const Pipeline &pipeline);
        void bindVertexBuffers(uint32_t firstBinding,
                               uint32_t bindingCount,
                               const VkBuffer *buffers,
                               const VkDeviceSize *offsets);
        void bindIndexBuffer(const VkBuffer &buffer, VkDeviceSize offset, VkIndexType indexType);
        void bindDescriptorSets(VkPipelineBindPoint bindPoint,
                                const PipelineLayout &layout,
                                uint32_t firstSet,
                                uint32_t descriptorSetCount,
                                const VkDescriptorSet *descriptorSets,
                                uint32_t dynamicOffsetCount,
                                const uint32_t *dynamicOffsets);
    
        void executeCommands(uint32_t commandBufferCount, const CommandBuffer *commandBuffers);
        void updateBuffer(const vk::Buffer &buffer,
                          VkDeviceSize dstOffset,
                          VkDeviceSize dataSize,
                          const void *data);
        void pushConstants(const PipelineLayout &layout,
                           VkShaderStageFlags flag,
                           uint32_t offset,
                           uint32_t size,
                           const void *data);
    };
    
    class Image final : public WrappedObject<Image, VkImage>
    {
      public:
        Image();
    
        // Use this method if the lifetime of the image is not controlled by ANGLE. (SwapChain)
        void setHandle(VkImage handle);
    
        // Called on shutdown when the helper class *doesn't* own the handle to the image resource.
        void reset();
    
        // Called on shutdown when the helper class *does* own the handle to the image resource.
        void destroy(VkDevice device);
    
        Error init(VkDevice device, const VkImageCreateInfo &createInfo);
    
        void getMemoryRequirements(VkDevice device, VkMemoryRequirements *requirementsOut) const;
        Error bindMemory(VkDevice device, const DeviceMemory &deviceMemory);
    
        void getSubresourceLayout(VkDevice device,
                                  VkImageAspectFlagBits aspectMask,
                                  uint32_t mipLevel,
                                  uint32_t arrayLayer,
                                  VkSubresourceLayout *outSubresourceLayout) const;
    };
    
    class ImageView final : public WrappedObject<ImageView, VkImageView>
    {
      public:
        ImageView();
        void destroy(VkDevice device);
    
        Error init(VkDevice device, const VkImageViewCreateInfo &createInfo);
    };
    
    class Semaphore final : public WrappedObject<Semaphore, VkSemaphore>
    {
      public:
        Semaphore();
        void destroy(VkDevice device);
    
        Error init(VkDevice device);
    };
    
    class Framebuffer final : public WrappedObject<Framebuffer, VkFramebuffer>
    {
      public:
        Framebuffer();
        void destroy(VkDevice device);
    
        // Use this method only in necessary cases. (RenderPass)
        void setHandle(VkFramebuffer handle);
    
        Error init(VkDevice device, const VkFramebufferCreateInfo &createInfo);
    };
    
    class DeviceMemory final : public WrappedObject<DeviceMemory, VkDeviceMemory>
    {
      public:
        DeviceMemory();
        void destroy(VkDevice device);
    
        Error allocate(VkDevice device, const VkMemoryAllocateInfo &allocInfo);
        Error map(VkDevice device,
                  VkDeviceSize offset,
                  VkDeviceSize size,
                  VkMemoryMapFlags flags,
                  uint8_t **mapPointer) const;
        void unmap(VkDevice device) const;
    };
    
    class RenderPass final : public WrappedObject<RenderPass, VkRenderPass>
    {
      public:
        RenderPass();
        void destroy(VkDevice device);
    
        Error init(VkDevice device, const VkRenderPassCreateInfo &createInfo);
    };
    
    enum class StagingUsage
    {
        Read,
        Write,
        Both,
    };
    
    class Buffer final : public WrappedObject<Buffer, VkBuffer>
    {
      public:
        Buffer();
        void destroy(VkDevice device);
    
        Error init(VkDevice device, const VkBufferCreateInfo &createInfo);
        Error bindMemory(VkDevice device, const DeviceMemory &deviceMemory);
        void getMemoryRequirements(VkDevice device, VkMemoryRequirements *memoryRequirementsOut);
    };
    
    class ShaderModule final : public WrappedObject<ShaderModule, VkShaderModule>
    {
      public:
        ShaderModule();
        void destroy(VkDevice device);
    
        Error init(VkDevice device, const VkShaderModuleCreateInfo &createInfo);
    };
    
    class Pipeline final : public WrappedObject<Pipeline, VkPipeline>
    {
      public:
        Pipeline();
        void destroy(VkDevice device);
    
        Error initGraphics(VkDevice device, const VkGraphicsPipelineCreateInfo &createInfo);
    };
    
    class PipelineLayout final : public WrappedObject<PipelineLayout, VkPipelineLayout>
    {
      public:
        PipelineLayout();
        void destroy(VkDevice device);
    
        Error init(VkDevice device, const VkPipelineLayoutCreateInfo &createInfo);
    };
    
    class DescriptorSetLayout final : public WrappedObject<DescriptorSetLayout, VkDescriptorSetLayout>
    {
      public:
        DescriptorSetLayout();
        void destroy(VkDevice device);
    
        Error init(VkDevice device, const VkDescriptorSetLayoutCreateInfo &createInfo);
    };
    
    class DescriptorPool final : public WrappedObject<DescriptorPool, VkDescriptorPool>
    {
      public:
        DescriptorPool();
        void destroy(VkDevice device);
    
        Error init(VkDevice device, const VkDescriptorPoolCreateInfo &createInfo);
    
        Error allocateDescriptorSets(VkDevice device,
                                     const VkDescriptorSetAllocateInfo &allocInfo,
                                     VkDescriptorSet *descriptorSetsOut);
        Error freeDescriptorSets(VkDevice device,
                                 uint32_t descriptorSetCount,
                                 const VkDescriptorSet *descriptorSets);
    };
    
    class Sampler final : public WrappedObject<Sampler, VkSampler>
    {
      public:
        Sampler();
        void destroy(VkDevice device);
        Error init(VkDevice device, const VkSamplerCreateInfo &createInfo);
    };
    
    class Fence final : public WrappedObject<Fence, VkFence>
    {
      public:
        Fence();
        void destroy(VkDevice fence);
        using WrappedObject::operator=;
    
        Error init(VkDevice device, const VkFenceCreateInfo &createInfo);
        VkResult getStatus(VkDevice device) const;
    };
    
    // Similar to StagingImage, for Buffers.
    class StagingBuffer final : angle::NonCopyable
    {
      public:
        StagingBuffer();
        void destroy(VkDevice device);
    
        Error init(ContextVk *contextVk, VkDeviceSize size, StagingUsage usage);
    
        Buffer &getBuffer() { return mBuffer; }
        const Buffer &getBuffer() const { return mBuffer; }
        DeviceMemory &getDeviceMemory() { return mDeviceMemory; }
        const DeviceMemory &getDeviceMemory() const { return mDeviceMemory; }
        size_t getSize() const { return mSize; }
    
        void dumpResources(Serial serial, std::vector<GarbageObject> *garbageQueue);
    
      private:
        Buffer mBuffer;
        DeviceMemory mDeviceMemory;
        size_t mSize;
    };
    
    template <typename ObjT>
    class ObjectAndSerial final : angle::NonCopyable
    {
      public:
        ObjectAndSerial() {}
    
        ObjectAndSerial(ObjT &&object, Serial queueSerial)
            : mObject(std::move(object)), mQueueSerial(queueSerial)
        {
        }
    
        ObjectAndSerial(ObjectAndSerial &&other)
            : mObject(std::move(other.mObject)), mQueueSerial(std::move(other.mQueueSerial))
        {
        }
        ObjectAndSerial &operator=(ObjectAndSerial &&other)
        {
            mObject      = std::move(other.mObject);
            mQueueSerial = std::move(other.mQueueSerial);
            return *this;
        }
    
        Serial queueSerial() const { return mQueueSerial; }
        void updateSerial(Serial newSerial)
        {
            ASSERT(newSerial >= mQueueSerial);
            mQueueSerial = newSerial;
        }
    
        const ObjT &get() const { return mObject; }
        ObjT &get() { return mObject; }
    
        bool valid() const { return mObject.valid(); }
    
      private:
        ObjT mObject;
        Serial mQueueSerial;
    };
    
    Error AllocateBufferMemory(RendererVk *renderer,
                               VkMemoryPropertyFlags memoryPropertyFlags,
                               Buffer *buffer,
                               DeviceMemory *deviceMemoryOut,
                               size_t *requiredSizeOut);
    
    struct BufferAndMemory final : angle::NonCopyable
    {
        BufferAndMemory();
        BufferAndMemory(Buffer &&buffer, DeviceMemory &&deviceMemory);
        BufferAndMemory(BufferAndMemory &&other);
        BufferAndMemory &operator=(BufferAndMemory &&other);
    
        Buffer buffer;
        DeviceMemory memory;
    };
    
    Error AllocateImageMemory(VkDevice device,
                              const MemoryProperties &memoryProperties,
                              VkMemoryPropertyFlags memoryPropertyFlags,
                              Image *image,
                              DeviceMemory *deviceMemoryOut,
                              size_t *requiredSizeOut);
    
    using ShaderAndSerial = ObjectAndSerial<ShaderModule>;
    
    // TODO(jmadill): Use gl::ShaderType when possible. http://anglebug.com/2522
    enum class ShaderType
    {
        VertexShader,
        FragmentShader,
        EnumCount,
        InvalidEnum = EnumCount,
    };
    
    template <typename T>
    using ShaderMap = angle::PackedEnumMap<ShaderType, T>;
    
    using AllShaderTypes = angle::AllEnums<vk::ShaderType>;
    
    enum class RecordingMode
    {
        Start,
        Append,
    };
    }  // namespace vk
    
    namespace gl_vk
    {
    VkRect2D GetRect(const gl::Rectangle &source);
    VkFilter GetFilter(const GLenum filter);
    VkSamplerMipmapMode GetSamplerMipmapMode(const GLenum filter);
    VkSamplerAddressMode GetSamplerAddressMode(const GLenum wrap);
    VkPrimitiveTopology GetPrimitiveTopology(gl::PrimitiveMode mode);
    VkCullModeFlags GetCullMode(const gl::RasterizerState &rasterState);
    VkFrontFace GetFrontFace(GLenum frontFace);
    VkSampleCountFlagBits GetSamples(GLint sampleCount);
    VkComponentSwizzle GetSwizzle(const GLenum swizzle);
    VkIndexType GetIndexType(GLenum elementType);
    void GetOffset(const gl::Offset &glOffset, VkOffset3D *vkOffset);
    void GetExtent(const gl::Extents &glExtent, VkExtent3D *vkExtent);
    VkImageType GetImageType(gl::TextureType textureType);
    VkImageViewType GetImageViewType(gl::TextureType textureType);
    VkColorComponentFlags GetColorComponentFlags(bool red, bool green, bool blue, bool alpha);
    }  // namespace gl_vk
    
    }  // namespace rx
    
    #define ANGLE_VK_TRY(command)                                          \
        {                                                                  \
            auto ANGLE_LOCAL_VAR = command;                                \
            if (ANGLE_UNLIKELY(ANGLE_LOCAL_VAR != VK_SUCCESS))             \
            {                                                              \
                return rx::vk::Error(ANGLE_LOCAL_VAR, __FILE__, __LINE__); \
            }                                                              \
        }                                                                  \
        ANGLE_EMPTY_STATEMENT
    
    #define ANGLE_VK_CHECK(test, error) ANGLE_VK_TRY(test ? VK_SUCCESS : error)
    
    std::ostream &operator<<(std::ostream &stream, const rx::vk::Error &error);
    
    #endif  // LIBANGLE_RENDERER_VULKAN_VK_UTILS_H_