Edit

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

Branch :

  • Show log

    Commit

  • Author : Cody Northrop
    Date : 2019-07-01 03:22:42
    Hash : 7d6923de
    Message : Revert "Vulkan: pipeline cache not populated as blob cache is not set" This reverts commit 134d6eed2a7d1f148a42c78c8e5da3cfc2df288e. Reason for revert: glmark2 is unable to start on Android-Q when using ANGLE as the driver. Original change's description: > Vulkan: pipeline cache not populated as blob cache is not set > > 1. Use vkMergePipelineCaches in eglSetBlobCacheFuncsANDROID as > blob cache callbacks are set after eglInititalize. > 2. Use a more proper way to save the cache data to disk. > > Bug: angleproject:3318 > Change-Id: Ieb5d10ab93e7afb2aab4446b387d7f36c878a686 > Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/1559671 > Reviewed-by: Jamie Madill <jmadill@chromium.org> > Commit-Queue: Jamie Madill <jmadill@chromium.org> TBR=syoussefi@chromium.org,jmadill@chromium.org,fei.yang@arm.com # Not skipping CQ checks because original CL landed > 1 day ago. Bug: angleproject:3318 Change-Id: I51e49bf103142e80b2c9028b3af6d3bb58cf6348 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/1683820 Reviewed-by: Cody Northrop <cnorthrop@google.com> Commit-Queue: Jamie Madill <jmadill@chromium.org>

  • src/libANGLE/renderer/vulkan/vk_wrapper.h
  • //
    // Copyright 2019 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_wrapper:
    //    Wrapper classes around Vulkan objects. In an ideal world we could generate this
    //    from vk.xml. Or reuse the generator in the vkhpp tool. For now this is manually
    //    generated and we must add missing functions and objects as we need them.
    
    #ifndef LIBANGLE_RENDERER_VULKAN_VK_WRAPPER_H_
    #define LIBANGLE_RENDERER_VULKAN_VK_WRAPPER_H_
    
    #include <vulkan/vulkan.h>
    
    #include "libANGLE/renderer/renderer_utils.h"
    
    namespace rx
    {
    namespace vk
    {
    // Base class for all wrapped vulkan objects. Implements several common helper routines.
    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; }
    
        template <typename ResourceOutType>
        void dumpResources(Serial serial, std::vector<ResourceOutType> *outQueue)
        {
            if (valid())
            {
                outQueue->emplace_back(serial, *static_cast<DerivedT *>(this));
                mHandle = VK_NULL_HANDLE;
            }
        }
    
        template <typename ResourceOutType>
        void dumpResources(std::vector<ResourceOutType> *outQueue)
        {
            if (valid())
            {
                outQueue->emplace_back(*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;
    };
    
    // Helper macros that apply to all the wrapped object types.
    // Unimplemented handle types:
    // Instance
    // PhysicalDevice
    // Device
    // Queue
    // DescriptorSet
    
    #define ANGLE_HANDLE_TYPES_X(FUNC) \
        FUNC(Buffer)                   \
        FUNC(BufferView)               \
        FUNC(CommandPool)              \
        FUNC(DescriptorPool)           \
        FUNC(DescriptorSetLayout)      \
        FUNC(DeviceMemory)             \
        FUNC(Event)                    \
        FUNC(Fence)                    \
        FUNC(Framebuffer)              \
        FUNC(Image)                    \
        FUNC(ImageView)                \
        FUNC(Pipeline)                 \
        FUNC(PipelineCache)            \
        FUNC(PipelineLayout)           \
        FUNC(QueryPool)                \
        FUNC(RenderPass)               \
        FUNC(Sampler)                  \
        FUNC(Semaphore)                \
        FUNC(ShaderModule)
    
    #define ANGLE_COMMA_SEP_FUNC(TYPE) TYPE,
    
    enum class HandleType
    {
        Invalid,
        CommandBuffer,
        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)
    namespace priv
    {
    class CommandBuffer;
    }  // namespace priv
    #undef ANGLE_PRE_DECLARE_CLASS_FUNC
    
    // Returns the HandleType of a Vk Handle.
    template <typename T>
    struct HandleTypeHelper;
    
    #define ANGLE_HANDLE_TYPE_HELPER_FUNC(TYPE)                         \
        template <>                                                     \
        struct HandleTypeHelper<TYPE>                                   \
        {                                                               \
            constexpr static HandleType kHandleType = HandleType::TYPE; \
        };
    
    ANGLE_HANDLE_TYPES_X(ANGLE_HANDLE_TYPE_HELPER_FUNC)
    template <>
    struct HandleTypeHelper<priv::CommandBuffer>
    {
        constexpr static HandleType kHandleType = HandleType::CommandBuffer;
    };
    
    #undef ANGLE_HANDLE_TYPE_HELPER_FUNC
    
    class CommandPool final : public WrappedObject<CommandPool, VkCommandPool>
    {
      public:
        CommandPool() = default;
    
        void destroy(VkDevice device);
        VkResult reset(VkDevice device, VkCommandPoolResetFlags flags);
    
        VkResult init(VkDevice device, const VkCommandPoolCreateInfo &createInfo);
    };
    
    class Pipeline final : public WrappedObject<Pipeline, VkPipeline>
    {
      public:
        Pipeline() = default;
        void destroy(VkDevice device);
    
        VkResult initGraphics(VkDevice device,
                              const VkGraphicsPipelineCreateInfo &createInfo,
                              const PipelineCache &pipelineCacheVk);
        VkResult initCompute(VkDevice device,
                             const VkComputePipelineCreateInfo &createInfo,
                             const PipelineCache &pipelineCacheVk);
    };
    
    namespace priv
    {
    
    // Helper class that wraps a Vulkan command buffer.
    class CommandBuffer : public WrappedObject<CommandBuffer, VkCommandBuffer>
    {
      public:
        CommandBuffer() = default;
    
        VkCommandBuffer releaseHandle();
    
        // This is used for normal pool allocated command buffers. It reset the handle.
        void destroy(VkDevice device);
    
        // This is used in conjunction with VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT.
        void destroy(VkDevice device, const CommandPool &commandPool);
    
        VkResult init(VkDevice device, const VkCommandBufferAllocateInfo &createInfo);
    
        // There is no way to know if the command buffer contains any commands.
        static bool CanKnowIfEmpty() { return false; }
        bool empty() const { return false; }
    
        using WrappedObject::operator=;
    
        static bool SupportsQueries(const VkPhysicalDeviceFeatures &features)
        {
            return features.inheritedQueries;
        }
    
        // Vulkan command buffers are executed as secondary command buffers within a primary command
        // buffer.
        static constexpr bool ExecutesInline() { return false; }
    
        VkResult begin(const VkCommandBufferBeginInfo &info);
    
        void beginQuery(VkQueryPool queryPool, uint32_t query, VkQueryControlFlags flags);
    
        void beginRenderPass(const VkRenderPassBeginInfo &beginInfo, VkSubpassContents subpassContents);
    
        void bindGraphicsDescriptorSets(const PipelineLayout &layout,
                                        uint32_t firstSet,
                                        uint32_t descriptorSetCount,
                                        const VkDescriptorSet *descriptorSets,
                                        uint32_t dynamicOffsetCount,
                                        const uint32_t *dynamicOffsets);
        void bindGraphicsPipeline(const Pipeline &pipeline);
        void bindComputeDescriptorSets(const PipelineLayout &layout,
                                       const VkDescriptorSet *descriptorSets);
        void bindComputePipeline(const Pipeline &pipeline);
        void bindPipeline(VkPipelineBindPoint pipelineBindPoint, const Pipeline &pipeline);
    
        void bindIndexBuffer(const Buffer &buffer, VkDeviceSize offset, VkIndexType indexType);
        void bindVertexBuffers(uint32_t firstBinding,
                               uint32_t bindingCount,
                               const VkBuffer *buffers,
                               const VkDeviceSize *offsets);
    
        void blitImage(const Image &srcImage,
                       VkImageLayout srcImageLayout,
                       const Image &dstImage,
                       VkImageLayout dstImageLayout,
                       uint32_t regionCount,
                       const VkImageBlit *regions,
                       VkFilter filter);
    
        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 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 dispatch(uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ);
    
        void draw(uint32_t vertexCount,
                  uint32_t instanceCount,
                  uint32_t firstVertex,
                  uint32_t firstInstance);
        void draw(uint32_t vertexCount, uint32_t firstVertex);
        void drawInstanced(uint32_t vertexCount, uint32_t instanceCount, uint32_t firstVertex);
        void drawIndexed(uint32_t indexCount,
                         uint32_t instanceCount,
                         uint32_t firstIndex,
                         int32_t vertexOffset,
                         uint32_t firstInstance);
        void drawIndexed(uint32_t indexCount);
        void drawIndexedInstanced(uint32_t indexCount, uint32_t instanceCount);
    
        VkResult end();
        void endQuery(VkQueryPool queryPool, uint32_t query);
        void endRenderPass();
        void executeCommands(uint32_t commandBufferCount, const CommandBuffer *commandBuffers);
    
        void executionBarrier(VkPipelineStageFlags stageMask);
    
        void fillBuffer(const Buffer &dstBuffer,
                        VkDeviceSize dstOffset,
                        VkDeviceSize size,
                        uint32_t data);
    
        void imageBarrier(VkPipelineStageFlags srcStageMask,
                          VkPipelineStageFlags dstStageMask,
                          const VkImageMemoryBarrier *imageMemoryBarrier);
    
        void memoryBarrier(VkPipelineStageFlags srcStageMask,
                           VkPipelineStageFlags dstStageMask,
                           const VkMemoryBarrier *memoryBarrier);
    
        void pipelineBarrier(VkPipelineStageFlags srcStageMask,
                             VkPipelineStageFlags dstStageMask,
                             VkDependencyFlags dependencyFlags,
                             uint32_t memoryBarrierCount,
                             const VkMemoryBarrier *memoryBarriers,
                             uint32_t bufferMemoryBarrierCount,
                             const VkBufferMemoryBarrier *bufferMemoryBarriers,
                             uint32_t imageMemoryBarrierCount,
                             const VkImageMemoryBarrier *imageMemoryBarriers);
    
        void pushConstants(const PipelineLayout &layout,
                           VkShaderStageFlags flag,
                           uint32_t offset,
                           uint32_t size,
                           const void *data);
    
        void setEvent(VkEvent event, VkPipelineStageFlags stageMask);
        VkResult reset();
        void resetEvent(VkEvent event, VkPipelineStageFlags stageMask);
        void resetQueryPool(VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount);
        void resolveImage(const Image &srcImage,
                          VkImageLayout srcImageLayout,
                          const Image &dstImage,
                          VkImageLayout dstImageLayout,
                          uint32_t regionCount,
                          const VkImageResolve *regions);
        void waitEvents(uint32_t eventCount,
                        const VkEvent *events,
                        VkPipelineStageFlags srcStageMask,
                        VkPipelineStageFlags dstStageMask,
                        uint32_t memoryBarrierCount,
                        const VkMemoryBarrier *memoryBarriers,
                        uint32_t bufferMemoryBarrierCount,
                        const VkBufferMemoryBarrier *bufferMemoryBarriers,
                        uint32_t imageMemoryBarrierCount,
                        const VkImageMemoryBarrier *imageMemoryBarriers);
    
        void writeTimestamp(VkPipelineStageFlagBits pipelineStage,
                            VkQueryPool queryPool,
                            uint32_t query);
    };
    }  // namespace priv
    
    class Image final : public WrappedObject<Image, VkImage>
    {
      public:
        Image() = default;
    
        // 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);
    
        VkResult init(VkDevice device, const VkImageCreateInfo &createInfo);
    
        void getMemoryRequirements(VkDevice device, VkMemoryRequirements *requirementsOut) const;
        VkResult 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() = default;
        void destroy(VkDevice device);
    
        VkResult init(VkDevice device, const VkImageViewCreateInfo &createInfo);
    };
    
    class Semaphore final : public WrappedObject<Semaphore, VkSemaphore>
    {
      public:
        Semaphore() = default;
        void destroy(VkDevice device);
    
        VkResult init(VkDevice device);
    };
    
    class Framebuffer final : public WrappedObject<Framebuffer, VkFramebuffer>
    {
      public:
        Framebuffer() = default;
        void destroy(VkDevice device);
    
        // Use this method only in necessary cases. (RenderPass)
        void setHandle(VkFramebuffer handle);
    
        VkResult init(VkDevice device, const VkFramebufferCreateInfo &createInfo);
    };
    
    class DeviceMemory final : public WrappedObject<DeviceMemory, VkDeviceMemory>
    {
      public:
        DeviceMemory() = default;
        void destroy(VkDevice device);
    
        VkResult allocate(VkDevice device, const VkMemoryAllocateInfo &allocInfo);
        VkResult 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() = default;
        void destroy(VkDevice device);
    
        VkResult init(VkDevice device, const VkRenderPassCreateInfo &createInfo);
    };
    
    enum class StagingUsage
    {
        Read,
        Write,
        Both,
    };
    
    class Buffer final : public WrappedObject<Buffer, VkBuffer>
    {
      public:
        Buffer() = default;
        void destroy(VkDevice device);
    
        VkResult init(VkDevice device, const VkBufferCreateInfo &createInfo);
        VkResult bindMemory(VkDevice device, const DeviceMemory &deviceMemory);
        void getMemoryRequirements(VkDevice device, VkMemoryRequirements *memoryRequirementsOut);
    };
    
    class BufferView final : public WrappedObject<BufferView, VkBufferView>
    {
      public:
        BufferView() = default;
        void destroy(VkDevice device);
    
        VkResult init(VkDevice device, const VkBufferViewCreateInfo &createInfo);
    };
    
    class ShaderModule final : public WrappedObject<ShaderModule, VkShaderModule>
    {
      public:
        ShaderModule() = default;
        void destroy(VkDevice device);
    
        VkResult init(VkDevice device, const VkShaderModuleCreateInfo &createInfo);
    };
    
    class PipelineLayout final : public WrappedObject<PipelineLayout, VkPipelineLayout>
    {
      public:
        PipelineLayout() = default;
        void destroy(VkDevice device);
    
        VkResult init(VkDevice device, const VkPipelineLayoutCreateInfo &createInfo);
    };
    
    class PipelineCache final : public WrappedObject<PipelineCache, VkPipelineCache>
    {
      public:
        PipelineCache() = default;
        void destroy(VkDevice device);
    
        VkResult init(VkDevice device, const VkPipelineCacheCreateInfo &createInfo);
        VkResult getCacheData(VkDevice device, size_t *cacheSize, void *cacheData);
    };
    
    class DescriptorSetLayout final : public WrappedObject<DescriptorSetLayout, VkDescriptorSetLayout>
    {
      public:
        DescriptorSetLayout() = default;
        void destroy(VkDevice device);
    
        VkResult init(VkDevice device, const VkDescriptorSetLayoutCreateInfo &createInfo);
    };
    
    class DescriptorPool final : public WrappedObject<DescriptorPool, VkDescriptorPool>
    {
      public:
        DescriptorPool() = default;
        void destroy(VkDevice device);
    
        VkResult init(VkDevice device, const VkDescriptorPoolCreateInfo &createInfo);
    
        VkResult allocateDescriptorSets(VkDevice device,
                                        const VkDescriptorSetAllocateInfo &allocInfo,
                                        VkDescriptorSet *descriptorSetsOut);
        VkResult freeDescriptorSets(VkDevice device,
                                    uint32_t descriptorSetCount,
                                    const VkDescriptorSet *descriptorSets);
    };
    
    class Sampler final : public WrappedObject<Sampler, VkSampler>
    {
      public:
        Sampler() = default;
        void destroy(VkDevice device);
        VkResult init(VkDevice device, const VkSamplerCreateInfo &createInfo);
    };
    
    class Event final : public WrappedObject<Event, VkEvent>
    {
      public:
        Event() = default;
        void destroy(VkDevice device);
        using WrappedObject::operator=;
    
        VkResult init(VkDevice device, const VkEventCreateInfo &createInfo);
        VkResult getStatus(VkDevice device) const;
        VkResult set(VkDevice device) const;
        VkResult reset(VkDevice device) const;
    };
    
    class Fence final : public WrappedObject<Fence, VkFence>
    {
      public:
        Fence() = default;
        void destroy(VkDevice device);
        using WrappedObject::operator=;
    
        VkResult init(VkDevice device, const VkFenceCreateInfo &createInfo);
        VkResult getStatus(VkDevice device) const;
        VkResult wait(VkDevice device, uint64_t timeout) const;
    };
    
    class QueryPool final : public WrappedObject<QueryPool, VkQueryPool>
    {
      public:
        QueryPool() = default;
        void destroy(VkDevice device);
    
        VkResult init(VkDevice device, const VkQueryPoolCreateInfo &createInfo);
        VkResult getResults(VkDevice device,
                            uint32_t firstQuery,
                            uint32_t queryCount,
                            size_t dataSize,
                            void *data,
                            VkDeviceSize stride,
                            VkQueryResultFlags flags) const;
    };
    
    // CommandPool implementation.
    ANGLE_INLINE void CommandPool::destroy(VkDevice device)
    {
        if (valid())
        {
            vkDestroyCommandPool(device, mHandle, nullptr);
            mHandle = VK_NULL_HANDLE;
        }
    }
    
    ANGLE_INLINE VkResult CommandPool::reset(VkDevice device, VkCommandPoolResetFlags flags)
    {
        ASSERT(valid());
        return vkResetCommandPool(device, mHandle, flags);
    }
    
    ANGLE_INLINE VkResult CommandPool::init(VkDevice device, const VkCommandPoolCreateInfo &createInfo)
    {
        ASSERT(!valid());
        return vkCreateCommandPool(device, &createInfo, nullptr, &mHandle);
    }
    
    namespace priv
    {
    
    // CommandBuffer implementation.
    ANGLE_INLINE VkCommandBuffer CommandBuffer::releaseHandle()
    {
        VkCommandBuffer handle = mHandle;
        mHandle                = nullptr;
        return handle;
    }
    
    ANGLE_INLINE VkResult CommandBuffer::init(VkDevice device,
                                              const VkCommandBufferAllocateInfo &createInfo)
    {
        ASSERT(!valid());
        return vkAllocateCommandBuffers(device, &createInfo, &mHandle);
    }
    
    ANGLE_INLINE void CommandBuffer::blitImage(const Image &srcImage,
                                               VkImageLayout srcImageLayout,
                                               const Image &dstImage,
                                               VkImageLayout dstImageLayout,
                                               uint32_t regionCount,
                                               const VkImageBlit *regions,
                                               VkFilter filter)
    {
        ASSERT(valid() && srcImage.valid() && dstImage.valid());
        ASSERT(regionCount == 1);
        vkCmdBlitImage(mHandle, srcImage.getHandle(), srcImageLayout, dstImage.getHandle(),
                       dstImageLayout, 1, regions, filter);
    }
    
    ANGLE_INLINE VkResult CommandBuffer::begin(const VkCommandBufferBeginInfo &info)
    {
        ASSERT(valid());
        return vkBeginCommandBuffer(mHandle, &info);
    }
    
    ANGLE_INLINE VkResult CommandBuffer::end()
    {
        ASSERT(valid());
        return vkEndCommandBuffer(mHandle);
    }
    
    ANGLE_INLINE VkResult CommandBuffer::reset()
    {
        ASSERT(valid());
        return vkResetCommandBuffer(mHandle, 0);
    }
    
    ANGLE_INLINE void CommandBuffer::memoryBarrier(VkPipelineStageFlags srcStageMask,
                                                   VkPipelineStageFlags dstStageMask,
                                                   const VkMemoryBarrier *memoryBarrier)
    {
        ASSERT(valid());
        vkCmdPipelineBarrier(mHandle, srcStageMask, dstStageMask, 0, 1, memoryBarrier, 0, nullptr, 0,
                             nullptr);
    }
    
    ANGLE_INLINE void CommandBuffer::pipelineBarrier(VkPipelineStageFlags srcStageMask,
                                                     VkPipelineStageFlags dstStageMask,
                                                     VkDependencyFlags dependencyFlags,
                                                     uint32_t memoryBarrierCount,
                                                     const VkMemoryBarrier *memoryBarriers,
                                                     uint32_t bufferMemoryBarrierCount,
                                                     const VkBufferMemoryBarrier *bufferMemoryBarriers,
                                                     uint32_t imageMemoryBarrierCount,
                                                     const VkImageMemoryBarrier *imageMemoryBarriers)
    {
        ASSERT(valid());
        vkCmdPipelineBarrier(mHandle, srcStageMask, dstStageMask, dependencyFlags, memoryBarrierCount,
                             memoryBarriers, bufferMemoryBarrierCount, bufferMemoryBarriers,
                             imageMemoryBarrierCount, imageMemoryBarriers);
    }
    
    ANGLE_INLINE void CommandBuffer::executionBarrier(VkPipelineStageFlags stageMask)
    {
        ASSERT(valid());
        vkCmdPipelineBarrier(mHandle, stageMask, stageMask, 0, 0, nullptr, 0, nullptr, 0, nullptr);
    }
    
    ANGLE_INLINE void CommandBuffer::imageBarrier(VkPipelineStageFlags srcStageMask,
                                                  VkPipelineStageFlags dstStageMask,
                                                  const VkImageMemoryBarrier *imageMemoryBarrier)
    {
        ASSERT(valid());
        vkCmdPipelineBarrier(mHandle, srcStageMask, dstStageMask, 0, 0, nullptr, 0, nullptr, 1,
                             imageMemoryBarrier);
    }
    
    ANGLE_INLINE void CommandBuffer::destroy(VkDevice device)
    {
        releaseHandle();
    }
    
    ANGLE_INLINE void CommandBuffer::destroy(VkDevice device, const vk::CommandPool &commandPool)
    {
        if (valid())
        {
            ASSERT(commandPool.valid());
            vkFreeCommandBuffers(device, commandPool.getHandle(), 1, &mHandle);
            mHandle = VK_NULL_HANDLE;
        }
    }
    
    ANGLE_INLINE void CommandBuffer::copyBuffer(const Buffer &srcBuffer,
                                                const Buffer &destBuffer,
                                                uint32_t regionCount,
                                                const VkBufferCopy *regions)
    {
        ASSERT(valid() && srcBuffer.valid() && destBuffer.valid());
        vkCmdCopyBuffer(mHandle, srcBuffer.getHandle(), destBuffer.getHandle(), regionCount, regions);
    }
    
    ANGLE_INLINE void CommandBuffer::copyBufferToImage(VkBuffer srcBuffer,
                                                       const Image &dstImage,
                                                       VkImageLayout dstImageLayout,
                                                       uint32_t regionCount,
                                                       const VkBufferImageCopy *regions)
    {
        ASSERT(valid() && dstImage.valid());
        ASSERT(srcBuffer != VK_NULL_HANDLE);
        ASSERT(regionCount == 1);
        vkCmdCopyBufferToImage(mHandle, srcBuffer, dstImage.getHandle(), dstImageLayout, 1, regions);
    }
    
    ANGLE_INLINE void CommandBuffer::copyImageToBuffer(const Image &srcImage,
                                                       VkImageLayout srcImageLayout,
                                                       VkBuffer dstBuffer,
                                                       uint32_t regionCount,
                                                       const VkBufferImageCopy *regions)
    {
        ASSERT(valid() && srcImage.valid());
        ASSERT(dstBuffer != VK_NULL_HANDLE);
        ASSERT(regionCount == 1);
        vkCmdCopyImageToBuffer(mHandle, srcImage.getHandle(), srcImageLayout, dstBuffer, 1, regions);
    }
    
    ANGLE_INLINE void CommandBuffer::clearColorImage(const Image &image,
                                                     VkImageLayout imageLayout,
                                                     const VkClearColorValue &color,
                                                     uint32_t rangeCount,
                                                     const VkImageSubresourceRange *ranges)
    {
        ASSERT(valid());
        ASSERT(rangeCount == 1);
        vkCmdClearColorImage(mHandle, image.getHandle(), imageLayout, &color, 1, ranges);
    }
    
    ANGLE_INLINE void CommandBuffer::clearDepthStencilImage(
        const Image &image,
        VkImageLayout imageLayout,
        const VkClearDepthStencilValue &depthStencil,
        uint32_t rangeCount,
        const VkImageSubresourceRange *ranges)
    {
        ASSERT(valid());
        ASSERT(rangeCount == 1);
        vkCmdClearDepthStencilImage(mHandle, image.getHandle(), imageLayout, &depthStencil, 1, ranges);
    }
    
    ANGLE_INLINE void CommandBuffer::clearAttachments(uint32_t attachmentCount,
                                                      const VkClearAttachment *attachments,
                                                      uint32_t rectCount,
                                                      const VkClearRect *rects)
    {
        ASSERT(valid());
        vkCmdClearAttachments(mHandle, attachmentCount, attachments, rectCount, rects);
    }
    
    ANGLE_INLINE void CommandBuffer::copyImage(const Image &srcImage,
                                               VkImageLayout srcImageLayout,
                                               const Image &dstImage,
                                               VkImageLayout dstImageLayout,
                                               uint32_t regionCount,
                                               const VkImageCopy *regions)
    {
        ASSERT(valid() && srcImage.valid() && dstImage.valid());
        ASSERT(regionCount == 1);
        vkCmdCopyImage(mHandle, srcImage.getHandle(), srcImageLayout, dstImage.getHandle(),
                       dstImageLayout, 1, regions);
    }
    
    ANGLE_INLINE void CommandBuffer::beginRenderPass(const VkRenderPassBeginInfo &beginInfo,
                                                     VkSubpassContents subpassContents)
    {
        ASSERT(valid());
        vkCmdBeginRenderPass(mHandle, &beginInfo, subpassContents);
    }
    
    ANGLE_INLINE void CommandBuffer::endRenderPass()
    {
        ASSERT(mHandle != VK_NULL_HANDLE);
        vkCmdEndRenderPass(mHandle);
    }
    
    ANGLE_INLINE void CommandBuffer::bindIndexBuffer(const Buffer &buffer,
                                                     VkDeviceSize offset,
                                                     VkIndexType indexType)
    {
        ASSERT(valid());
        vkCmdBindIndexBuffer(mHandle, buffer.getHandle(), offset, indexType);
    }
    
    ANGLE_INLINE void CommandBuffer::bindComputeDescriptorSets(const PipelineLayout &layout,
                                                               const VkDescriptorSet *descriptorSets)
    {
        ASSERT(valid() && layout.valid());
        vkCmdBindDescriptorSets(mHandle, VK_PIPELINE_BIND_POINT_COMPUTE, layout.getHandle(), 0, 1,
                                descriptorSets, 0, nullptr);
    }
    
    ANGLE_INLINE void CommandBuffer::bindGraphicsDescriptorSets(const PipelineLayout &layout,
                                                                uint32_t firstSet,
                                                                uint32_t descriptorSetCount,
                                                                const VkDescriptorSet *descriptorSets,
                                                                uint32_t dynamicOffsetCount,
                                                                const uint32_t *dynamicOffsets)
    {
        ASSERT(valid() && layout.valid());
        vkCmdBindDescriptorSets(mHandle, VK_PIPELINE_BIND_POINT_GRAPHICS, layout.getHandle(), firstSet,
                                descriptorSetCount, descriptorSets, dynamicOffsetCount, dynamicOffsets);
    }
    
    ANGLE_INLINE void CommandBuffer::executeCommands(uint32_t commandBufferCount,
                                                     const CommandBuffer *commandBuffers)
    {
        ASSERT(valid());
        vkCmdExecuteCommands(mHandle, commandBufferCount, commandBuffers[0].ptr());
    }
    
    ANGLE_INLINE void CommandBuffer::fillBuffer(const Buffer &dstBuffer,
                                                VkDeviceSize dstOffset,
                                                VkDeviceSize size,
                                                uint32_t data)
    {
        ASSERT(valid());
        vkCmdFillBuffer(mHandle, dstBuffer.getHandle(), dstOffset, size, data);
    }
    
    ANGLE_INLINE void CommandBuffer::pushConstants(const PipelineLayout &layout,
                                                   VkShaderStageFlags flag,
                                                   uint32_t offset,
                                                   uint32_t size,
                                                   const void *data)
    {
        ASSERT(valid() && layout.valid());
        ASSERT(offset == 0);
        vkCmdPushConstants(mHandle, layout.getHandle(), flag, 0, size, data);
    }
    
    ANGLE_INLINE void CommandBuffer::setEvent(VkEvent event, VkPipelineStageFlags stageMask)
    {
        ASSERT(valid() && event != VK_NULL_HANDLE);
        vkCmdSetEvent(mHandle, event, stageMask);
    }
    
    ANGLE_INLINE void CommandBuffer::resetEvent(VkEvent event, VkPipelineStageFlags stageMask)
    {
        ASSERT(valid() && event != VK_NULL_HANDLE);
        vkCmdResetEvent(mHandle, event, stageMask);
    }
    
    ANGLE_INLINE void CommandBuffer::waitEvents(uint32_t eventCount,
                                                const VkEvent *events,
                                                VkPipelineStageFlags srcStageMask,
                                                VkPipelineStageFlags dstStageMask,
                                                uint32_t memoryBarrierCount,
                                                const VkMemoryBarrier *memoryBarriers,
                                                uint32_t bufferMemoryBarrierCount,
                                                const VkBufferMemoryBarrier *bufferMemoryBarriers,
                                                uint32_t imageMemoryBarrierCount,
                                                const VkImageMemoryBarrier *imageMemoryBarriers)
    {
        ASSERT(valid());
        vkCmdWaitEvents(mHandle, eventCount, events, srcStageMask, dstStageMask, memoryBarrierCount,
                        memoryBarriers, bufferMemoryBarrierCount, bufferMemoryBarriers,
                        imageMemoryBarrierCount, imageMemoryBarriers);
    }
    
    ANGLE_INLINE void CommandBuffer::resetQueryPool(VkQueryPool queryPool,
                                                    uint32_t firstQuery,
                                                    uint32_t queryCount)
    {
        ASSERT(valid());
        vkCmdResetQueryPool(mHandle, queryPool, firstQuery, queryCount);
    }
    
    ANGLE_INLINE void CommandBuffer::resolveImage(const Image &srcImage,
                                                  VkImageLayout srcImageLayout,
                                                  const Image &dstImage,
                                                  VkImageLayout dstImageLayout,
                                                  uint32_t regionCount,
                                                  const VkImageResolve *regions)
    {
        ASSERT(valid() && srcImage.valid() && dstImage.valid());
        vkCmdResolveImage(mHandle, srcImage.getHandle(), srcImageLayout, dstImage.getHandle(),
                          dstImageLayout, regionCount, regions);
    }
    
    ANGLE_INLINE void CommandBuffer::beginQuery(VkQueryPool queryPool,
                                                uint32_t query,
                                                VkQueryControlFlags flags)
    {
        ASSERT(valid());
        vkCmdBeginQuery(mHandle, queryPool, query, flags);
    }
    
    ANGLE_INLINE void CommandBuffer::endQuery(VkQueryPool queryPool, uint32_t query)
    {
        ASSERT(valid());
        vkCmdEndQuery(mHandle, queryPool, query);
    }
    
    ANGLE_INLINE void CommandBuffer::writeTimestamp(VkPipelineStageFlagBits pipelineStage,
                                                    VkQueryPool queryPool,
                                                    uint32_t query)
    {
        ASSERT(valid());
        vkCmdWriteTimestamp(mHandle, pipelineStage, queryPool, query);
    }
    
    ANGLE_INLINE void CommandBuffer::draw(uint32_t vertexCount,
                                          uint32_t instanceCount,
                                          uint32_t firstVertex,
                                          uint32_t firstInstance)
    {
        ASSERT(valid());
        vkCmdDraw(mHandle, vertexCount, instanceCount, firstVertex, firstInstance);
    }
    
    ANGLE_INLINE void CommandBuffer::draw(uint32_t vertexCount, uint32_t firstVertex)
    {
        ASSERT(valid());
        vkCmdDraw(mHandle, vertexCount, 1, firstVertex, 0);
    }
    
    ANGLE_INLINE void CommandBuffer::drawInstanced(uint32_t vertexCount,
                                                   uint32_t instanceCount,
                                                   uint32_t firstVertex)
    {
        ASSERT(valid());
        vkCmdDraw(mHandle, vertexCount, instanceCount, firstVertex, 0);
    }
    
    ANGLE_INLINE void CommandBuffer::drawIndexed(uint32_t indexCount,
                                                 uint32_t instanceCount,
                                                 uint32_t firstIndex,
                                                 int32_t vertexOffset,
                                                 uint32_t firstInstance)
    {
        ASSERT(valid());
        vkCmdDrawIndexed(mHandle, indexCount, instanceCount, firstIndex, vertexOffset, firstInstance);
    }
    
    ANGLE_INLINE void CommandBuffer::drawIndexed(uint32_t indexCount)
    {
        ASSERT(valid());
        vkCmdDrawIndexed(mHandle, indexCount, 1, 0, 0, 0);
    }
    
    ANGLE_INLINE void CommandBuffer::drawIndexedInstanced(uint32_t indexCount, uint32_t instanceCount)
    {
        ASSERT(valid());
        vkCmdDrawIndexed(mHandle, indexCount, instanceCount, 0, 0, 0);
    }
    
    ANGLE_INLINE void CommandBuffer::dispatch(uint32_t groupCountX,
                                              uint32_t groupCountY,
                                              uint32_t groupCountZ)
    {
        ASSERT(valid());
        vkCmdDispatch(mHandle, groupCountX, groupCountY, groupCountZ);
    }
    
    ANGLE_INLINE void CommandBuffer::bindPipeline(VkPipelineBindPoint pipelineBindPoint,
                                                  const Pipeline &pipeline)
    {
        ASSERT(valid() && pipeline.valid());
        vkCmdBindPipeline(mHandle, pipelineBindPoint, pipeline.getHandle());
    }
    
    ANGLE_INLINE void CommandBuffer::bindGraphicsPipeline(const Pipeline &pipeline)
    {
        ASSERT(valid() && pipeline.valid());
        vkCmdBindPipeline(mHandle, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline.getHandle());
    }
    
    ANGLE_INLINE void CommandBuffer::bindComputePipeline(const Pipeline &pipeline)
    {
        ASSERT(valid() && pipeline.valid());
        vkCmdBindPipeline(mHandle, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline.getHandle());
    }
    
    ANGLE_INLINE void CommandBuffer::bindVertexBuffers(uint32_t firstBinding,
                                                       uint32_t bindingCount,
                                                       const VkBuffer *buffers,
                                                       const VkDeviceSize *offsets)
    {
        ASSERT(valid());
        vkCmdBindVertexBuffers(mHandle, firstBinding, bindingCount, buffers, offsets);
    }
    
    }  // namespace priv
    
    // Image implementation.
    ANGLE_INLINE void Image::setHandle(VkImage handle)
    {
        mHandle = handle;
    }
    
    ANGLE_INLINE void Image::reset()
    {
        mHandle = VK_NULL_HANDLE;
    }
    
    ANGLE_INLINE void Image::destroy(VkDevice device)
    {
        if (valid())
        {
            vkDestroyImage(device, mHandle, nullptr);
            mHandle = VK_NULL_HANDLE;
        }
    }
    
    ANGLE_INLINE VkResult Image::init(VkDevice device, const VkImageCreateInfo &createInfo)
    {
        ASSERT(!valid());
        return vkCreateImage(device, &createInfo, nullptr, &mHandle);
    }
    
    ANGLE_INLINE void Image::getMemoryRequirements(VkDevice device,
                                                   VkMemoryRequirements *requirementsOut) const
    {
        ASSERT(valid());
        vkGetImageMemoryRequirements(device, mHandle, requirementsOut);
    }
    
    ANGLE_INLINE VkResult Image::bindMemory(VkDevice device, const vk::DeviceMemory &deviceMemory)
    {
        ASSERT(valid() && deviceMemory.valid());
        return vkBindImageMemory(device, mHandle, deviceMemory.getHandle(), 0);
    }
    
    ANGLE_INLINE void Image::getSubresourceLayout(VkDevice device,
                                                  VkImageAspectFlagBits aspectMask,
                                                  uint32_t mipLevel,
                                                  uint32_t arrayLayer,
                                                  VkSubresourceLayout *outSubresourceLayout) const
    {
        VkImageSubresource subresource = {};
        subresource.aspectMask         = aspectMask;
        subresource.mipLevel           = mipLevel;
        subresource.arrayLayer         = arrayLayer;
    
        vkGetImageSubresourceLayout(device, getHandle(), &subresource, outSubresourceLayout);
    }
    
    // ImageView implementation.
    ANGLE_INLINE void ImageView::destroy(VkDevice device)
    {
        if (valid())
        {
            vkDestroyImageView(device, mHandle, nullptr);
            mHandle = VK_NULL_HANDLE;
        }
    }
    
    ANGLE_INLINE VkResult ImageView::init(VkDevice device, const VkImageViewCreateInfo &createInfo)
    {
        return vkCreateImageView(device, &createInfo, nullptr, &mHandle);
    }
    
    // Semaphore implementation.
    ANGLE_INLINE void Semaphore::destroy(VkDevice device)
    {
        if (valid())
        {
            vkDestroySemaphore(device, mHandle, nullptr);
            mHandle = VK_NULL_HANDLE;
        }
    }
    
    ANGLE_INLINE VkResult Semaphore::init(VkDevice device)
    {
        ASSERT(!valid());
    
        VkSemaphoreCreateInfo semaphoreInfo = {};
        semaphoreInfo.sType                 = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
        semaphoreInfo.flags                 = 0;
    
        return vkCreateSemaphore(device, &semaphoreInfo, nullptr, &mHandle);
    }
    
    // Framebuffer implementation.
    ANGLE_INLINE void Framebuffer::destroy(VkDevice device)
    {
        if (valid())
        {
            vkDestroyFramebuffer(device, mHandle, nullptr);
            mHandle = VK_NULL_HANDLE;
        }
    }
    
    ANGLE_INLINE VkResult Framebuffer::init(VkDevice device, const VkFramebufferCreateInfo &createInfo)
    {
        ASSERT(!valid());
        return vkCreateFramebuffer(device, &createInfo, nullptr, &mHandle);
    }
    
    ANGLE_INLINE void Framebuffer::setHandle(VkFramebuffer handle)
    {
        mHandle = handle;
    }
    
    // DeviceMemory implementation.
    ANGLE_INLINE void DeviceMemory::destroy(VkDevice device)
    {
        if (valid())
        {
            vkFreeMemory(device, mHandle, nullptr);
            mHandle = VK_NULL_HANDLE;
        }
    }
    
    ANGLE_INLINE VkResult DeviceMemory::allocate(VkDevice device, const VkMemoryAllocateInfo &allocInfo)
    {
        ASSERT(!valid());
        return vkAllocateMemory(device, &allocInfo, nullptr, &mHandle);
    }
    
    ANGLE_INLINE VkResult DeviceMemory::map(VkDevice device,
                                            VkDeviceSize offset,
                                            VkDeviceSize size,
                                            VkMemoryMapFlags flags,
                                            uint8_t **mapPointer) const
    {
        ASSERT(valid());
        return vkMapMemory(device, mHandle, offset, size, flags, reinterpret_cast<void **>(mapPointer));
    }
    
    ANGLE_INLINE void DeviceMemory::unmap(VkDevice device) const
    {
        ASSERT(valid());
        vkUnmapMemory(device, mHandle);
    }
    
    // RenderPass implementation.
    ANGLE_INLINE void RenderPass::destroy(VkDevice device)
    {
        if (valid())
        {
            vkDestroyRenderPass(device, mHandle, nullptr);
            mHandle = VK_NULL_HANDLE;
        }
    }
    
    ANGLE_INLINE VkResult RenderPass::init(VkDevice device, const VkRenderPassCreateInfo &createInfo)
    {
        ASSERT(!valid());
        return vkCreateRenderPass(device, &createInfo, nullptr, &mHandle);
    }
    
    // Buffer implementation.
    ANGLE_INLINE void Buffer::destroy(VkDevice device)
    {
        if (valid())
        {
            vkDestroyBuffer(device, mHandle, nullptr);
            mHandle = VK_NULL_HANDLE;
        }
    }
    
    ANGLE_INLINE VkResult Buffer::init(VkDevice device, const VkBufferCreateInfo &createInfo)
    {
        ASSERT(!valid());
        return vkCreateBuffer(device, &createInfo, nullptr, &mHandle);
    }
    
    ANGLE_INLINE VkResult Buffer::bindMemory(VkDevice device, const DeviceMemory &deviceMemory)
    {
        ASSERT(valid() && deviceMemory.valid());
        return vkBindBufferMemory(device, mHandle, deviceMemory.getHandle(), 0);
    }
    
    ANGLE_INLINE void Buffer::getMemoryRequirements(VkDevice device,
                                                    VkMemoryRequirements *memoryRequirementsOut)
    {
        ASSERT(valid());
        vkGetBufferMemoryRequirements(device, mHandle, memoryRequirementsOut);
    }
    
    // BufferView implementation.
    ANGLE_INLINE void BufferView::destroy(VkDevice device)
    {
        if (valid())
        {
            vkDestroyBufferView(device, mHandle, nullptr);
            mHandle = VK_NULL_HANDLE;
        }
    }
    
    ANGLE_INLINE VkResult BufferView::init(VkDevice device, const VkBufferViewCreateInfo &createInfo)
    {
        ASSERT(!valid());
        return vkCreateBufferView(device, &createInfo, nullptr, &mHandle);
    }
    
    // ShaderModule implementation.
    ANGLE_INLINE void ShaderModule::destroy(VkDevice device)
    {
        if (mHandle != VK_NULL_HANDLE)
        {
            vkDestroyShaderModule(device, mHandle, nullptr);
            mHandle = VK_NULL_HANDLE;
        }
    }
    
    ANGLE_INLINE VkResult ShaderModule::init(VkDevice device,
                                             const VkShaderModuleCreateInfo &createInfo)
    {
        ASSERT(!valid());
        return vkCreateShaderModule(device, &createInfo, nullptr, &mHandle);
    }
    
    // PipelineLayout implementation.
    ANGLE_INLINE void PipelineLayout::destroy(VkDevice device)
    {
        if (valid())
        {
            vkDestroyPipelineLayout(device, mHandle, nullptr);
            mHandle = VK_NULL_HANDLE;
        }
    }
    
    ANGLE_INLINE VkResult PipelineLayout::init(VkDevice device,
                                               const VkPipelineLayoutCreateInfo &createInfo)
    {
        ASSERT(!valid());
        return vkCreatePipelineLayout(device, &createInfo, nullptr, &mHandle);
    }
    
    // PipelineCache implementation.
    ANGLE_INLINE void PipelineCache::destroy(VkDevice device)
    {
        if (valid())
        {
            vkDestroyPipelineCache(device, mHandle, nullptr);
            mHandle = VK_NULL_HANDLE;
        }
    }
    
    ANGLE_INLINE VkResult PipelineCache::init(VkDevice device,
                                              const VkPipelineCacheCreateInfo &createInfo)
    {
        ASSERT(!valid());
        // Note: if we are concerned with memory usage of this cache, we should give it custom
        // allocators.  Also, failure of this function is of little importance.
        return vkCreatePipelineCache(device, &createInfo, nullptr, &mHandle);
    }
    
    ANGLE_INLINE VkResult PipelineCache::getCacheData(VkDevice device,
                                                      size_t *cacheSize,
                                                      void *cacheData)
    {
        ASSERT(valid());
    
        // Note: vkGetPipelineCacheData can return VK_INCOMPLETE if cacheSize is smaller than actual
        // size. There are two usages of this function.  One is with *cacheSize == 0 to query the size
        // of the cache, and one is with an appropriate buffer to retrieve the cache contents.
        // VK_INCOMPLETE in the first case is an expected output.  In the second case, VK_INCOMPLETE is
        // also acceptable and the resulting buffer will contain valid value by spec.  Angle currently
        // ensures *cacheSize to be either 0 or of enough size, therefore VK_INCOMPLETE is not expected.
        return vkGetPipelineCacheData(device, mHandle, cacheSize, cacheData);
    }
    
    // Pipeline implementation.
    ANGLE_INLINE void Pipeline::destroy(VkDevice device)
    {
        if (valid())
        {
            vkDestroyPipeline(device, mHandle, nullptr);
            mHandle = VK_NULL_HANDLE;
        }
    }
    
    ANGLE_INLINE VkResult Pipeline::initGraphics(VkDevice device,
                                                 const VkGraphicsPipelineCreateInfo &createInfo,
                                                 const PipelineCache &pipelineCacheVk)
    {
        ASSERT(!valid());
        return vkCreateGraphicsPipelines(device, pipelineCacheVk.getHandle(), 1, &createInfo, nullptr,
                                         &mHandle);
    }
    
    ANGLE_INLINE VkResult Pipeline::initCompute(VkDevice device,
                                                const VkComputePipelineCreateInfo &createInfo,
                                                const PipelineCache &pipelineCacheVk)
    {
        ASSERT(!valid());
        return vkCreateComputePipelines(device, pipelineCacheVk.getHandle(), 1, &createInfo, nullptr,
                                        &mHandle);
    }
    
    // DescriptorSetLayout implementation.
    ANGLE_INLINE void DescriptorSetLayout::destroy(VkDevice device)
    {
        if (valid())
        {
            vkDestroyDescriptorSetLayout(device, mHandle, nullptr);
            mHandle = VK_NULL_HANDLE;
        }
    }
    
    ANGLE_INLINE VkResult DescriptorSetLayout::init(VkDevice device,
                                                    const VkDescriptorSetLayoutCreateInfo &createInfo)
    {
        ASSERT(!valid());
        return vkCreateDescriptorSetLayout(device, &createInfo, nullptr, &mHandle);
    }
    
    // DescriptorPool implementation.
    ANGLE_INLINE void DescriptorPool::destroy(VkDevice device)
    {
        if (valid())
        {
            vkDestroyDescriptorPool(device, mHandle, nullptr);
            mHandle = VK_NULL_HANDLE;
        }
    }
    
    ANGLE_INLINE VkResult DescriptorPool::init(VkDevice device,
                                               const VkDescriptorPoolCreateInfo &createInfo)
    {
        ASSERT(!valid());
        return vkCreateDescriptorPool(device, &createInfo, nullptr, &mHandle);
    }
    
    ANGLE_INLINE VkResult
    DescriptorPool::allocateDescriptorSets(VkDevice device,
                                           const VkDescriptorSetAllocateInfo &allocInfo,
                                           VkDescriptorSet *descriptorSetsOut)
    {
        ASSERT(valid());
        return vkAllocateDescriptorSets(device, &allocInfo, descriptorSetsOut);
    }
    
    ANGLE_INLINE VkResult DescriptorPool::freeDescriptorSets(VkDevice device,
                                                             uint32_t descriptorSetCount,
                                                             const VkDescriptorSet *descriptorSets)
    {
        ASSERT(valid());
        ASSERT(descriptorSetCount > 0);
        return vkFreeDescriptorSets(device, mHandle, descriptorSetCount, descriptorSets);
    }
    
    // Sampler implementation.
    ANGLE_INLINE void Sampler::destroy(VkDevice device)
    {
        if (valid())
        {
            vkDestroySampler(device, mHandle, nullptr);
            mHandle = VK_NULL_HANDLE;
        }
    }
    
    ANGLE_INLINE VkResult Sampler::init(VkDevice device, const VkSamplerCreateInfo &createInfo)
    {
        ASSERT(!valid());
        return vkCreateSampler(device, &createInfo, nullptr, &mHandle);
    }
    
    // Event implementation.
    ANGLE_INLINE void Event::destroy(VkDevice device)
    {
        if (valid())
        {
            vkDestroyEvent(device, mHandle, nullptr);
            mHandle = VK_NULL_HANDLE;
        }
    }
    
    ANGLE_INLINE VkResult Event::init(VkDevice device, const VkEventCreateInfo &createInfo)
    {
        ASSERT(!valid());
        return vkCreateEvent(device, &createInfo, nullptr, &mHandle);
    }
    
    ANGLE_INLINE VkResult Event::getStatus(VkDevice device) const
    {
        ASSERT(valid());
        return vkGetEventStatus(device, mHandle);
    }
    
    ANGLE_INLINE VkResult Event::set(VkDevice device) const
    {
        ASSERT(valid());
        return vkSetEvent(device, mHandle);
    }
    
    ANGLE_INLINE VkResult Event::reset(VkDevice device) const
    {
        ASSERT(valid());
        return vkResetEvent(device, mHandle);
    }
    
    // Fence implementation.
    ANGLE_INLINE void Fence::destroy(VkDevice device)
    {
        if (valid())
        {
            vkDestroyFence(device, mHandle, nullptr);
            mHandle = VK_NULL_HANDLE;
        }
    }
    
    ANGLE_INLINE VkResult Fence::init(VkDevice device, const VkFenceCreateInfo &createInfo)
    {
        ASSERT(!valid());
        return vkCreateFence(device, &createInfo, nullptr, &mHandle);
    }
    
    ANGLE_INLINE VkResult Fence::getStatus(VkDevice device) const
    {
        ASSERT(valid());
        return vkGetFenceStatus(device, mHandle);
    }
    
    ANGLE_INLINE VkResult Fence::wait(VkDevice device, uint64_t timeout) const
    {
        ASSERT(valid());
        return vkWaitForFences(device, 1, &mHandle, true, timeout);
    }
    
    // QueryPool implementation.
    ANGLE_INLINE void QueryPool::destroy(VkDevice device)
    {
        if (valid())
        {
            vkDestroyQueryPool(device, mHandle, nullptr);
            mHandle = VK_NULL_HANDLE;
        }
    }
    
    ANGLE_INLINE VkResult QueryPool::init(VkDevice device, const VkQueryPoolCreateInfo &createInfo)
    {
        ASSERT(!valid());
        return vkCreateQueryPool(device, &createInfo, nullptr, &mHandle);
    }
    
    ANGLE_INLINE VkResult QueryPool::getResults(VkDevice device,
                                                uint32_t firstQuery,
                                                uint32_t queryCount,
                                                size_t dataSize,
                                                void *data,
                                                VkDeviceSize stride,
                                                VkQueryResultFlags flags) const
    {
        ASSERT(valid());
        return vkGetQueryPoolResults(device, mHandle, firstQuery, queryCount, dataSize, data, stride,
                                     flags);
    }
    }  // namespace vk
    }  // namespace rx
    
    #endif  // LIBANGLE_RENDERER_VULKAN_VK_WRAPPER_H_