Vulkan:Integrate SecondaryCommandBuffers

Integrate the custom SecondaryCommandBuffer type into the CommandGraph
nodes by adding new ANGLE_USE_CUSTOM_VULKAN_CMD_BUFFERS define that can
be set in the BUILD gn args with angle_enable_custom_vulkan_cmd_buffers
set to "true."
Initially the custom cmd buffers are disabled by default.

This adds some support functions to SecondaryCommandBuffer to make the
integration easier by matching the wrapped cmd buffer interface:
initialize(), end(), valid().

Bug: angleproject:3136
Change-Id: Ib910554583192550757bb8ce89914e3ea8737988
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/1526556
Commit-Queue: Tobin Ehlis <tobine@google.com>
Reviewed-by: Jamie Madill <jmadill@chromium.org>
diff --git a/src/common/angleutils.h b/src/common/angleutils.h
index 7e7460a..09adb58 100644
--- a/src/common/angleutils.h
+++ b/src/common/angleutils.h
@@ -324,4 +324,10 @@
 #    define ANGLE_NO_DISCARD
 #endif  // __has_cpp_attribute(nodiscard)
 
+#if __has_cpp_attribute(maybe_unused)
+#    define ANGLE_MAYBE_UNUSED [[maybe_unused]]
+#else
+#    define ANGLE_MAYBE_UNUSED
+#endif  // __has_cpp_attribute(maybe_unused)
+
 #endif  // COMMON_ANGLEUTILS_H_
diff --git a/src/libANGLE/renderer/vulkan/BufferVk.cpp b/src/libANGLE/renderer/vulkan/BufferVk.cpp
index 3d0389e..cbd54b0 100644
--- a/src/libANGLE/renderer/vulkan/BufferVk.cpp
+++ b/src/libANGLE/renderer/vulkan/BufferVk.cpp
@@ -246,7 +246,7 @@
                                      uint32_t copyCount,
                                      const VkBufferCopy *copies)
 {
-    vk::CommandBuffer *commandBuffer;
+    CommandBufferT *commandBuffer;
     ANGLE_TRY(mBuffer.recordCommands(contextVk, &commandBuffer));
     commandBuffer->copyBuffer(mBuffer.getBuffer(), destBuffer->getBuffer(), copyCount, copies);
 
diff --git a/src/libANGLE/renderer/vulkan/CommandGraph.cpp b/src/libANGLE/renderer/vulkan/CommandGraph.cpp
index cd24f0e..4fb85c6 100644
--- a/src/libANGLE/renderer/vulkan/CommandGraph.cpp
+++ b/src/libANGLE/renderer/vulkan/CommandGraph.cpp
@@ -25,14 +25,28 @@
 {
 namespace
 {
+ANGLE_MAYBE_UNUSED
 angle::Result InitAndBeginCommandBuffer(vk::Context *context,
                                         const CommandPool &commandPool,
                                         const VkCommandBufferInheritanceInfo &inheritanceInfo,
                                         VkCommandBufferUsageFlags flags,
+                                        angle::PoolAllocator *poolAllocator,
+                                        SecondaryCommandBuffer *commandBuffer)
+{
+    ASSERT(!commandBuffer->valid());
+    commandBuffer->initialize(poolAllocator);
+    return angle::Result::Continue;
+}
+
+ANGLE_MAYBE_UNUSED
+angle::Result InitAndBeginCommandBuffer(vk::Context *context,
+                                        const CommandPool &commandPool,
+                                        const VkCommandBufferInheritanceInfo &inheritanceInfo,
+                                        VkCommandBufferUsageFlags flags,
+                                        angle::PoolAllocator *poolAllocator,
                                         CommandBuffer *commandBuffer)
 {
     ASSERT(!commandBuffer->valid());
-
     VkCommandBufferAllocateInfo createInfo = {};
     createInfo.sType                       = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
     createInfo.commandPool                 = commandPool.getHandle();
@@ -124,6 +138,26 @@
     kLabelColors[colorIndex].writeData(label->color);
 }
 
+#if ANGLE_USE_CUSTOM_VULKAN_CMD_BUFFERS
+static constexpr VkSubpassContents kRenderPassContents = VK_SUBPASS_CONTENTS_INLINE;
+#else
+static constexpr VkSubpassContents kRenderPassContents =
+    VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS;
+#endif
+
+// Helpers to unify executeCommands call based on underlying cmd buffer type
+ANGLE_MAYBE_UNUSED
+void ExecuteCommands(CommandBuffer *primCmdBuffer, SecondaryCommandBuffer *secCmdBuffer)
+{
+    secCmdBuffer->executeCommands(primCmdBuffer->getHandle());
+}
+
+ANGLE_MAYBE_UNUSED
+void ExecuteCommands(CommandBuffer *primCmdBuffer, CommandBuffer *secCmdBuffer)
+{
+    primCmdBuffer->executeCommands(1, secCmdBuffer);
+}
+
 }  // anonymous namespace
 
 // CommandGraphResource implementation.
@@ -139,7 +173,7 @@
 }
 
 angle::Result CommandGraphResource::recordCommands(Context *context,
-                                                   CommandBuffer **commandBufferOut)
+                                                   CommandBufferT **commandBufferOut)
 {
     updateQueueSerial(context->getRenderer()->getCurrentQueueSerial());
 
@@ -150,7 +184,7 @@
             context, context->getRenderer()->getCommandPool(), commandBufferOut);
     }
 
-    CommandBuffer *outsideRenderPassCommands = mCurrentWritingNode->getOutsideRenderPassCommands();
+    CommandBufferT *outsideRenderPassCommands = mCurrentWritingNode->getOutsideRenderPassCommands();
     if (!outsideRenderPassCommands->valid())
     {
         ANGLE_TRY(mCurrentWritingNode->beginOutsideRenderPassRecording(
@@ -175,7 +209,7 @@
                                                     const gl::Rectangle &renderArea,
                                                     const RenderPassDesc &renderPassDesc,
                                                     const std::vector<VkClearValue> &clearValues,
-                                                    CommandBuffer **commandBufferOut)
+                                                    CommandBufferT **commandBufferOut)
 {
     // If a barrier has been inserted in the meantime, stop the command buffer.
     if (!hasChildlessWritingNode())
@@ -251,9 +285,11 @@
 }
 
 // CommandGraphNode implementation.
-CommandGraphNode::CommandGraphNode(CommandGraphNodeFunction function)
+CommandGraphNode::CommandGraphNode(CommandGraphNodeFunction function,
+                                   angle::PoolAllocator *poolAllocator)
     : mRenderPassClearValues{},
       mFunction(function),
+      mPoolAllocator(poolAllocator),
       mQueryPool(VK_NULL_HANDLE),
       mQueryIndex(0),
       mFenceSyncEvent(VK_NULL_HANDLE),
@@ -273,15 +309,9 @@
     mInsideRenderPassCommands.releaseHandle();
 }
 
-CommandBuffer *CommandGraphNode::getOutsideRenderPassCommands()
-{
-    ASSERT(!mHasChildren);
-    return &mOutsideRenderPassCommands;
-}
-
 angle::Result CommandGraphNode::beginOutsideRenderPassRecording(Context *context,
                                                                 const CommandPool &commandPool,
-                                                                CommandBuffer **commandsOut)
+                                                                CommandBufferT **commandsOut)
 {
     ASSERT(!mHasChildren);
 
@@ -295,7 +325,7 @@
     inheritanceInfo.queryFlags         = 0;
     inheritanceInfo.pipelineStatistics = 0;
 
-    ANGLE_TRY(InitAndBeginCommandBuffer(context, commandPool, inheritanceInfo, 0,
+    ANGLE_TRY(InitAndBeginCommandBuffer(context, commandPool, inheritanceInfo, 0, mPoolAllocator,
                                         &mOutsideRenderPassCommands));
 
     *commandsOut = &mOutsideRenderPassCommands;
@@ -303,7 +333,7 @@
 }
 
 angle::Result CommandGraphNode::beginInsideRenderPassRecording(Context *context,
-                                                               CommandBuffer **commandsOut)
+                                                               CommandBufferT **commandsOut)
 {
     ASSERT(!mHasChildren);
 
@@ -323,9 +353,10 @@
     inheritanceInfo.queryFlags         = 0;
     inheritanceInfo.pipelineStatistics = 0;
 
-    ANGLE_TRY(InitAndBeginCommandBuffer(
-        context, context->getRenderer()->getCommandPool(), inheritanceInfo,
-        VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT, &mInsideRenderPassCommands));
+    ANGLE_TRY(InitAndBeginCommandBuffer(context, context->getRenderer()->getCommandPool(),
+                                        inheritanceInfo,
+                                        VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT,
+                                        mPoolAllocator, &mInsideRenderPassCommands));
 
     *commandsOut = &mInsideRenderPassCommands;
     return angle::Result::Continue;
@@ -462,7 +493,7 @@
             if (mOutsideRenderPassCommands.valid())
             {
                 ANGLE_VK_TRY(context, mOutsideRenderPassCommands.end());
-                primaryCommandBuffer->executeCommands(1, &mOutsideRenderPassCommands);
+                ExecuteCommands(primaryCommandBuffer, &mOutsideRenderPassCommands);
             }
 
             if (mInsideRenderPassCommands.valid())
@@ -488,9 +519,8 @@
                 beginInfo.clearValueCount = mRenderPassDesc.attachmentCount();
                 beginInfo.pClearValues    = mRenderPassClearValues.data();
 
-                primaryCommandBuffer->beginRenderPass(
-                    beginInfo, VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS);
-                primaryCommandBuffer->executeCommands(1, &mInsideRenderPassCommands);
+                primaryCommandBuffer->beginRenderPass(beginInfo, kRenderPassContents);
+                ExecuteCommands(primaryCommandBuffer, &mInsideRenderPassCommands);
                 primaryCommandBuffer->endRenderPass();
             }
             break;
@@ -600,8 +630,10 @@
 }
 
 // CommandGraph implementation.
-CommandGraph::CommandGraph(bool enableGraphDiagnostics)
-    : mEnableGraphDiagnostics(enableGraphDiagnostics), mLastBarrierIndex(kInvalidNodeIndex)
+CommandGraph::CommandGraph(bool enableGraphDiagnostics, angle::PoolAllocator *poolAllocator)
+    : mEnableGraphDiagnostics(enableGraphDiagnostics),
+      mPoolAllocator(poolAllocator),
+      mLastBarrierIndex(kInvalidNodeIndex)
 {}
 
 CommandGraph::~CommandGraph()
@@ -612,7 +644,7 @@
 CommandGraphNode *CommandGraph::allocateNode(CommandGraphNodeFunction function)
 {
     // TODO(jmadill): Use a pool allocator for the CPU node allocations.
-    CommandGraphNode *newCommands = new CommandGraphNode(function);
+    CommandGraphNode *newCommands = new CommandGraphNode(function, mPoolAllocator);
     mNodes.emplace_back(newCommands);
     return newCommands;
 }
diff --git a/src/libANGLE/renderer/vulkan/CommandGraph.h b/src/libANGLE/renderer/vulkan/CommandGraph.h
index 2bb90ff..4548789 100644
--- a/src/libANGLE/renderer/vulkan/CommandGraph.h
+++ b/src/libANGLE/renderer/vulkan/CommandGraph.h
@@ -10,8 +10,15 @@
 #ifndef LIBANGLE_RENDERER_VULKAN_COMMAND_GRAPH_H_
 #define LIBANGLE_RENDERER_VULKAN_COMMAND_GRAPH_H_
 
+#include "libANGLE/renderer/vulkan/SecondaryCommandBuffer.h"
 #include "libANGLE/renderer/vulkan/vk_cache_utils.h"
 
+#if ANGLE_USE_CUSTOM_VULKAN_CMD_BUFFERS
+using CommandBufferT = rx::vk::SecondaryCommandBuffer;
+#else
+using CommandBufferT = rx::vk::CommandBuffer;
+#endif
+
 namespace rx
 {
 
@@ -61,20 +68,24 @@
     ANGLE_INLINE void onCommandBufferFinished() { mCommandBuffer = nullptr; }
 
   protected:
-    vk::CommandBuffer *mCommandBuffer = nullptr;
+    CommandBufferT *mCommandBuffer = nullptr;
 };
 
 // Only used internally in the command graph. Kept in the header for better inlining performance.
 class CommandGraphNode final : angle::NonCopyable
 {
   public:
-    CommandGraphNode(CommandGraphNodeFunction function);
+    CommandGraphNode(CommandGraphNodeFunction function, angle::PoolAllocator *poolAllocator);
     ~CommandGraphNode();
 
     // Immutable queries for when we're walking the commands tree.
-    CommandBuffer *getOutsideRenderPassCommands();
+    CommandBufferT *getOutsideRenderPassCommands()
+    {
+        ASSERT(!mHasChildren);
+        return &mOutsideRenderPassCommands;
+    }
 
-    CommandBuffer *getInsideRenderPassCommands()
+    CommandBufferT *getInsideRenderPassCommands()
     {
         ASSERT(!mHasChildren);
         return &mInsideRenderPassCommands;
@@ -83,10 +94,10 @@
     // For outside the render pass (copies, transitions, etc).
     angle::Result beginOutsideRenderPassRecording(Context *context,
                                                   const CommandPool &commandPool,
-                                                  CommandBuffer **commandsOut);
+                                                  CommandBufferT **commandsOut);
 
     // For rendering commands (draws).
-    angle::Result beginInsideRenderPassRecording(Context *context, CommandBuffer **commandsOut);
+    angle::Result beginInsideRenderPassRecording(Context *context, CommandBufferT **commandsOut);
 
     // storeRenderPassInfo and append*RenderTarget store info relevant to the RenderPass.
     void storeRenderPassInfo(const Framebuffer &framebuffer,
@@ -173,11 +184,11 @@
     gl::AttachmentArray<VkClearValue> mRenderPassClearValues;
 
     CommandGraphNodeFunction mFunction;
-
+    angle::PoolAllocator *mPoolAllocator;
     // Keep separate buffers for commands inside and outside a RenderPass.
     // TODO(jmadill): We might not need inside and outside RenderPass commands separate.
-    CommandBuffer mOutsideRenderPassCommands;
-    CommandBuffer mInsideRenderPassCommands;
+    CommandBufferT mOutsideRenderPassCommands;
+    CommandBufferT mInsideRenderPassCommands;
 
     // Special-function additional data:
     // Queries:
@@ -251,7 +262,7 @@
     // Allocates a write node via getNewWriteNode and returns a started command buffer.
     // The started command buffer will render outside of a RenderPass.
     // Will append to an existing command buffer/graph node if possible.
-    angle::Result recordCommands(Context *context, CommandBuffer **commandBufferOut);
+    angle::Result recordCommands(Context *context, CommandBufferT **commandBufferOut);
 
     // Begins a command buffer on the current graph node for in-RenderPass rendering.
     // Called from FramebufferVk::startNewRenderPass and UtilsVk functions.
@@ -260,12 +271,12 @@
                                   const gl::Rectangle &renderArea,
                                   const RenderPassDesc &renderPassDesc,
                                   const std::vector<VkClearValue> &clearValues,
-                                  CommandBuffer **commandBufferOut);
+                                  CommandBufferT **commandBufferOut);
 
     // Checks if we're in a RenderPass, returning true if so. Updates serial internally.
     // Returns the started command buffer in commandBufferOut.
     ANGLE_INLINE bool appendToStartedRenderPass(Serial currentQueueSerial,
-                                                CommandBuffer **commandBufferOut)
+                                                CommandBufferT **commandBufferOut)
     {
         updateQueueSerial(currentQueueSerial);
         if (hasStartedRenderPass())
@@ -340,13 +351,13 @@
 // ANGLE's CommandGraph (and CommandGraphNode) attempt to solve these problems using deferred
 // command submission. We also sometimes call this command re-ordering. A brief summary:
 //
-// During GL command processing, we record Vulkan commands into secondary command buffers, which
+// During GL command processing, we record Vulkan commands into SecondaryCommandBuffers, which
 // are stored in CommandGraphNodes, and these nodes are chained together via dependencies to
-// for a directed acyclic CommandGraph. When we need to submit the CommandGraph, say during a
+// form a directed acyclic CommandGraph. When we need to submit the CommandGraph, say during a
 // SwapBuffers or ReadPixels call, we begin a primary Vulkan CommandBuffer, and walk the
-// CommandGraph, starting at the most senior nodes, recording secondary CommandBuffers inside
+// CommandGraph, starting at the most senior nodes, recording SecondaryCommandBuffers inside
 // and outside RenderPasses as necessary, filled with the right load/store operations. Once
-// the primary CommandBuffer has recorded all of the secondary CommandBuffers from all the open
+// the primary CommandBuffer has recorded all of the SecondaryCommandBuffers from all the open
 // CommandGraphNodes, we submit the primary CommandBuffer to the VkQueue on the device.
 //
 // The Command Graph consists of an array of open Command Graph Nodes. It supports allocating new
@@ -355,7 +366,7 @@
 class CommandGraph final : angle::NonCopyable
 {
   public:
-    explicit CommandGraph(bool enableGraphDiagnostics);
+    explicit CommandGraph(bool enableGraphDiagnostics, angle::PoolAllocator *poolAllocator);
     ~CommandGraph();
 
     // Allocates a new CommandGraphNode and adds it to the list of current open nodes. No ordering
@@ -397,6 +408,7 @@
 
     std::vector<CommandGraphNode *> mNodes;
     bool mEnableGraphDiagnostics;
+    angle::PoolAllocator *mPoolAllocator;
 
     // A set of nodes (eventually) exist that act as barriers to guarantee submission order.  For
     // example, a glMemoryBarrier() calls would lead to such a barrier or beginning and ending a
diff --git a/src/libANGLE/renderer/vulkan/ContextVk.cpp b/src/libANGLE/renderer/vulkan/ContextVk.cpp
index 4c16aac..035d577 100644
--- a/src/libANGLE/renderer/vulkan/ContextVk.cpp
+++ b/src/libANGLE/renderer/vulkan/ContextVk.cpp
@@ -206,7 +206,7 @@
                                    gl::DrawElementsType indexTypeOrNone,
                                    const void *indices,
                                    DirtyBits dirtyBitMask,
-                                   vk::CommandBuffer **commandBufferOut)
+                                   CommandBufferT **commandBufferOut)
 {
     // Set any dirty bits that depend on draw call parameters or other objects.
     if (mode != mCurrentDrawMode)
@@ -273,7 +273,7 @@
                                           GLsizei instanceCount,
                                           gl::DrawElementsType indexType,
                                           const void *indices,
-                                          vk::CommandBuffer **commandBufferOut)
+                                          CommandBufferT **commandBufferOut)
 {
     if (indexType != mCurrentDrawElementsType)
     {
@@ -312,7 +312,7 @@
                                            GLsizei vertexOrIndexCount,
                                            gl::DrawElementsType indexTypeOrInvalid,
                                            const void *indices,
-                                           vk::CommandBuffer **commandBufferOut)
+                                           CommandBufferT **commandBufferOut)
 {
     ANGLE_TRY(mVertexArray->handleLineLoop(this, firstVertex, vertexOrIndexCount,
                                            indexTypeOrInvalid, indices));
@@ -325,7 +325,7 @@
 }
 
 angle::Result ContextVk::handleDirtyDefaultAttribs(const gl::Context *context,
-                                                   vk::CommandBuffer *commandBuffer)
+                                                   CommandBufferT *commandBuffer)
 {
     ASSERT(mDirtyDefaultAttribsMask.any());
 
@@ -339,7 +339,7 @@
 }
 
 angle::Result ContextVk::handleDirtyPipeline(const gl::Context *context,
-                                             vk::CommandBuffer *commandBuffer)
+                                             CommandBufferT *commandBuffer)
 {
     if (!mCurrentPipeline)
     {
@@ -379,7 +379,7 @@
 }
 
 angle::Result ContextVk::handleDirtyTextures(const gl::Context *context,
-                                             vk::CommandBuffer *commandBuffer)
+                                             CommandBufferT *commandBuffer)
 {
     ANGLE_TRY(updateActiveTextures(context));
 
@@ -391,7 +391,7 @@
 }
 
 angle::Result ContextVk::handleDirtyVertexBuffers(const gl::Context *context,
-                                                  vk::CommandBuffer *commandBuffer)
+                                                  CommandBufferT *commandBuffer)
 {
     uint32_t maxAttrib = mProgram->getState().getMaxActiveAttribLocation();
     const gl::AttribArray<VkBuffer> &bufferHandles = mVertexArray->getCurrentArrayBufferHandles();
@@ -417,12 +417,12 @@
 }
 
 angle::Result ContextVk::handleDirtyIndexBuffer(const gl::Context *context,
-                                                vk::CommandBuffer *commandBuffer)
+                                                CommandBufferT *commandBuffer)
 {
     vk::BufferHelper *elementArrayBuffer = mVertexArray->getCurrentElementArrayBuffer();
     ASSERT(elementArrayBuffer != nullptr);
 
-    commandBuffer->bindIndexBuffer(elementArrayBuffer->getBuffer().getHandle(),
+    commandBuffer->bindIndexBuffer(elementArrayBuffer->getBuffer(),
                                    mVertexArray->getCurrentElementArrayBufferOffset(),
                                    gl_vk::kIndexTypeMap[mCurrentDrawElementsType]);
 
@@ -433,7 +433,7 @@
 }
 
 angle::Result ContextVk::handleDirtyDescriptorSets(const gl::Context *context,
-                                                   vk::CommandBuffer *commandBuffer)
+                                                   CommandBufferT *commandBuffer)
 {
     ANGLE_TRY(mProgram->updateDescriptorSets(this, commandBuffer));
 
@@ -449,7 +449,7 @@
                                     GLint first,
                                     GLsizei count)
 {
-    vk::CommandBuffer *commandBuffer = nullptr;
+    CommandBufferT *commandBuffer    = nullptr;
     uint32_t clampedVertexCount      = gl::GetClampedVertexCount<uint32_t>(count);
 
     if (mode == gl::PrimitiveMode::LineLoop)
@@ -481,7 +481,7 @@
         return angle::Result::Stop;
     }
 
-    vk::CommandBuffer *commandBuffer = nullptr;
+    CommandBufferT *commandBuffer = nullptr;
     ANGLE_TRY(setupDraw(context, mode, first, count, instances, gl::DrawElementsType::InvalidEnum,
                         nullptr, mNonIndexedDirtyBitsMask, &commandBuffer));
     commandBuffer->draw(gl::GetClampedVertexCount<uint32_t>(count), instances, first, 0);
@@ -494,7 +494,7 @@
                                       gl::DrawElementsType type,
                                       const void *indices)
 {
-    vk::CommandBuffer *commandBuffer = nullptr;
+    CommandBufferT *commandBuffer = nullptr;
     if (mode == gl::PrimitiveMode::LineLoop)
     {
         ANGLE_TRY(setupLineLoopDraw(context, mode, 0, count, type, indices, &commandBuffer));
@@ -523,7 +523,7 @@
         return angle::Result::Stop;
     }
 
-    vk::CommandBuffer *commandBuffer = nullptr;
+    CommandBufferT *commandBuffer = nullptr;
     ANGLE_TRY(setupIndexedDraw(context, mode, count, instances, type, indices, &commandBuffer));
     commandBuffer->drawIndexed(count, instances, 0, 0, 0);
     return angle::Result::Continue;
@@ -1157,7 +1157,7 @@
 }
 
 angle::Result ContextVk::handleDirtyDriverUniforms(const gl::Context *context,
-                                                   vk::CommandBuffer *commandBuffer)
+                                                   CommandBufferT *commandBuffer)
 {
     // Release any previously retained buffers.
     mDriverUniformsBuffer.releaseRetainedBuffers(mRenderer);
diff --git a/src/libANGLE/renderer/vulkan/ContextVk.h b/src/libANGLE/renderer/vulkan/ContextVk.h
index 09d651f..0262c18 100644
--- a/src/libANGLE/renderer/vulkan/ContextVk.h
+++ b/src/libANGLE/renderer/vulkan/ContextVk.h
@@ -167,6 +167,8 @@
 
     ANGLE_INLINE void invalidateVertexAndIndexBuffers()
     {
+        // TODO: Make the pipeline invalidate more fine-grained. Only need to dirty here if PSO
+        //  VtxInput state (stride, fmt, inputRate...) has changed. http://anglebug.com/3256
         invalidateCurrentPipeline();
         mDirtyBits.set(DIRTY_BIT_VERTEX_BUFFERS);
         mDirtyBits.set(DIRTY_BIT_INDEX_BUFFER);
@@ -224,7 +226,7 @@
     using DirtyBits = angle::BitSet<DIRTY_BIT_MAX>;
 
     using DirtyBitHandler = angle::Result (ContextVk::*)(const gl::Context *,
-                                                         vk::CommandBuffer *commandBuffer);
+                                                         CommandBufferT *commandBuffer);
 
     std::array<DirtyBitHandler, DIRTY_BIT_MAX> mDirtyBitHandlers;
 
@@ -236,21 +238,21 @@
                             gl::DrawElementsType indexTypeOrInvalid,
                             const void *indices,
                             DirtyBits dirtyBitMask,
-                            vk::CommandBuffer **commandBufferOut);
+                            CommandBufferT **commandBufferOut);
     angle::Result setupIndexedDraw(const gl::Context *context,
                                    gl::PrimitiveMode mode,
                                    GLsizei indexCount,
                                    GLsizei instanceCount,
                                    gl::DrawElementsType indexType,
                                    const void *indices,
-                                   vk::CommandBuffer **commandBufferOut);
+                                   CommandBufferT **commandBufferOut);
     angle::Result setupLineLoopDraw(const gl::Context *context,
                                     gl::PrimitiveMode mode,
                                     GLint firstVertex,
                                     GLsizei vertexOrIndexCount,
                                     gl::DrawElementsType indexTypeOrInvalid,
                                     const void *indices,
-                                    vk::CommandBuffer **commandBufferOut);
+                                    CommandBufferT **commandBufferOut);
 
     void updateViewport(FramebufferVk *framebufferVk,
                         const gl::Rectangle &viewport,
@@ -271,17 +273,16 @@
     void invalidateDriverUniforms();
 
     angle::Result handleDirtyDefaultAttribs(const gl::Context *context,
-                                            vk::CommandBuffer *commandBuffer);
-    angle::Result handleDirtyPipeline(const gl::Context *context, vk::CommandBuffer *commandBuffer);
-    angle::Result handleDirtyTextures(const gl::Context *context, vk::CommandBuffer *commandBuffer);
+                                            CommandBufferT *commandBuffer);
+    angle::Result handleDirtyPipeline(const gl::Context *context, CommandBufferT *commandBuffer);
+    angle::Result handleDirtyTextures(const gl::Context *context, CommandBufferT *commandBuffer);
     angle::Result handleDirtyVertexBuffers(const gl::Context *context,
-                                           vk::CommandBuffer *commandBuffer);
-    angle::Result handleDirtyIndexBuffer(const gl::Context *context,
-                                         vk::CommandBuffer *commandBuffer);
+                                           CommandBufferT *commandBuffer);
+    angle::Result handleDirtyIndexBuffer(const gl::Context *context, CommandBufferT *commandBuffer);
     angle::Result handleDirtyDriverUniforms(const gl::Context *context,
-                                            vk::CommandBuffer *commandBuffer);
+                                            CommandBufferT *commandBuffer);
     angle::Result handleDirtyDescriptorSets(const gl::Context *context,
-                                            vk::CommandBuffer *commandBuffer);
+                                            CommandBufferT *commandBuffer);
 
     vk::PipelineHelper *mCurrentPipeline;
     gl::PrimitiveMode mCurrentDrawMode;
diff --git a/src/libANGLE/renderer/vulkan/FramebufferVk.cpp b/src/libANGLE/renderer/vulkan/FramebufferVk.cpp
index b0af474..ef371a9 100644
--- a/src/libANGLE/renderer/vulkan/FramebufferVk.cpp
+++ b/src/libANGLE/renderer/vulkan/FramebufferVk.cpp
@@ -166,7 +166,7 @@
     ContextVk *contextVk = vk::GetImpl(context);
 
     // This command buffer is only started once.
-    vk::CommandBuffer *commandBuffer = nullptr;
+    CommandBufferT *commandBuffer = nullptr;
 
     const gl::FramebufferAttachment *depthAttachment = mState.getDepthAttachment();
     bool clearDepth = (depthAttachment && (mask & GL_DEPTH_BUFFER_BIT) != 0);
@@ -424,7 +424,7 @@
     VkImageAspectFlags aspectMask =
         vk::GetDepthStencilAspectFlagsForCopy(blitDepthBuffer, blitStencilBuffer);
 
-    vk::CommandBuffer *commandBuffer;
+    CommandBufferT *commandBuffer;
     ANGLE_TRY(mFramebuffer.recordCommands(contextVk, &commandBuffer));
 
     vk::ImageHelper *writeImage = drawRenderTarget->getImageForWrite(&mFramebuffer);
@@ -509,7 +509,7 @@
 
     // Reinitialize the commandBuffer after a read pixels because it calls
     // renderer->finish which makes command buffers obsolete.
-    vk::CommandBuffer *commandBuffer;
+    CommandBufferT *commandBuffer;
     ANGLE_TRY(mFramebuffer.recordCommands(contextVk, &commandBuffer));
 
     // We read the bytes of the image in a buffer, now we have to copy them into the
@@ -669,7 +669,7 @@
 
     vk::ImageHelper *dstImage = drawRenderTarget->getImageForWrite(&mFramebuffer);
 
-    vk::CommandBuffer *commandBuffer;
+    CommandBufferT *commandBuffer;
     ANGLE_TRY(mFramebuffer.recordCommands(contextVk, &commandBuffer));
 
     const vk::Format &readImageFormat = readRenderTarget->getImageFormat();
@@ -903,7 +903,7 @@
 
     // This command can only happen inside a render pass, so obtain one if its already happening
     // or create a new one if not.
-    vk::CommandBuffer *commandBuffer = nullptr;
+    CommandBufferT *commandBuffer    = nullptr;
     vk::RecordingMode mode           = vk::RecordingMode::Start;
     ANGLE_TRY(getCommandBufferForDraw(contextVk, &commandBuffer, &mode));
 
@@ -1032,7 +1032,7 @@
 }
 
 angle::Result FramebufferVk::getCommandBufferForDraw(ContextVk *contextVk,
-                                                     vk::CommandBuffer **commandBufferOut,
+                                                     CommandBufferT **commandBufferOut,
                                                      vk::RecordingMode *modeOut)
 {
     RendererVk *renderer = contextVk->getRenderer();
@@ -1048,7 +1048,7 @@
 }
 
 angle::Result FramebufferVk::startNewRenderPass(ContextVk *contextVk,
-                                                vk::CommandBuffer **commandBufferOut)
+                                                CommandBufferT **commandBufferOut)
 {
     vk::Framebuffer *framebuffer = nullptr;
     ANGLE_TRY(getFramebuffer(contextVk, &framebuffer));
@@ -1056,7 +1056,7 @@
     // TODO(jmadill): Proper clear value implementation. http://anglebug.com/2361
     std::vector<VkClearValue> attachmentClearValues;
 
-    vk::CommandBuffer *writeCommands = nullptr;
+    CommandBufferT *writeCommands = nullptr;
     ANGLE_TRY(mFramebuffer.recordCommands(contextVk, &writeCommands));
 
     vk::RenderPassDesc renderPassDesc;
@@ -1112,7 +1112,7 @@
 
     ANGLE_TRY(renderTarget->ensureImageInitialized(contextVk));
 
-    vk::CommandBuffer *commandBuffer = nullptr;
+    CommandBufferT *commandBuffer = nullptr;
     ANGLE_TRY(mFramebuffer.recordCommands(contextVk, &commandBuffer));
 
     // Note that although we're reading from the image, we need to update the layout below.
diff --git a/src/libANGLE/renderer/vulkan/FramebufferVk.h b/src/libANGLE/renderer/vulkan/FramebufferVk.h
index d159c73..a12d5ab 100644
--- a/src/libANGLE/renderer/vulkan/FramebufferVk.h
+++ b/src/libANGLE/renderer/vulkan/FramebufferVk.h
@@ -106,14 +106,14 @@
     RenderTargetVk *getColorReadRenderTarget() const;
 
     // This will clear the current write operation if it is complete.
-    bool appendToStartedRenderPass(Serial currentQueueSerial, vk::CommandBuffer **commandBufferOut)
+    bool appendToStartedRenderPass(Serial currentQueueSerial, CommandBufferT **commandBufferOut)
     {
         return mFramebuffer.appendToStartedRenderPass(currentQueueSerial, commandBufferOut);
     }
 
     vk::FramebufferHelper *getFramebuffer() { return &mFramebuffer; }
 
-    angle::Result startNewRenderPass(ContextVk *context, vk::CommandBuffer **commandBufferOut);
+    angle::Result startNewRenderPass(ContextVk *context, CommandBufferT **commandBufferOut);
 
     RenderTargetVk *getFirstRenderTarget() const;
     GLint getSamples() const;
@@ -127,7 +127,7 @@
 
     // Helper for appendToStarted/else startNewRenderPass.
     angle::Result getCommandBufferForDraw(ContextVk *contextVk,
-                                          vk::CommandBuffer **commandBufferOut,
+                                          CommandBufferT **commandBufferOut,
                                           vk::RecordingMode *modeOut);
 
     // The 'in' rectangles must be clipped to the scissor and FBO. The clipping is done in 'blit'.
diff --git a/src/libANGLE/renderer/vulkan/ProgramVk.cpp b/src/libANGLE/renderer/vulkan/ProgramVk.cpp
index 206bc20..64dccb7 100644
--- a/src/libANGLE/renderer/vulkan/ProgramVk.cpp
+++ b/src/libANGLE/renderer/vulkan/ProgramVk.cpp
@@ -862,7 +862,7 @@
             // Ensure the image is in read-only layout
             if (image.isLayoutChangeNecessary(vk::ImageLayout::FragmentShaderReadOnly))
             {
-                vk::CommandBuffer *srcLayoutChange;
+                CommandBufferT *srcLayoutChange;
                 ANGLE_TRY(image.recordCommands(contextVk, &srcLayoutChange));
 
                 image.changeLayout(VK_IMAGE_ASPECT_COLOR_BIT,
@@ -910,8 +910,7 @@
     }
 }
 
-angle::Result ProgramVk::updateDescriptorSets(ContextVk *contextVk,
-                                              vk::CommandBuffer *commandBuffer)
+angle::Result ProgramVk::updateDescriptorSets(ContextVk *contextVk, CommandBufferT *commandBuffer)
 {
     // Can probably use better dirty bits here.
 
diff --git a/src/libANGLE/renderer/vulkan/ProgramVk.h b/src/libANGLE/renderer/vulkan/ProgramVk.h
index e59feef..ccdc933 100644
--- a/src/libANGLE/renderer/vulkan/ProgramVk.h
+++ b/src/libANGLE/renderer/vulkan/ProgramVk.h
@@ -108,7 +108,7 @@
     angle::Result updateTexturesDescriptorSet(ContextVk *contextVk,
                                               vk::FramebufferHelper *framebuffer);
 
-    angle::Result updateDescriptorSets(ContextVk *contextVk, vk::CommandBuffer *commandBuffer);
+    angle::Result updateDescriptorSets(ContextVk *contextVk, CommandBufferT *commandBuffer);
 
     // For testing only.
     void setDefaultUniformBlocksMinSizeForTesting(size_t minSize);
diff --git a/src/libANGLE/renderer/vulkan/RenderTargetVk.cpp b/src/libANGLE/renderer/vulkan/RenderTargetVk.cpp
index 8035c8e..059632d 100644
--- a/src/libANGLE/renderer/vulkan/RenderTargetVk.cpp
+++ b/src/libANGLE/renderer/vulkan/RenderTargetVk.cpp
@@ -53,7 +53,7 @@
 }
 
 void RenderTargetVk::onColorDraw(vk::FramebufferHelper *framebufferVk,
-                                 vk::CommandBuffer *commandBuffer,
+                                 CommandBufferT *commandBuffer,
                                  vk::RenderPassDesc *renderPassDesc)
 {
     ASSERT(commandBuffer->valid());
@@ -71,7 +71,7 @@
 }
 
 void RenderTargetVk::onDepthStencilDraw(vk::FramebufferHelper *framebufferVk,
-                                        vk::CommandBuffer *commandBuffer,
+                                        CommandBufferT *commandBuffer,
                                         vk::RenderPassDesc *renderPassDesc)
 {
     ASSERT(commandBuffer->valid());
@@ -135,7 +135,7 @@
 
 vk::ImageHelper *RenderTargetVk::getImageForRead(vk::CommandGraphResource *readingResource,
                                                  vk::ImageLayout layout,
-                                                 vk::CommandBuffer *commandBuffer)
+                                                 CommandBufferT *commandBuffer)
 {
     ASSERT(mImage && mImage->valid());
 
@@ -145,7 +145,7 @@
     //
     // if (mImage->isLayoutChangeNecessary(layout)
     // {
-    //     vk::CommandBuffer *srcLayoutChange;
+    //     CommandBufferT *srcLayoutChange;
     //     ANGLE_TRY(mImage->recordCommands(contextVk, &srcLayoutChange));
     //     mImage->changeLayout(mImage->getAspectFlags(), layout, srcLayoutChange);
     // }
diff --git a/src/libANGLE/renderer/vulkan/RenderTargetVk.h b/src/libANGLE/renderer/vulkan/RenderTargetVk.h
index bc6ace3..aa20780 100644
--- a/src/libANGLE/renderer/vulkan/RenderTargetVk.h
+++ b/src/libANGLE/renderer/vulkan/RenderTargetVk.h
@@ -53,10 +53,10 @@
 
     // Note: RenderTargets should be called in order, with the depth/stencil onRender last.
     void onColorDraw(vk::FramebufferHelper *framebufferVk,
-                     vk::CommandBuffer *commandBuffer,
+                     CommandBufferT *commandBuffer,
                      vk::RenderPassDesc *renderPassDesc);
     void onDepthStencilDraw(vk::FramebufferHelper *framebufferVk,
-                            vk::CommandBuffer *commandBuffer,
+                            CommandBufferT *commandBuffer,
                             vk::RenderPassDesc *renderPassDesc);
 
     vk::ImageHelper &getImage();
@@ -65,7 +65,7 @@
     // getImageForRead will also transition the resource to the given layout.
     vk::ImageHelper *getImageForRead(vk::CommandGraphResource *readingResource,
                                      vk::ImageLayout layout,
-                                     vk::CommandBuffer *commandBuffer);
+                                     CommandBufferT *commandBuffer);
     vk::ImageHelper *getImageForWrite(vk::CommandGraphResource *writingResource) const;
 
     vk::ImageView *getDrawImageView() const;
diff --git a/src/libANGLE/renderer/vulkan/RenderbufferVk.cpp b/src/libANGLE/renderer/vulkan/RenderbufferVk.cpp
index 1e485a9..a77d986 100644
--- a/src/libANGLE/renderer/vulkan/RenderbufferVk.cpp
+++ b/src/libANGLE/renderer/vulkan/RenderbufferVk.cpp
@@ -93,7 +93,7 @@
                                         &mImageView, 0, 1));
 
         // TODO(jmadill): Fold this into the RenderPass load/store ops. http://anglebug.com/2361
-        vk::CommandBuffer *commandBuffer = nullptr;
+        CommandBufferT *commandBuffer = nullptr;
         ANGLE_TRY(mImage->recordCommands(contextVk, &commandBuffer));
 
         if (isDepthOrStencilFormat)
@@ -143,7 +143,7 @@
     uint32_t rendererQueueFamilyIndex = contextVk->getRenderer()->getQueueFamilyIndex();
     if (mImage->isQueueChangeNeccesary(rendererQueueFamilyIndex))
     {
-        vk::CommandBuffer *commandBuffer = nullptr;
+        CommandBufferT *commandBuffer = nullptr;
         ANGLE_TRY(mImage->recordCommands(contextVk, &commandBuffer));
         mImage->changeLayoutAndQueue(aspect, vk::ImageLayout::ColorAttachment,
                                      rendererQueueFamilyIndex, commandBuffer);
diff --git a/src/libANGLE/renderer/vulkan/RendererVk.cpp b/src/libANGLE/renderer/vulkan/RendererVk.cpp
index 9e14e4b..de1f8db 100644
--- a/src/libANGLE/renderer/vulkan/RendererVk.cpp
+++ b/src/libANGLE/renderer/vulkan/RendererVk.cpp
@@ -41,6 +41,7 @@
 constexpr char kMockDeviceName[]                          = "Vulkan Mock Device";
 constexpr size_t kInFlightCommandsLimit                   = 100u;
 constexpr VkFormatFeatureFlags kInvalidFormatFeatureFlags = static_cast<VkFormatFeatureFlags>(-1);
+constexpr size_t kDefaultPoolAllocatorPageSize            = 16 * 1024;
 }  // anonymous namespace
 
 namespace rx
@@ -505,7 +506,8 @@
       mCurrentQueueSerial(mQueueSerialFactory.generate()),
       mDeviceLost(false),
       mPipelineCacheVkUpdateTimeout(kPipelineCacheVkUpdatePeriod),
-      mCommandGraph(kEnableCommandGraphDiagnostics),
+      mPoolAllocator(kDefaultPoolAllocatorPageSize),
+      mCommandGraph(kEnableCommandGraphDiagnostics, &mPoolAllocator),
       mGpuEventsEnabled(false),
       mGpuClockSync{std::numeric_limits<double>::max(), std::numeric_limits<double>::max()},
       mGpuEventTimestampOrigin(0)
diff --git a/src/libANGLE/renderer/vulkan/RendererVk.h b/src/libANGLE/renderer/vulkan/RendererVk.h
index 48a1fe5..ed94053 100644
--- a/src/libANGLE/renderer/vulkan/RendererVk.h
+++ b/src/libANGLE/renderer/vulkan/RendererVk.h
@@ -13,6 +13,7 @@
 #include <vulkan/vulkan.h>
 #include <memory>
 
+#include "common/PoolAlloc.h"
 #include "common/angleutils.h"
 #include "libANGLE/BlobCache.h"
 #include "libANGLE/Caps.h"
@@ -334,6 +335,9 @@
     // http://anglebug.com/2701
     vk::Shared<vk::Fence> mSubmitFence;
 
+    // Pool allocator used for command graph but may be expanded to other allocations
+    angle::PoolAllocator mPoolAllocator;
+
     // See CommandGraph.h for a desription of the Command Graph.
     vk::CommandGraph mCommandGraph;
 
diff --git a/src/libANGLE/renderer/vulkan/SecondaryCommandBuffer.cpp b/src/libANGLE/renderer/vulkan/SecondaryCommandBuffer.cpp
index 0e9725c..a0ccc7f 100644
--- a/src/libANGLE/renderer/vulkan/SecondaryCommandBuffer.cpp
+++ b/src/libANGLE/renderer/vulkan/SecondaryCommandBuffer.cpp
@@ -51,7 +51,7 @@
 }
 
 void SecondaryCommandBuffer::bindDescriptorSets(VkPipelineBindPoint bindPoint,
-                                                VkPipelineLayout layout,
+                                                const PipelineLayout &layout,
                                                 uint32_t firstSet,
                                                 uint32_t descriptorSetCount,
                                                 const VkDescriptorSet *descriptorSets,
@@ -65,7 +65,7 @@
         initCommand<BindDescriptorSetParams>(CommandID::BindDescriptorSets, varSize);
     // Copy params into memory
     paramStruct->bindPoint          = bindPoint;
-    paramStruct->layout             = layout;
+    paramStruct->layout             = layout.getHandle();
     paramStruct->firstSet           = firstSet;
     paramStruct->descriptorSetCount = descriptorSetCount;
     paramStruct->dynamicOffsetCount = dynamicOffsetCount;
@@ -74,23 +74,23 @@
     storePointerParameter(dynamicOffsets, &paramStruct->dynamicOffsets, offsetSize);
 }
 
-void SecondaryCommandBuffer::bindIndexBuffer(const VkBuffer &buffer,
+void SecondaryCommandBuffer::bindIndexBuffer(const Buffer &buffer,
                                              VkDeviceSize offset,
                                              VkIndexType indexType)
 {
     BindIndexBufferParams *paramStruct =
         initCommand<BindIndexBufferParams>(CommandID::BindIndexBuffer, 0);
-    paramStruct->buffer    = buffer;
+    paramStruct->buffer    = buffer.getHandle();
     paramStruct->offset    = offset;
     paramStruct->indexType = indexType;
 }
 
 void SecondaryCommandBuffer::bindPipeline(VkPipelineBindPoint pipelineBindPoint,
-                                          VkPipeline pipeline)
+                                          const Pipeline &pipeline)
 {
     BindPipelineParams *paramStruct = initCommand<BindPipelineParams>(CommandID::BindPipeline, 0);
     paramStruct->pipelineBindPoint  = pipelineBindPoint;
-    paramStruct->pipeline           = pipeline;
+    paramStruct->pipeline           = pipeline.getHandle();
 }
 
 void SecondaryCommandBuffer::bindVertexBuffers(uint32_t firstBinding,
@@ -110,9 +110,9 @@
     storePointerParameter(offsets, &paramStruct->offsets, offsetSize);
 }
 
-void SecondaryCommandBuffer::blitImage(VkImage srcImage,
+void SecondaryCommandBuffer::blitImage(const Image &srcImage,
                                        VkImageLayout srcImageLayout,
-                                       VkImage dstImage,
+                                       const Image &dstImage,
                                        VkImageLayout dstImageLayout,
                                        uint32_t regionCount,
                                        const VkImageBlit *pRegions,
@@ -120,9 +120,9 @@
 {
     size_t regionSize            = regionCount * sizeof(VkImageBlit);
     BlitImageParams *paramStruct = initCommand<BlitImageParams>(CommandID::BlitImage, regionSize);
-    paramStruct->srcImage        = srcImage;
+    paramStruct->srcImage        = srcImage.getHandle();
     paramStruct->srcImageLayout  = srcImageLayout;
-    paramStruct->dstImage        = dstImage;
+    paramStruct->dstImage        = dstImage.getHandle();
     paramStruct->dstImageLayout  = dstImageLayout;
     paramStruct->regionCount     = regionCount;
     paramStruct->filter          = filter;
@@ -130,23 +130,23 @@
     storePointerParameter(pRegions, &paramStruct->pRegions, regionSize);
 }
 
-void SecondaryCommandBuffer::copyBuffer(const VkBuffer &srcBuffer,
-                                        const VkBuffer &destBuffer,
+void SecondaryCommandBuffer::copyBuffer(const Buffer &srcBuffer,
+                                        const Buffer &destBuffer,
                                         uint32_t regionCount,
                                         const VkBufferCopy *regions)
 {
     size_t regionSize = regionCount * sizeof(VkBufferCopy);
     CopyBufferParams *paramStruct =
         initCommand<CopyBufferParams>(CommandID::CopyBuffer, regionSize);
-    paramStruct->srcBuffer   = srcBuffer;
-    paramStruct->destBuffer  = destBuffer;
+    paramStruct->srcBuffer   = srcBuffer.getHandle();
+    paramStruct->destBuffer  = destBuffer.getHandle();
     paramStruct->regionCount = regionCount;
     // Copy variable sized data
     storePointerParameter(regions, &paramStruct->regions, regionSize);
 }
 
 void SecondaryCommandBuffer::copyBufferToImage(VkBuffer srcBuffer,
-                                               VkImage dstImage,
+                                               const Image &dstImage,
                                                VkImageLayout dstImageLayout,
                                                uint32_t regionCount,
                                                const VkBufferImageCopy *regions)
@@ -155,32 +155,32 @@
     CopyBufferToImageParams *paramStruct =
         initCommand<CopyBufferToImageParams>(CommandID::CopyBufferToImage, regionSize);
     paramStruct->srcBuffer      = srcBuffer;
-    paramStruct->dstImage       = dstImage;
+    paramStruct->dstImage       = dstImage.getHandle();
     paramStruct->dstImageLayout = dstImageLayout;
     paramStruct->regionCount    = regionCount;
     // Copy variable sized data
     storePointerParameter(regions, &paramStruct->regions, regionSize);
 }
 
-void SecondaryCommandBuffer::copyImage(VkImage srcImage,
+void SecondaryCommandBuffer::copyImage(const Image &srcImage,
                                        VkImageLayout srcImageLayout,
-                                       VkImage dstImage,
+                                       const Image &dstImage,
                                        VkImageLayout dstImageLayout,
                                        uint32_t regionCount,
                                        const VkImageCopy *regions)
 {
     size_t regionSize            = regionCount * sizeof(VkImageCopy);
     CopyImageParams *paramStruct = initCommand<CopyImageParams>(CommandID::CopyImage, regionSize);
-    paramStruct->srcImage        = srcImage;
+    paramStruct->srcImage        = srcImage.getHandle();
     paramStruct->srcImageLayout  = srcImageLayout;
-    paramStruct->dstImage        = dstImage;
+    paramStruct->dstImage        = dstImage.getHandle();
     paramStruct->dstImageLayout  = dstImageLayout;
     paramStruct->regionCount     = regionCount;
     // Copy variable sized data
     storePointerParameter(regions, &paramStruct->regions, regionSize);
 }
 
-void SecondaryCommandBuffer::copyImageToBuffer(VkImage srcImage,
+void SecondaryCommandBuffer::copyImageToBuffer(const Image &srcImage,
                                                VkImageLayout srcImageLayout,
                                                VkBuffer dstBuffer,
                                                uint32_t regionCount,
@@ -189,7 +189,7 @@
     size_t regionSize = regionCount * sizeof(VkBufferImageCopy);
     CopyImageToBufferParams *paramStruct =
         initCommand<CopyImageToBufferParams>(CommandID::CopyImageToBuffer, regionSize);
-    paramStruct->srcImage       = srcImage;
+    paramStruct->srcImage       = srcImage.getHandle();
     paramStruct->srcImageLayout = srcImageLayout;
     paramStruct->dstBuffer      = dstBuffer;
     paramStruct->regionCount    = regionCount;
@@ -213,7 +213,7 @@
     storePointerParameter(rects, &paramStruct->rects, rectSize);
 }
 
-void SecondaryCommandBuffer::clearColorImage(VkImage image,
+void SecondaryCommandBuffer::clearColorImage(const Image &image,
                                              VkImageLayout imageLayout,
                                              const VkClearColorValue &color,
                                              uint32_t rangeCount,
@@ -222,7 +222,7 @@
     size_t rangeSize = rangeCount * sizeof(VkImageSubresourceRange);
     ClearColorImageParams *paramStruct =
         initCommand<ClearColorImageParams>(CommandID::ClearColorImage, rangeSize);
-    paramStruct->image       = image;
+    paramStruct->image       = image.getHandle();
     paramStruct->imageLayout = imageLayout;
     paramStruct->color       = color;
     paramStruct->rangeCount  = rangeCount;
@@ -230,7 +230,7 @@
     storePointerParameter(ranges, &paramStruct->ranges, rangeSize);
 }
 
-void SecondaryCommandBuffer::clearDepthStencilImage(VkImage image,
+void SecondaryCommandBuffer::clearDepthStencilImage(const Image &image,
                                                     VkImageLayout imageLayout,
                                                     const VkClearDepthStencilValue &depthStencil,
                                                     uint32_t rangeCount,
@@ -239,7 +239,7 @@
     size_t rangeSize = rangeCount * sizeof(VkImageSubresourceRange);
     ClearDepthStencilImageParams *paramStruct =
         initCommand<ClearDepthStencilImageParams>(CommandID::ClearDepthStencilImage, rangeSize);
-    paramStruct->image        = image;
+    paramStruct->image        = image.getHandle();
     paramStruct->imageLayout  = imageLayout;
     paramStruct->depthStencil = depthStencil;
     paramStruct->rangeCount   = rangeCount;
@@ -247,7 +247,7 @@
     storePointerParameter(ranges, &paramStruct->ranges, rangeSize);
 }
 
-void SecondaryCommandBuffer::updateBuffer(VkBuffer buffer,
+void SecondaryCommandBuffer::updateBuffer(const Buffer &buffer,
                                           VkDeviceSize dstOffset,
                                           VkDeviceSize dataSize,
                                           const void *data)
@@ -255,14 +255,14 @@
     ASSERT(dataSize == static_cast<size_t>(dataSize));
     UpdateBufferParams *paramStruct =
         initCommand<UpdateBufferParams>(CommandID::UpdateBuffer, static_cast<size_t>(dataSize));
-    paramStruct->buffer    = buffer;
+    paramStruct->buffer    = buffer.getHandle();
     paramStruct->dstOffset = dstOffset;
     paramStruct->dataSize  = dataSize;
     // Copy variable sized data
     storePointerParameter(data, &paramStruct->data, static_cast<size_t>(dataSize));
 }
 
-void SecondaryCommandBuffer::pushConstants(VkPipelineLayout layout,
+void SecondaryCommandBuffer::pushConstants(const PipelineLayout &layout,
                                            VkShaderStageFlags flag,
                                            uint32_t offset,
                                            uint32_t size,
@@ -271,7 +271,7 @@
     ASSERT(size == static_cast<size_t>(size));
     PushConstantsParams *paramStruct =
         initCommand<PushConstantsParams>(CommandID::PushConstants, static_cast<size_t>(size));
-    paramStruct->layout = layout;
+    paramStruct->layout = layout.getHandle();
     paramStruct->flag   = flag;
     paramStruct->offset = offset;
     paramStruct->size   = size;
diff --git a/src/libANGLE/renderer/vulkan/SecondaryCommandBuffer.h b/src/libANGLE/renderer/vulkan/SecondaryCommandBuffer.h
index 31b3f59..86661de 100644
--- a/src/libANGLE/renderer/vulkan/SecondaryCommandBuffer.h
+++ b/src/libANGLE/renderer/vulkan/SecondaryCommandBuffer.h
@@ -14,6 +14,7 @@
 #include <vulkan/vulkan.h>
 
 #include "common/PoolAlloc.h"
+#include "libANGLE/renderer/vulkan/vk_wrapper.h"
 
 namespace rx
 {
@@ -295,56 +296,54 @@
 class SecondaryCommandBuffer final : angle::NonCopyable
 {
   public:
-    SecondaryCommandBuffer(angle::PoolAllocator *allocator)
-        : mHead(nullptr), mLast(nullptr), mAllocator(allocator)
-    {}
+    SecondaryCommandBuffer() : mHead(nullptr), mLast(nullptr), mAllocator(nullptr) {}
     ~SecondaryCommandBuffer() {}
 
     // Add commands
     void bindDescriptorSets(VkPipelineBindPoint bindPoint,
-                            VkPipelineLayout layout,
+                            const PipelineLayout &layout,
                             uint32_t firstSet,
                             uint32_t descriptorSetCount,
                             const VkDescriptorSet *descriptorSets,
                             uint32_t dynamicOffsetCount,
                             const uint32_t *dynamicOffsets);
 
-    void bindIndexBuffer(const VkBuffer &buffer, VkDeviceSize offset, VkIndexType indexType);
+    void bindIndexBuffer(const Buffer &buffer, VkDeviceSize offset, VkIndexType indexType);
 
-    void bindPipeline(VkPipelineBindPoint pipelineBindPoint, VkPipeline pipeline);
+    void bindPipeline(VkPipelineBindPoint pipelineBindPoint, const Pipeline &pipeline);
 
     void bindVertexBuffers(uint32_t firstBinding,
                            uint32_t bindingCount,
                            const VkBuffer *buffers,
                            const VkDeviceSize *offsets);
 
-    void blitImage(VkImage srcImage,
+    void blitImage(const Image &srcImage,
                    VkImageLayout srcImageLayout,
-                   VkImage dstImage,
+                   const Image &dstImage,
                    VkImageLayout dstImageLayout,
                    uint32_t regionCount,
                    const VkImageBlit *pRegions,
                    VkFilter filter);
 
-    void copyBuffer(const VkBuffer &srcBuffer,
-                    const VkBuffer &destBuffer,
+    void copyBuffer(const Buffer &srcBuffer,
+                    const Buffer &destBuffer,
                     uint32_t regionCount,
                     const VkBufferCopy *regions);
 
     void copyBufferToImage(VkBuffer srcBuffer,
-                           VkImage dstImage,
+                           const Image &dstImage,
                            VkImageLayout dstImageLayout,
                            uint32_t regionCount,
                            const VkBufferImageCopy *regions);
 
-    void copyImage(VkImage srcImage,
+    void copyImage(const Image &srcImage,
                    VkImageLayout srcImageLayout,
-                   VkImage dstImage,
+                   const Image &dstImage,
                    VkImageLayout dstImageLayout,
                    uint32_t regionCount,
                    const VkImageCopy *regions);
 
-    void copyImageToBuffer(VkImage srcImage,
+    void copyImageToBuffer(const Image &srcImage,
                            VkImageLayout srcImageLayout,
                            VkBuffer dstBuffer,
                            uint32_t regionCount,
@@ -355,24 +354,24 @@
                           uint32_t rectCount,
                           const VkClearRect *rects);
 
-    void clearColorImage(VkImage image,
+    void clearColorImage(const Image &image,
                          VkImageLayout imageLayout,
                          const VkClearColorValue &color,
                          uint32_t rangeCount,
                          const VkImageSubresourceRange *ranges);
 
-    void clearDepthStencilImage(VkImage image,
+    void clearDepthStencilImage(const Image &image,
                                 VkImageLayout imageLayout,
                                 const VkClearDepthStencilValue &depthStencil,
                                 uint32_t rangeCount,
                                 const VkImageSubresourceRange *ranges);
 
-    void updateBuffer(VkBuffer buffer,
+    void updateBuffer(const Buffer &buffer,
                       VkDeviceSize dstOffset,
                       VkDeviceSize dataSize,
                       const void *data);
 
-    void pushConstants(VkPipelineLayout layout,
+    void pushConstants(const PipelineLayout &layout,
                        VkShaderStageFlags flag,
                        uint32_t offset,
                        uint32_t size,
@@ -423,9 +422,17 @@
     void writeTimestamp(VkPipelineStageFlagBits pipelineStage,
                         VkQueryPool queryPool,
                         uint32_t query);
+    // No-op for compatibility
+    VkResult end() { return VK_SUCCESS; }
 
     // Parse the cmds in this cmd buffer into given primary cmd buffer for execution
     void executeCommands(VkCommandBuffer cmdBuffer);
+    // Initialize the SecondaryCommandBuffer by setting the allocator it will use
+    void initialize(angle::PoolAllocator *allocator) { mAllocator = allocator; }
+    // This will cause the SecondaryCommandBuffer to become invalid by clearing its allocator
+    void releaseHandle() { mAllocator = nullptr; }
+    // The SecondaryCommandBuffer is valid if it's been initialized
+    bool valid() { return mAllocator != nullptr; }
 
   private:
     // Allocate and initialize memory for given commandID & variable param size
diff --git a/src/libANGLE/renderer/vulkan/SurfaceVk.cpp b/src/libANGLE/renderer/vulkan/SurfaceVk.cpp
index 682208b..7c711c4 100644
--- a/src/libANGLE/renderer/vulkan/SurfaceVk.cpp
+++ b/src/libANGLE/renderer/vulkan/SurfaceVk.cpp
@@ -548,7 +548,7 @@
                                              &member.imageView, 0, 1));
 
         // Allocate a command buffer for clearing our images to black.
-        vk::CommandBuffer *commandBuffer = nullptr;
+        CommandBufferT *commandBuffer = nullptr;
         ANGLE_TRY(member.image.recordCommands(displayVk, &commandBuffer));
 
         // Set transfer dest layout, and clear the image to black.
@@ -571,7 +571,7 @@
         VkClearDepthStencilValue depthStencilClearValue = {1.0f, 0};
 
         // Clear the image.
-        vk::CommandBuffer *commandBuffer = nullptr;
+        CommandBufferT *commandBuffer = nullptr;
         ANGLE_TRY(mDepthStencilImage.recordCommands(displayVk, &commandBuffer));
         mDepthStencilImage.clearDepthStencil(aspect, aspect, depthStencilClearValue, commandBuffer);
 
@@ -706,7 +706,7 @@
 
     SwapchainImage &image = mSwapchainImages[mCurrentSwapchainImageIndex];
 
-    vk::CommandBuffer *swapCommands = nullptr;
+    CommandBufferT *swapCommands = nullptr;
     ANGLE_TRY(image.image.recordCommands(displayVk, &swapCommands));
 
     image.image.changeLayout(VK_IMAGE_ASPECT_COLOR_BIT, vk::ImageLayout::Present, swapCommands);
diff --git a/src/libANGLE/renderer/vulkan/TextureVk.cpp b/src/libANGLE/renderer/vulkan/TextureVk.cpp
index 7914052..de083b4 100644
--- a/src/libANGLE/renderer/vulkan/TextureVk.cpp
+++ b/src/libANGLE/renderer/vulkan/TextureVk.cpp
@@ -534,7 +534,7 @@
     // Change source layout if necessary
     if (srcImage->isLayoutChangeNecessary(vk::ImageLayout::TransferSrc))
     {
-        vk::CommandBuffer *srcLayoutChange;
+        CommandBufferT *srcLayoutChange;
         ANGLE_TRY(srcImage->recordCommands(contextVk, &srcLayoutChange));
         srcImage->changeLayout(VK_IMAGE_ASPECT_COLOR_BIT, vk::ImageLayout::TransferSrc,
                                srcLayoutChange);
@@ -552,7 +552,7 @@
         // Make sure any updates to the image are already flushed.
         ANGLE_TRY(ensureImageInitialized(contextVk));
 
-        vk::CommandBuffer *commandBuffer;
+        CommandBufferT *commandBuffer;
         ANGLE_TRY(mImage->recordCommands(contextVk, &commandBuffer));
 
         // Change the image layout before the transfer
@@ -580,7 +580,7 @@
                                               gl::Extents(sourceArea.width, sourceArea.height, 1),
                                               destFormat, kTransferStagingImageFlags, layerCount));
 
-        vk::CommandBuffer *commandBuffer;
+        CommandBufferT *commandBuffer;
         ANGLE_TRY(stagingImage->recordCommands(contextVk, &commandBuffer));
 
         // Change the image layout before the transfer
@@ -749,7 +749,7 @@
     const vk::Format &format = renderer->getFormat(internalFormat);
     ANGLE_TRY(ensureImageAllocated(renderer, format));
 
-    vk::CommandBuffer *commandBuffer = nullptr;
+    CommandBufferT *commandBuffer = nullptr;
     ANGLE_TRY(mImage->recordCommands(contextVk, &commandBuffer));
 
     if (mImage->valid())
@@ -782,7 +782,7 @@
     uint32_t rendererQueueFamilyIndex = renderer->getQueueFamilyIndex();
     if (mImage->isQueueChangeNeccesary(rendererQueueFamilyIndex))
     {
-        vk::CommandBuffer *commandBuffer = nullptr;
+        CommandBufferT *commandBuffer = nullptr;
         ANGLE_TRY(mImage->recordCommands(contextVk, &commandBuffer));
         mImage->changeLayoutAndQueue(VK_IMAGE_ASPECT_COLOR_BIT,
                                      vk::ImageLayout::FragmentShaderReadOnly,
@@ -938,7 +938,7 @@
     size_t sourceCopyAllocationSize =
         sourceArea.width * sourceArea.height * imageFormat.pixelBytes * layerCount;
 
-    vk::CommandBuffer *commandBuffer = nullptr;
+    CommandBufferT *commandBuffer = nullptr;
     ANGLE_TRY(mImage->recordCommands(contextVk, &commandBuffer));
 
     // Requirement of the copyImageToBuffer, the source image must be in SRC_OPTIMAL layout.
@@ -1004,7 +1004,7 @@
             sourceRowPitch, imageData + bufferOffset));
     }
 
-    vk::CommandBuffer *commandBuffer;
+    CommandBufferT *commandBuffer;
     ANGLE_TRY(mImage->recordCommands(contextVk, &commandBuffer));
     return mImage->flushStagedUpdates(contextVk, getNativeImageLevel(0), getLevelCount(),
                                       commandBuffer);
@@ -1132,7 +1132,7 @@
     {
         return angle::Result::Continue;
     }
-    vk::CommandBuffer *commandBuffer = nullptr;
+    CommandBufferT *commandBuffer = nullptr;
     ANGLE_TRY(mImage->recordCommands(contextVk, &commandBuffer));
 
     if (!mImage->valid())
@@ -1290,7 +1290,7 @@
                                    const vk::Format &format,
                                    const gl::Extents &extents,
                                    const uint32_t levelCount,
-                                   vk::CommandBuffer *commandBuffer)
+                                   CommandBufferT *commandBuffer)
 {
     const RendererVk *renderer       = contextVk->getRenderer();
     const angle::Format &angleFormat = format.textureFormat();
diff --git a/src/libANGLE/renderer/vulkan/TextureVk.h b/src/libANGLE/renderer/vulkan/TextureVk.h
index 6f3c753..18ff551 100644
--- a/src/libANGLE/renderer/vulkan/TextureVk.h
+++ b/src/libANGLE/renderer/vulkan/TextureVk.h
@@ -253,7 +253,7 @@
                             const vk::Format &format,
                             const gl::Extents &extents,
                             const uint32_t levelCount,
-                            vk::CommandBuffer *commandBuffer);
+                            CommandBufferT *commandBuffer);
     void releaseImage(RendererVk *renderer);
     void releaseStagingBuffer(RendererVk *renderer);
     uint32_t getLevelCount() const;
diff --git a/src/libANGLE/renderer/vulkan/UtilsVk.cpp b/src/libANGLE/renderer/vulkan/UtilsVk.cpp
index a290eb1..1656af4 100644
--- a/src/libANGLE/renderer/vulkan/UtilsVk.cpp
+++ b/src/libANGLE/renderer/vulkan/UtilsVk.cpp
@@ -311,7 +311,7 @@
                                     const VkDescriptorSet descriptorSet,
                                     const void *pushConstants,
                                     size_t pushConstantsSize,
-                                    vk::CommandBuffer *commandBuffer)
+                                    CommandBufferT *commandBuffer)
 {
     RendererVk *renderer = context->getRenderer();
 
@@ -373,7 +373,7 @@
 
     ANGLE_TRY(ensureBufferClearResourcesInitialized(context));
 
-    vk::CommandBuffer *commandBuffer;
+    CommandBufferT *commandBuffer;
     ANGLE_TRY(dest->recordCommands(context, &commandBuffer));
 
     // Tell dest it's being written to.
@@ -429,7 +429,7 @@
 
     ANGLE_TRY(ensureBufferCopyResourcesInitialized(context));
 
-    vk::CommandBuffer *commandBuffer;
+    CommandBufferT *commandBuffer;
     ANGLE_TRY(dest->recordCommands(context, &commandBuffer));
 
     // Tell src we are going to read from it.
@@ -498,7 +498,7 @@
 
     ANGLE_TRY(ensureConvertVertexResourcesInitialized(context));
 
-    vk::CommandBuffer *commandBuffer;
+    CommandBufferT *commandBuffer;
     ANGLE_TRY(dest->recordCommands(context, &commandBuffer));
 
     // Tell src we are going to read from it.
@@ -576,7 +576,7 @@
                                        const vk::ImageView *imageView,
                                        const vk::RenderPassDesc &renderPassDesc,
                                        const gl::Rectangle &renderArea,
-                                       vk::CommandBuffer **commandBufferOut)
+                                       CommandBufferT **commandBufferOut)
 {
     RendererVk *renderer = contextVk->getRenderer();
 
@@ -617,7 +617,7 @@
 
     ANGLE_TRY(ensureImageClearResourcesInitialized(contextVk));
 
-    vk::CommandBuffer *commandBuffer;
+    CommandBufferT *commandBuffer;
     if (!framebuffer->appendToStartedRenderPass(renderer->getCurrentQueueSerial(), &commandBuffer))
     {
         ANGLE_TRY(framebuffer->startNewRenderPass(contextVk, &commandBuffer));
@@ -740,20 +740,20 @@
     // Change source layout outside render pass
     if (src->isLayoutChangeNecessary(vk::ImageLayout::FragmentShaderReadOnly))
     {
-        vk::CommandBuffer *srcLayoutChange;
+        CommandBufferT *srcLayoutChange;
         ANGLE_TRY(src->recordCommands(contextVk, &srcLayoutChange));
         src->changeLayout(VK_IMAGE_ASPECT_COLOR_BIT, vk::ImageLayout::FragmentShaderReadOnly,
                           srcLayoutChange);
     }
 
     // Change destination layout outside render pass as well
-    vk::CommandBuffer *destLayoutChange;
+    CommandBufferT *destLayoutChange;
     ANGLE_TRY(dest->recordCommands(contextVk, &destLayoutChange));
 
     dest->changeLayout(VK_IMAGE_ASPECT_COLOR_BIT, vk::ImageLayout::ColorAttachment,
                        destLayoutChange);
 
-    vk::CommandBuffer *commandBuffer;
+    CommandBufferT *commandBuffer;
     ANGLE_TRY(
         startRenderPass(contextVk, dest, destView, renderPassDesc, renderArea, &commandBuffer));
 
diff --git a/src/libANGLE/renderer/vulkan/UtilsVk.h b/src/libANGLE/renderer/vulkan/UtilsVk.h
index 574b468..f1c6724 100644
--- a/src/libANGLE/renderer/vulkan/UtilsVk.h
+++ b/src/libANGLE/renderer/vulkan/UtilsVk.h
@@ -192,7 +192,7 @@
                                const VkDescriptorSet descriptorSet,
                                const void *pushConstants,
                                size_t pushConstantsSize,
-                               vk::CommandBuffer *commandBuffer);
+                               CommandBufferT *commandBuffer);
 
     // Initializes descriptor set layout, pipeline layout and descriptor pool corresponding to given
     // function, if not already initialized.  Uses setSizes to create the layout.  For example, if
@@ -218,7 +218,7 @@
                                   const vk::ImageView *imageView,
                                   const vk::RenderPassDesc &renderPassDesc,
                                   const gl::Rectangle &renderArea,
-                                  vk::CommandBuffer **commandBufferOut);
+                                  CommandBufferT **commandBufferOut);
 
     angle::PackedEnumMap<Function, vk::DescriptorSetLayoutPointerArray> mDescriptorSetLayouts;
     angle::PackedEnumMap<Function, vk::BindingPointer<vk::PipelineLayout>> mPipelineLayouts;
diff --git a/src/libANGLE/renderer/vulkan/vk_helpers.cpp b/src/libANGLE/renderer/vulkan/vk_helpers.cpp
index 8ba4f80..8d7c2de 100644
--- a/src/libANGLE/renderer/vulkan/vk_helpers.cpp
+++ b/src/libANGLE/renderer/vulkan/vk_helpers.cpp
@@ -1060,7 +1060,7 @@
 }
 
 // static
-void LineLoopHelper::Draw(uint32_t count, CommandBuffer *commandBuffer)
+void LineLoopHelper::Draw(uint32_t count, CommandBufferT *commandBuffer)
 {
     // Our first index is always 0 because that's how we set it up in createIndexBuffer*.
     // Note: this could theoretically overflow and wrap to zero.
@@ -1128,7 +1128,7 @@
                                            const VkBufferCopy &copyRegion)
 {
     // 'recordCommands' will implicitly stop any reads from using the old buffer data.
-    vk::CommandBuffer *commandBuffer = nullptr;
+    CommandBufferT *commandBuffer = nullptr;
     ANGLE_TRY(recordCommands(context, &commandBuffer));
 
     if (mCurrentReadAccess != 0 || mCurrentWriteAccess != 0)
@@ -1558,7 +1558,7 @@
 
 void ImageHelper::changeLayout(VkImageAspectFlags aspectMask,
                                ImageLayout newLayout,
-                               CommandBuffer *commandBuffer)
+                               CommandBufferT *commandBuffer)
 {
     if (!isLayoutChangeNecessary(newLayout))
     {
@@ -1571,7 +1571,7 @@
 void ImageHelper::changeLayoutAndQueue(VkImageAspectFlags aspectMask,
                                        ImageLayout newLayout,
                                        uint32_t newQueueFamilyIndex,
-                                       CommandBuffer *commandBuffer)
+                                       CommandBufferT *commandBuffer)
 {
     ASSERT(isQueueChangeNeccesary(newQueueFamilyIndex));
     forceChangeLayoutAndQueue(aspectMask, newLayout, newQueueFamilyIndex, commandBuffer);
@@ -1580,7 +1580,7 @@
 void ImageHelper::forceChangeLayoutAndQueue(VkImageAspectFlags aspectMask,
                                             ImageLayout newLayout,
                                             uint32_t newQueueFamilyIndex,
-                                            CommandBuffer *commandBuffer)
+                                            CommandBufferT *commandBuffer)
 {
 
     const ImageMemoryBarrierData &transitionFrom = kImageMemoryBarrierData[mCurrentLayout];
@@ -1613,7 +1613,7 @@
 void ImageHelper::clearColor(const VkClearColorValue &color,
                              uint32_t baseMipLevel,
                              uint32_t levelCount,
-                             CommandBuffer *commandBuffer)
+                             CommandBufferT *commandBuffer)
 
 {
     clearColorLayer(color, baseMipLevel, levelCount, 0, mLayerCount, commandBuffer);
@@ -1624,7 +1624,7 @@
                                   uint32_t levelCount,
                                   uint32_t baseArrayLayer,
                                   uint32_t layerCount,
-                                  CommandBuffer *commandBuffer)
+                                  CommandBufferT *commandBuffer)
 {
     ASSERT(valid());
 
@@ -1643,7 +1643,7 @@
 void ImageHelper::clearDepthStencil(VkImageAspectFlags imageAspectFlags,
                                     VkImageAspectFlags clearAspectFlags,
                                     const VkClearDepthStencilValue &depthStencil,
-                                    CommandBuffer *commandBuffer)
+                                    CommandBufferT *commandBuffer)
 {
     ASSERT(valid());
 
@@ -1678,7 +1678,7 @@
                        const gl::Extents &copySize,
                        const VkImageSubresourceLayers &srcSubresource,
                        const VkImageSubresourceLayers &dstSubresource,
-                       CommandBuffer *commandBuffer)
+                       CommandBufferT *commandBuffer)
 {
     ASSERT(commandBuffer->valid() && srcImage->valid() && dstImage->valid());
 
@@ -1704,7 +1704,7 @@
 
 angle::Result ImageHelper::generateMipmapsWithBlit(ContextVk *contextVk, GLuint maxLevel)
 {
-    vk::CommandBuffer *commandBuffer = nullptr;
+    CommandBufferT *commandBuffer = nullptr;
     ANGLE_TRY(recordCommands(contextVk, &commandBuffer));
 
     changeLayout(VK_IMAGE_ASPECT_COLOR_BIT, ImageLayout::TransferDst, commandBuffer);
@@ -2065,7 +2065,7 @@
 angle::Result ImageHelper::flushStagedUpdates(Context *context,
                                               uint32_t baseLevel,
                                               uint32_t levelCount,
-                                              vk::CommandBuffer *commandBuffer)
+                                              CommandBufferT *commandBuffer)
 {
     if (mSubresourceUpdates.empty())
     {
diff --git a/src/libANGLE/renderer/vulkan/vk_helpers.h b/src/libANGLE/renderer/vulkan/vk_helpers.h
index b0853a8..1b71c0f 100644
--- a/src/libANGLE/renderer/vulkan/vk_helpers.h
+++ b/src/libANGLE/renderer/vulkan/vk_helpers.h
@@ -379,7 +379,7 @@
     void release(RendererVk *renderer);
     void destroy(VkDevice device);
 
-    static void Draw(uint32_t count, CommandBuffer *commandBuffer);
+    static void Draw(uint32_t count, CommandBufferT *commandBuffer);
 
   private:
     DynamicBuffer mDynamicIndexBuffer;
@@ -613,19 +613,19 @@
     void clearColor(const VkClearColorValue &color,
                     uint32_t baseMipLevel,
                     uint32_t levelCount,
-                    CommandBuffer *commandBuffer);
+                    CommandBufferT *commandBuffer);
 
     void clearColorLayer(const VkClearColorValue &color,
                          uint32_t baseMipLevel,
                          uint32_t levelCount,
                          uint32_t baseArrayLayer,
                          uint32_t layerCount,
-                         CommandBuffer *commandBuffer);
+                         CommandBufferT *commandBuffer);
 
     void clearDepthStencil(VkImageAspectFlags imageAspectFlags,
                            VkImageAspectFlags clearAspectFlags,
                            const VkClearDepthStencilValue &depthStencil,
-                           CommandBuffer *commandBuffer);
+                           CommandBufferT *commandBuffer);
     gl::Extents getSize(const gl::ImageIndex &index) const;
 
     static void Copy(ImageHelper *srcImage,
@@ -635,7 +635,7 @@
                      const gl::Extents &copySize,
                      const VkImageSubresourceLayers &srcSubresources,
                      const VkImageSubresourceLayers &dstSubresources,
-                     CommandBuffer *commandBuffer);
+                     CommandBufferT *commandBuffer);
 
     angle::Result generateMipmapsWithBlit(ContextVk *contextVk, GLuint maxLevel);
 
@@ -683,7 +683,7 @@
     angle::Result flushStagedUpdates(Context *context,
                                      uint32_t baseLevel,
                                      uint32_t levelCount,
-                                     vk::CommandBuffer *commandBuffer);
+                                     CommandBufferT *commandBuffer);
 
     bool hasStagedUpdates() const;
 
@@ -694,7 +694,7 @@
 
     void changeLayout(VkImageAspectFlags aspectMask,
                       ImageLayout newLayout,
-                      CommandBuffer *commandBuffer);
+                      CommandBufferT *commandBuffer);
 
     bool isQueueChangeNeccesary(uint32_t newQueueFamilyIndex) const
     {
@@ -704,13 +704,13 @@
     void changeLayoutAndQueue(VkImageAspectFlags aspectMask,
                               ImageLayout newLayout,
                               uint32_t newQueueFamilyIndex,
-                              CommandBuffer *commandBuffer);
+                              CommandBufferT *commandBuffer);
 
   private:
     void forceChangeLayoutAndQueue(VkImageAspectFlags aspectMask,
                                    ImageLayout newLayout,
                                    uint32_t newQueueFamilyIndex,
-                                   CommandBuffer *commandBuffer);
+                                   CommandBufferT *commandBuffer);
 
     struct SubresourceUpdate
     {
diff --git a/src/libANGLE/renderer/vulkan/vk_wrapper.h b/src/libANGLE/renderer/vulkan/vk_wrapper.h
index de7b84e..beceaa0 100644
--- a/src/libANGLE/renderer/vulkan/vk_wrapper.h
+++ b/src/libANGLE/renderer/vulkan/vk_wrapper.h
@@ -242,7 +242,7 @@
                            const VkBuffer *buffers,
                            const VkDeviceSize *offsets);
 
-    void bindIndexBuffer(const VkBuffer &buffer, VkDeviceSize offset, VkIndexType indexType);
+    void bindIndexBuffer(const Buffer &buffer, VkDeviceSize offset, VkIndexType indexType);
     void bindDescriptorSets(VkPipelineBindPoint bindPoint,
                             const PipelineLayout &layout,
                             uint32_t firstSet,
@@ -252,7 +252,7 @@
                             const uint32_t *dynamicOffsets);
 
     void executeCommands(uint32_t commandBufferCount, const CommandBuffer *commandBuffers);
-    void updateBuffer(const vk::Buffer &buffer,
+    void updateBuffer(const Buffer &buffer,
                       VkDeviceSize dstOffset,
                       VkDeviceSize dataSize,
                       const void *data);
@@ -534,7 +534,7 @@
                                            VkImageBlit *pRegions,
                                            VkFilter filter)
 {
-    ASSERT(valid());
+    ASSERT(valid() && srcImage.valid() && dstImage.valid());
     vkCmdBlitImage(mHandle, srcImage.getHandle(), srcImageLayout, dstImage.getHandle(),
                    dstImageLayout, regionCount, pRegions, filter);
 }
@@ -588,13 +588,12 @@
     }
 }
 
-ANGLE_INLINE void CommandBuffer::copyBuffer(const vk::Buffer &srcBuffer,
-                                            const vk::Buffer &destBuffer,
+ANGLE_INLINE void CommandBuffer::copyBuffer(const Buffer &srcBuffer,
+                                            const Buffer &destBuffer,
                                             uint32_t regionCount,
                                             const VkBufferCopy *regions)
 {
-    ASSERT(valid());
-    ASSERT(srcBuffer.valid() && destBuffer.valid());
+    ASSERT(valid() && srcBuffer.valid() && destBuffer.valid());
     vkCmdCopyBuffer(mHandle, srcBuffer.getHandle(), destBuffer.getHandle(), regionCount, regions);
 }
 
@@ -604,9 +603,8 @@
                                                    uint32_t regionCount,
                                                    const VkBufferImageCopy *regions)
 {
-    ASSERT(valid());
+    ASSERT(valid() && dstImage.valid());
     ASSERT(srcBuffer != VK_NULL_HANDLE);
-    ASSERT(dstImage.valid());
     vkCmdCopyBufferToImage(mHandle, srcBuffer, dstImage.getHandle(), dstImageLayout, regionCount,
                            regions);
 }
@@ -617,14 +615,13 @@
                                                    uint32_t regionCount,
                                                    const VkBufferImageCopy *regions)
 {
-    ASSERT(valid());
+    ASSERT(valid() && srcImage.valid());
     ASSERT(dstBuffer != VK_NULL_HANDLE);
-    ASSERT(srcImage.valid());
     vkCmdCopyImageToBuffer(mHandle, srcImage.getHandle(), srcImageLayout, dstBuffer, regionCount,
                            regions);
 }
 
-ANGLE_INLINE void CommandBuffer::clearColorImage(const vk::Image &image,
+ANGLE_INLINE void CommandBuffer::clearColorImage(const Image &image,
                                                  VkImageLayout imageLayout,
                                                  const VkClearColorValue &color,
                                                  uint32_t rangeCount,
@@ -635,7 +632,7 @@
 }
 
 ANGLE_INLINE void CommandBuffer::clearDepthStencilImage(
-    const vk::Image &image,
+    const Image &image,
     VkImageLayout imageLayout,
     const VkClearDepthStencilValue &depthStencil,
     uint32_t rangeCount,
@@ -655,9 +652,9 @@
     vkCmdClearAttachments(mHandle, attachmentCount, attachments, rectCount, rects);
 }
 
-ANGLE_INLINE void CommandBuffer::copyImage(const vk::Image &srcImage,
+ANGLE_INLINE void CommandBuffer::copyImage(const Image &srcImage,
                                            VkImageLayout srcImageLayout,
-                                           const vk::Image &dstImage,
+                                           const Image &dstImage,
                                            VkImageLayout dstImageLayout,
                                            uint32_t regionCount,
                                            const VkImageCopy *regions)
@@ -680,23 +677,23 @@
     vkCmdEndRenderPass(mHandle);
 }
 
-ANGLE_INLINE void CommandBuffer::bindIndexBuffer(const VkBuffer &buffer,
+ANGLE_INLINE void CommandBuffer::bindIndexBuffer(const Buffer &buffer,
                                                  VkDeviceSize offset,
                                                  VkIndexType indexType)
 {
     ASSERT(valid());
-    vkCmdBindIndexBuffer(mHandle, buffer, offset, indexType);
+    vkCmdBindIndexBuffer(mHandle, buffer.getHandle(), offset, indexType);
 }
 
 ANGLE_INLINE void CommandBuffer::bindDescriptorSets(VkPipelineBindPoint bindPoint,
-                                                    const vk::PipelineLayout &layout,
+                                                    const PipelineLayout &layout,
                                                     uint32_t firstSet,
                                                     uint32_t descriptorSetCount,
                                                     const VkDescriptorSet *descriptorSets,
                                                     uint32_t dynamicOffsetCount,
                                                     const uint32_t *dynamicOffsets)
 {
-    ASSERT(valid());
+    ASSERT(valid() && layout.valid());
     vkCmdBindDescriptorSets(mHandle, bindPoint, layout.getHandle(), firstSet, descriptorSetCount,
                             descriptorSets, dynamicOffsetCount, dynamicOffsets);
 }
@@ -708,7 +705,7 @@
     vkCmdExecuteCommands(mHandle, commandBufferCount, commandBuffers[0].ptr());
 }
 
-ANGLE_INLINE void CommandBuffer::updateBuffer(const vk::Buffer &buffer,
+ANGLE_INLINE void CommandBuffer::updateBuffer(const Buffer &buffer,
                                               VkDeviceSize dstOffset,
                                               VkDeviceSize dataSize,
                                               const void *data)