Revert "Vulkan:Optimize SecondaryCommandBuffers"

This reverts commit 2219b18c984ed69251f3db3c7b5fd69a2fa68c77.

Reason for revert: Failing to compile on ASAN builders:

https://ci.chromium.org/p/chromium/builders/try/linux-libfuzzer-asan-rel/134782

Currently blocking roll.

Original change's description:
> Vulkan:Optimize SecondaryCommandBuffers
> 
> Optimize performance of SecondaryCommandBuffers and enable them as the
> default build option.
> To disable this set angle_enable_custom_vulkan_cmd_buffers=false in
> your build args.
> 
> This CL enhances the PoolAllocator to have a "fast" mode that can
> be enabled at class creation. This mode uses an alignment of 1 byte and
> enables a fastAllocation() call that avoids some bookkeeping overhead.
> The SecondaryCommandBuffer uses this fastAllocation() function.
> Furthermore the fast path of fast allocate, using the current page,
> is inlined for maximum speed.
> Jamie Madill also updated the SecondaryCommandBuffers to pre-allocate
> blocks so that the commands occur linearly in memory. This speeds up
> processing with improved cache coherency and minimizes overhead when
> recording commands.
> Also the core Draw functions and their state updates are all inlined
> as well as the common functions to initialize commands and to copy
> command pointer data.
> 
> This change also includes some new, custom commands. One is
> imageBarrier that is a specialized version of pipelineBarrier that only
> performs a single image layout transition.
> There are customized versions of various Draw commands to minimize
> copying of parameters.
> There are also specialized commands to bind[Graphics|Compute]Pipeline
> that have the pipeline type built in to the command.
> More custom commands and command data size optimizations will be made
> in follow-on commits.
> 
> Bug: angleproject:3136
> Change-Id: I35453cc2656bc8c51f0d84d1adef106900aca9a5
> Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/1497418
> Commit-Queue: Tobin Ehlis <tobine@google.com>
> Reviewed-by: Jamie Madill <jmadill@chromium.org>

TBR=tobine@google.com,syoussefi@chromium.org,jmadill@chromium.org

Change-Id: I1c0bfe864ff343eb8ea6c88556523f8715c981d5
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Bug: angleproject:3136
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/1535998
Reviewed-by: Jamie Madill <jmadill@chromium.org>
Commit-Queue: Jamie Madill <jmadill@chromium.org>
diff --git a/gni/angle.gni b/gni/angle.gni
index 9e76b75..24732c0 100644
--- a/gni/angle.gni
+++ b/gni/angle.gni
@@ -86,7 +86,7 @@
     angle_vulkan_conformant_configs_only = is_official_build
 
     # Enable custom (cpu-side) secondary command buffers
-    angle_enable_custom_vulkan_cmd_buffers = true
+    angle_enable_custom_vulkan_cmd_buffers = false
   }
 }
 
diff --git a/src/common/PoolAlloc.cpp b/src/common/PoolAlloc.cpp
index 3c2979f..a340f08 100644
--- a/src/common/PoolAlloc.cpp
+++ b/src/common/PoolAlloc.cpp
@@ -15,7 +15,6 @@
 
 #include "common/angleutils.h"
 #include "common/debug.h"
-#include "common/mathutil.h"
 #include "common/platform.h"
 #include "common/tls.h"
 
@@ -37,48 +36,43 @@
 #endif
       mLocked(false)
 {
-    if (mAlignment == 1)
-    {
-        // This is a special fast-path where fastAllocation() is enabled
-        mAlignmentMask = 0;
-        mHeaderSkip    = sizeof(Header);
-    }
-    else
-    {
-        //
-        // Adjust mAlignment to be at least pointer aligned and
-        // power of 2.
-        //
-        size_t minAlign = sizeof(void *);
-        mAlignment &= ~(minAlign - 1);
-        if (mAlignment < minAlign)
-            mAlignment = minAlign;
-        mAlignment     = gl::ceilPow2(mAlignment);
-        mAlignmentMask = mAlignment - 1;
+    //
+    // Adjust mAlignment to be at least pointer aligned and
+    // power of 2.
+    //
+    size_t minAlign = sizeof(void *);
+    mAlignment &= ~(minAlign - 1);
+    if (mAlignment < minAlign)
+        mAlignment = minAlign;
+    size_t a = 1;
+    while (a < mAlignment)
+        a <<= 1;
+    mAlignment     = a;
+    mAlignmentMask = a - 1;
 
 #if !defined(ANGLE_DISABLE_POOL_ALLOC)
-        //
-        // Align header skip
-        //
-        mHeaderSkip = minAlign;
-        if (mHeaderSkip < sizeof(Header))
-        {
-            mHeaderSkip = rx::roundUp(sizeof(Header), mAlignment);
-        }
-    }
     //
     // Don't allow page sizes we know are smaller than all common
     // OS page sizes.
     //
     if (mPageSize < 4 * 1024)
         mPageSize = 4 * 1024;
+
     //
     // A large mCurrentPageOffset indicates a new page needs to
     // be obtained to allocate memory.
     //
     mCurrentPageOffset = mPageSize;
-#else  // !defined(ANGLE_DISABLE_POOL_ALLOC)
+
+    //
+    // Align header skip
+    //
+    mHeaderSkip = minAlign;
+    if (mHeaderSkip < sizeof(Header))
+    {
+        mHeaderSkip = (sizeof(Header) + mAlignmentMask) & ~mAlignmentMask;
     }
+#else  // !defined(ANGLE_DISABLE_POOL_ALLOC)
     mStack.push_back({});
 #endif
 }
@@ -268,21 +262,7 @@
             reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(memory) + mHeaderSkip);
         return std::align(mAlignment, numBytes, unalignedPtr, allocationSize);
     }
-    unsigned char *newPageAddr =
-        static_cast<unsigned char *>(allocateNewPage(numBytes, allocationSize));
-    return initializeAllocation(mInUseList, newPageAddr, numBytes);
-#else  // !defined(ANGLE_DISABLE_POOL_ALLOC)
-    void *alloc = malloc(numBytes + mAlignmentMask);
-    mStack.back().push_back(alloc);
 
-    intptr_t intAlloc = reinterpret_cast<intptr_t>(alloc);
-    intAlloc          = rx::roundUp(intAlloc, mAlignment);
-    return reinterpret_cast<void *>(intAlloc);
-#endif
-}
-
-void *PoolAllocator::allocateNewPage(size_t numBytes, size_t allocationSize)
-{
     //
     // Need a simple page to allocate from.
     //
@@ -298,13 +278,22 @@
         if (memory == 0)
             return 0;
     }
+
     // Use placement-new to initialize header
     new (memory) Header(mInUseList, 1);
     mInUseList = memory;
 
     unsigned char *ret = reinterpret_cast<unsigned char *>(mInUseList) + mHeaderSkip;
     mCurrentPageOffset = (mHeaderSkip + allocationSize + mAlignmentMask) & ~mAlignmentMask;
-    return ret;
+    return initializeAllocation(mInUseList, ret, numBytes);
+#else  // !defined(ANGLE_DISABLE_POOL_ALLOC)
+    void *alloc = malloc(numBytes + mAlignmentMask);
+    mStack.back().push_back(alloc);
+
+    intptr_t intAlloc = reinterpret_cast<intptr_t>(alloc);
+    intAlloc          = (intAlloc + mAlignmentMask) & ~mAlignmentMask;
+    return reinterpret_cast<void *>(intAlloc);
+#endif
 }
 
 void PoolAllocator::lock()
diff --git a/src/common/PoolAlloc.h b/src/common/PoolAlloc.h
index 1955fc3..90d1653 100644
--- a/src/common/PoolAlloc.h
+++ b/src/common/PoolAlloc.h
@@ -38,7 +38,6 @@
 #include <vector>
 
 #include "angleutils.h"
-#include "common/debug.h"
 
 namespace angle
 {
@@ -124,10 +123,6 @@
 {
   public:
     static const int kDefaultAlignment = 16;
-    //
-    // Create PoolAllocator. If alignment is be set to 1 byte then fastAllocate()
-    //  function can be used to make allocations with less overhead.
-    //
     PoolAllocator(int growthIncrement = 8 * 1024, int allocationAlignment = kDefaultAlignment);
 
     //
@@ -159,32 +154,6 @@
     void *allocate(size_t numBytes);
 
     //
-    // Call fastAllocate() for a faster allocate function that does minimal bookkeeping
-    // preCondition: Allocator must have been created w/ alignment of 1
-    ANGLE_INLINE uint8_t *fastAllocate(size_t numBytes)
-    {
-#if defined(ANGLE_DISABLE_POOL_ALLOC)
-        return allocate(numBytes);
-#endif
-        ASSERT(mAlignment == 1);
-        // No multi-page allocations
-        ASSERT(numBytes <= (mPageSize - mHeaderSkip));
-        //
-        // Do the allocation, most likely case inline first, for efficiency.
-        //
-        if (numBytes <= mPageSize - mCurrentPageOffset)
-        {
-            //
-            // Safe to allocate from mCurrentPageOffset.
-            //
-            uint8_t *memory = reinterpret_cast<uint8_t *>(mInUseList) + mCurrentPageOffset;
-            mCurrentPageOffset += numBytes;
-            return memory;
-        }
-        return reinterpret_cast<uint8_t *>(allocateNewPage(numBytes, numBytes));
-    }
-
-    //
     // There is no deallocate.  The point of this class is that
     // deallocation can be skipped by the user of it, as the model
     // of use is to simultaneously deallocate everything at once
@@ -236,8 +205,6 @@
     };
     using AllocStack = std::vector<AllocState>;
 
-    // Slow path of allocation when we have to get a new page.
-    void *allocateNewPage(size_t numBytes, size_t allocationSize);
     // Track allocations if and only if we're using guard blocks
     void *initializeAllocation(Header *block, unsigned char *memory, size_t numBytes)
     {
diff --git a/src/libANGLE/renderer/vulkan/CommandGraph.cpp b/src/libANGLE/renderer/vulkan/CommandGraph.cpp
index c6fa205..4fb85c6 100644
--- a/src/libANGLE/renderer/vulkan/CommandGraph.cpp
+++ b/src/libANGLE/renderer/vulkan/CommandGraph.cpp
@@ -139,9 +139,10 @@
 }
 
 #if ANGLE_USE_CUSTOM_VULKAN_CMD_BUFFERS
-constexpr VkSubpassContents kRenderPassContents = VK_SUBPASS_CONTENTS_INLINE;
+static constexpr VkSubpassContents kRenderPassContents = VK_SUBPASS_CONTENTS_INLINE;
 #else
-constexpr VkSubpassContents kRenderPassContents = VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS;
+static constexpr VkSubpassContents kRenderPassContents =
+    VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS;
 #endif
 
 // Helpers to unify executeCommands call based on underlying cmd buffer type
@@ -302,6 +303,7 @@
 CommandGraphNode::~CommandGraphNode()
 {
     mRenderPassFramebuffer.setHandle(VK_NULL_HANDLE);
+
     // Command buffers are managed by the command pool, so don't need to be freed.
     mOutsideRenderPassCommands.releaseHandle();
     mInsideRenderPassCommands.releaseHandle();
@@ -501,6 +503,7 @@
                 RenderPass *renderPass = nullptr;
                 ANGLE_TRY(renderPassCache->getCompatibleRenderPass(context, serial, mRenderPassDesc,
                                                                    &renderPass));
+
                 ANGLE_VK_TRY(context, mInsideRenderPassCommands.end());
 
                 VkRenderPassBeginInfo beginInfo = {};
@@ -631,10 +634,7 @@
     : mEnableGraphDiagnostics(enableGraphDiagnostics),
       mPoolAllocator(poolAllocator),
       mLastBarrierIndex(kInvalidNodeIndex)
-{
-    // Push so that allocations made from here will be recycled in clear() below.
-    mPoolAllocator->push();
-}
+{}
 
 CommandGraph::~CommandGraph()
 {
@@ -776,12 +776,6 @@
 void CommandGraph::clear()
 {
     mLastBarrierIndex = kInvalidNodeIndex;
-    // Release cmd graph pool memory now that cmds are submitted
-    // NOTE: This frees all memory since last push. Right now only the CommandGraph
-    //  will push the allocator (at creation and below). If other people start
-    //  pushing the allocator this (and/or the allocator) will need to be updated.
-    mPoolAllocator->pop();
-    mPoolAllocator->push();
 
     // TODO(jmadill): Use pool allocator for performance. http://anglebug.com/2951
     for (CommandGraphNode *node : mNodes)
diff --git a/src/libANGLE/renderer/vulkan/CommandGraph.h b/src/libANGLE/renderer/vulkan/CommandGraph.h
index d8dd133..4548789 100644
--- a/src/libANGLE/renderer/vulkan/CommandGraph.h
+++ b/src/libANGLE/renderer/vulkan/CommandGraph.h
@@ -24,7 +24,6 @@
 
 namespace vk
 {
-
 enum class VisitedState
 {
     Unvisited,
@@ -120,11 +119,9 @@
     static void SetHappensBeforeDependencies(CommandGraphNode **beforeNodes,
                                              size_t beforeNodesCount,
                                              CommandGraphNode *afterNode);
-
     static void SetHappensBeforeDependencies(CommandGraphNode *beforeNode,
                                              CommandGraphNode **afterNodes,
                                              size_t afterNodesCount);
-
     bool hasParents() const;
     bool hasChildren() const { return mHasChildren; }
 
diff --git a/src/libANGLE/renderer/vulkan/ContextVk.cpp b/src/libANGLE/renderer/vulkan/ContextVk.cpp
index 41ac026..035d577 100644
--- a/src/libANGLE/renderer/vulkan/ContextVk.cpp
+++ b/src/libANGLE/renderer/vulkan/ContextVk.cpp
@@ -369,7 +369,9 @@
 
         mGraphicsPipelineTransition.reset();
     }
-    commandBuffer->bindGraphicsPipeline(mCurrentPipeline->getPipeline());
+
+    commandBuffer->bindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, mCurrentPipeline->getPipeline());
+
     // Update the queue serial for the pipeline object.
     ASSERT(mCurrentPipeline && mCurrentPipeline->valid());
     mCurrentPipeline->updateSerial(mRenderer->getCurrentQueueSerial());
@@ -447,8 +449,8 @@
                                     GLint first,
                                     GLsizei count)
 {
-    CommandBufferT *commandBuffer = nullptr;
-    uint32_t clampedVertexCount   = gl::GetClampedVertexCount<uint32_t>(count);
+    CommandBufferT *commandBuffer    = nullptr;
+    uint32_t clampedVertexCount      = gl::GetClampedVertexCount<uint32_t>(count);
 
     if (mode == gl::PrimitiveMode::LineLoop)
     {
@@ -460,7 +462,7 @@
     {
         ANGLE_TRY(setupDraw(context, mode, first, count, 1, gl::DrawElementsType::InvalidEnum,
                             nullptr, mNonIndexedDirtyBitsMask, &commandBuffer));
-        commandBuffer->draw(clampedVertexCount, first);
+        commandBuffer->draw(clampedVertexCount, 1, first, 0);
     }
 
     return angle::Result::Continue;
@@ -482,7 +484,7 @@
     CommandBufferT *commandBuffer = nullptr;
     ANGLE_TRY(setupDraw(context, mode, first, count, instances, gl::DrawElementsType::InvalidEnum,
                         nullptr, mNonIndexedDirtyBitsMask, &commandBuffer));
-    commandBuffer->drawInstanced(gl::GetClampedVertexCount<uint32_t>(count), instances, first);
+    commandBuffer->draw(gl::GetClampedVertexCount<uint32_t>(count), instances, first, 0);
     return angle::Result::Continue;
 }
 
@@ -501,7 +503,7 @@
     else
     {
         ANGLE_TRY(setupIndexedDraw(context, mode, count, 1, type, indices, &commandBuffer));
-        commandBuffer->drawIndexed(count);
+        commandBuffer->drawIndexed(count, 1, 0, 0, 0);
     }
 
     return angle::Result::Continue;
@@ -523,7 +525,7 @@
 
     CommandBufferT *commandBuffer = nullptr;
     ANGLE_TRY(setupIndexedDraw(context, mode, count, instances, type, indices, &commandBuffer));
-    commandBuffer->drawIndexedInstanced(count, instances);
+    commandBuffer->drawIndexed(count, instances, 0, 0, 0);
     return angle::Result::Continue;
 }
 
diff --git a/src/libANGLE/renderer/vulkan/FramebufferVk.cpp b/src/libANGLE/renderer/vulkan/FramebufferVk.cpp
index 21a57a7..ef371a9 100644
--- a/src/libANGLE/renderer/vulkan/FramebufferVk.cpp
+++ b/src/libANGLE/renderer/vulkan/FramebufferVk.cpp
@@ -424,7 +424,7 @@
     VkImageAspectFlags aspectMask =
         vk::GetDepthStencilAspectFlagsForCopy(blitDepthBuffer, blitStencilBuffer);
 
-    CommandBufferT *commandBuffer = nullptr;
+    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.
-    CommandBufferT *commandBuffer = nullptr;
+    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);
 
-    CommandBufferT *commandBuffer = nullptr;
+    CommandBufferT *commandBuffer;
     ANGLE_TRY(mFramebuffer.recordCommands(contextVk, &commandBuffer));
 
     const vk::Format &readImageFormat = readRenderTarget->getImageFormat();
@@ -903,8 +903,8 @@
 
     // This command can only happen inside a render pass, so obtain one if its already happening
     // or create a new one if not.
-    CommandBufferT *commandBuffer = nullptr;
-    vk::RecordingMode mode        = vk::RecordingMode::Start;
+    CommandBufferT *commandBuffer    = nullptr;
+    vk::RecordingMode mode           = vk::RecordingMode::Start;
     ANGLE_TRY(getCommandBufferForDraw(contextVk, &commandBuffer, &mode));
 
     // The array layer is offset by the ImageView. So we shouldn't need to set a base array layer.
diff --git a/src/libANGLE/renderer/vulkan/RendererVk.cpp b/src/libANGLE/renderer/vulkan/RendererVk.cpp
index c3b7fb4..de1f8db 100644
--- a/src/libANGLE/renderer/vulkan/RendererVk.cpp
+++ b/src/libANGLE/renderer/vulkan/RendererVk.cpp
@@ -506,7 +506,7 @@
       mCurrentQueueSerial(mQueueSerialFactory.generate()),
       mDeviceLost(false),
       mPipelineCacheVkUpdateTimeout(kPipelineCacheVkUpdatePeriod),
-      mPoolAllocator(kDefaultPoolAllocatorPageSize, 1),
+      mPoolAllocator(kDefaultPoolAllocatorPageSize),
       mCommandGraph(kEnableCommandGraphDiagnostics, &mPoolAllocator),
       mGpuEventsEnabled(false),
       mGpuClockSync{std::numeric_limits<double>::max(), std::numeric_limits<double>::max()},
diff --git a/src/libANGLE/renderer/vulkan/SecondaryCommandBuffer.cpp b/src/libANGLE/renderer/vulkan/SecondaryCommandBuffer.cpp
index 88a476a..a0ccc7f 100644
--- a/src/libANGLE/renderer/vulkan/SecondaryCommandBuffer.cpp
+++ b/src/libANGLE/renderer/vulkan/SecondaryCommandBuffer.cpp
@@ -14,6 +14,102 @@
 {
 namespace vk
 {
+
+// Allocate/initialize memory for the command and return pointer to Cmd Header
+template <class StructType>
+StructType *SecondaryCommandBuffer::initCommand(CommandID cmdID, size_t variableSize)
+{
+    size_t paramSize      = sizeof(StructType);
+    size_t completeSize   = sizeof(CommandHeader) + paramSize + variableSize;
+    CommandHeader *header = static_cast<CommandHeader *>(mAllocator->allocate(completeSize));
+    // Update cmd ID in header
+    header->id   = cmdID;
+    header->next = nullptr;
+    // Update mHead ptr
+    mHead = (mHead == nullptr) ? header : mHead;
+    // Update prev cmd's "next" ptr and mLast ptr
+    if (mLast)
+    {
+        mLast->next = header;
+    }
+    // Update mLast ptr
+    mLast = header;
+
+    uint8_t *fixedParamPtr = reinterpret_cast<uint8_t *>(header) + sizeof(CommandHeader);
+    mPtrCmdData            = fixedParamPtr + sizeof(StructType);
+    return reinterpret_cast<StructType *>(fixedParamPtr);
+}
+
+template <class PtrType>
+void SecondaryCommandBuffer::storePointerParameter(const PtrType *paramData,
+                                                   const PtrType **writePtr,
+                                                   size_t sizeInBytes)
+{
+    *writePtr = reinterpret_cast<const PtrType *>(mPtrCmdData);
+    memcpy(mPtrCmdData, paramData, sizeInBytes);
+    mPtrCmdData += sizeInBytes;
+}
+
+void SecondaryCommandBuffer::bindDescriptorSets(VkPipelineBindPoint bindPoint,
+                                                const PipelineLayout &layout,
+                                                uint32_t firstSet,
+                                                uint32_t descriptorSetCount,
+                                                const VkDescriptorSet *descriptorSets,
+                                                uint32_t dynamicOffsetCount,
+                                                const uint32_t *dynamicOffsets)
+{
+    size_t descSize   = descriptorSetCount * sizeof(VkDescriptorSet);
+    size_t offsetSize = dynamicOffsetCount * sizeof(uint32_t);
+    size_t varSize    = descSize + offsetSize;
+    BindDescriptorSetParams *paramStruct =
+        initCommand<BindDescriptorSetParams>(CommandID::BindDescriptorSets, varSize);
+    // Copy params into memory
+    paramStruct->bindPoint          = bindPoint;
+    paramStruct->layout             = layout.getHandle();
+    paramStruct->firstSet           = firstSet;
+    paramStruct->descriptorSetCount = descriptorSetCount;
+    paramStruct->dynamicOffsetCount = dynamicOffsetCount;
+    // Copy variable sized data
+    storePointerParameter(descriptorSets, &paramStruct->descriptorSets, descSize);
+    storePointerParameter(dynamicOffsets, &paramStruct->dynamicOffsets, offsetSize);
+}
+
+void SecondaryCommandBuffer::bindIndexBuffer(const Buffer &buffer,
+                                             VkDeviceSize offset,
+                                             VkIndexType indexType)
+{
+    BindIndexBufferParams *paramStruct =
+        initCommand<BindIndexBufferParams>(CommandID::BindIndexBuffer, 0);
+    paramStruct->buffer    = buffer.getHandle();
+    paramStruct->offset    = offset;
+    paramStruct->indexType = indexType;
+}
+
+void SecondaryCommandBuffer::bindPipeline(VkPipelineBindPoint pipelineBindPoint,
+                                          const Pipeline &pipeline)
+{
+    BindPipelineParams *paramStruct = initCommand<BindPipelineParams>(CommandID::BindPipeline, 0);
+    paramStruct->pipelineBindPoint  = pipelineBindPoint;
+    paramStruct->pipeline           = pipeline.getHandle();
+}
+
+void SecondaryCommandBuffer::bindVertexBuffers(uint32_t firstBinding,
+                                               uint32_t bindingCount,
+                                               const VkBuffer *buffers,
+                                               const VkDeviceSize *offsets)
+{
+    size_t buffSize   = bindingCount * sizeof(VkBuffer);
+    size_t offsetSize = bindingCount * sizeof(VkDeviceSize);
+    BindVertexBuffersParams *paramStruct =
+        initCommand<BindVertexBuffersParams>(CommandID::BindVertexBuffers, buffSize + offsetSize);
+    // Copy params
+    paramStruct->firstBinding = firstBinding;
+    paramStruct->bindingCount = bindingCount;
+    // Copy variable sized data
+    storePointerParameter(buffers, &paramStruct->buffers, buffSize);
+    storePointerParameter(offsets, &paramStruct->offsets, offsetSize);
+}
+
 void SecondaryCommandBuffer::blitImage(const Image &srcImage,
                                        VkImageLayout srcImageLayout,
                                        const Image &dstImage,
@@ -209,11 +305,37 @@
     storePointerParameter(scissors, &paramStruct->scissors, scissorSize);
 }
 
+void SecondaryCommandBuffer::draw(uint32_t vertexCount,
+                                  uint32_t instanceCount,
+                                  uint32_t firstVertex,
+                                  uint32_t firstInstance)
+{
+    DrawParams *paramStruct    = initCommand<DrawParams>(CommandID::Draw, 0);
+    paramStruct->vertexCount   = vertexCount;
+    paramStruct->instanceCount = instanceCount;
+    paramStruct->firstVertex   = firstVertex;
+    paramStruct->firstInstance = firstInstance;
+}
+
+void SecondaryCommandBuffer::drawIndexed(uint32_t indexCount,
+                                         uint32_t instanceCount,
+                                         uint32_t firstIndex,
+                                         int32_t vertexOffset,
+                                         uint32_t firstInstance)
+{
+    DrawIndexedParams *paramStruct = initCommand<DrawIndexedParams>(CommandID::DrawIndexed, 0);
+    paramStruct->indexCount        = indexCount;
+    paramStruct->instanceCount     = instanceCount;
+    paramStruct->firstIndex        = firstIndex;
+    paramStruct->vertexOffset      = vertexOffset;
+    paramStruct->firstInstance     = firstInstance;
+}
+
 void SecondaryCommandBuffer::dispatch(uint32_t groupCountX,
                                       uint32_t groupCountY,
                                       uint32_t groupCountZ)
 {
-    DispatchParams *paramStruct = initCommand<DispatchParams>(CommandID::Dispatch);
+    DispatchParams *paramStruct = initCommand<DispatchParams>(CommandID::Dispatch, 0);
     paramStruct->groupCountX    = groupCountX;
     paramStruct->groupCountY    = groupCountY;
     paramStruct->groupCountZ    = groupCountZ;
@@ -233,10 +355,9 @@
     size_t buffBarrierSize             = bufferMemoryBarrierCount * sizeof(VkBufferMemoryBarrier);
     size_t imgBarrierSize              = imageMemoryBarrierCount * sizeof(VkImageMemoryBarrier);
     PipelineBarrierParams *paramStruct = initCommand<PipelineBarrierParams>(
-        CommandID::PipelineBarrier, memBarrierSize + buffBarrierSize + imgBarrierSize);
+        CommandID::PipelinBarrier, memBarrierSize + buffBarrierSize + imgBarrierSize);
     paramStruct->srcStageMask             = srcStageMask;
     paramStruct->dstStageMask             = dstStageMask;
-    paramStruct->dependencyFlags          = dependencyFlags;
     paramStruct->memoryBarrierCount       = memoryBarrierCount;
     paramStruct->bufferMemoryBarrierCount = bufferMemoryBarrierCount;
     paramStruct->imageMemoryBarrierCount  = imageMemoryBarrierCount;
@@ -247,26 +368,16 @@
     storePointerParameter(imageMemoryBarriers, &paramStruct->imageMemoryBarriers, imgBarrierSize);
 }
 
-void SecondaryCommandBuffer::imageBarrier(VkPipelineStageFlags srcStageMask,
-                                          VkPipelineStageFlags dstStageMask,
-                                          VkImageMemoryBarrier *imageMemoryBarrier)
-{
-    ImageBarrierParams *paramStruct = initCommand<ImageBarrierParams>(CommandID::ImageBarrier);
-    paramStruct->srcStageMask       = srcStageMask;
-    paramStruct->dstStageMask       = dstStageMask;
-    paramStruct->imageMemoryBarrier = *imageMemoryBarrier;
-}
-
 void SecondaryCommandBuffer::setEvent(VkEvent event, VkPipelineStageFlags stageMask)
 {
-    SetEventParams *paramStruct = initCommand<SetEventParams>(CommandID::SetEvent);
+    SetEventParams *paramStruct = initCommand<SetEventParams>(CommandID::SetEvent, 0);
     paramStruct->event          = event;
     paramStruct->stageMask      = stageMask;
 }
 
 void SecondaryCommandBuffer::resetEvent(VkEvent event, VkPipelineStageFlags stageMask)
 {
-    ResetEventParams *paramStruct = initCommand<ResetEventParams>(CommandID::ResetEvent);
+    ResetEventParams *paramStruct = initCommand<ResetEventParams>(CommandID::ResetEvent, 0);
     paramStruct->event            = event;
     paramStruct->stageMask        = stageMask;
 }
@@ -307,7 +418,7 @@
                                             uint32_t queryCount)
 {
     ResetQueryPoolParams *paramStruct =
-        initCommand<ResetQueryPoolParams>(CommandID::ResetQueryPool);
+        initCommand<ResetQueryPoolParams>(CommandID::ResetQueryPool, 0);
     paramStruct->queryPool  = queryPool;
     paramStruct->firstQuery = firstQuery;
     paramStruct->queryCount = queryCount;
@@ -317,7 +428,7 @@
                                         uint32_t query,
                                         VkQueryControlFlags flags)
 {
-    BeginQueryParams *paramStruct = initCommand<BeginQueryParams>(CommandID::BeginQuery);
+    BeginQueryParams *paramStruct = initCommand<BeginQueryParams>(CommandID::BeginQuery, 0);
     paramStruct->queryPool        = queryPool;
     paramStruct->query            = query;
     paramStruct->flags            = flags;
@@ -325,7 +436,7 @@
 
 void SecondaryCommandBuffer::endQuery(VkQueryPool queryPool, uint32_t query)
 {
-    EndQueryParams *paramStruct = initCommand<EndQueryParams>(CommandID::EndQuery);
+    EndQueryParams *paramStruct = initCommand<EndQueryParams>(CommandID::EndQuery, 0);
     paramStruct->queryPool      = queryPool;
     paramStruct->query          = query;
 }
@@ -335,276 +446,225 @@
                                             uint32_t query)
 {
     WriteTimestampParams *paramStruct =
-        initCommand<WriteTimestampParams>(CommandID::WriteTimestamp);
+        initCommand<WriteTimestampParams>(CommandID::WriteTimestamp, 0);
     paramStruct->pipelineStage = pipelineStage;
     paramStruct->queryPool     = queryPool;
     paramStruct->query         = query;
 }
 
-ANGLE_INLINE const CommandHeader *NextCommand(const CommandHeader *command)
-{
-    return reinterpret_cast<const CommandHeader *>(reinterpret_cast<const uint8_t *>(command) +
-                                                   command->size);
-}
-
 // Parse the cmds in this cmd buffer into given primary cmd buffer
 void SecondaryCommandBuffer::executeCommands(VkCommandBuffer cmdBuffer)
 {
-    for (const CommandHeader *command : mCommands)
+    for (CommandHeader *currentCommand = mHead; currentCommand;
+         currentCommand                = currentCommand->next)
     {
-        for (const CommandHeader *currentCommand                      = command;
-             currentCommand->id != CommandID::Invalid; currentCommand = NextCommand(currentCommand))
+        switch (currentCommand->id)
         {
-            switch (currentCommand->id)
+            case CommandID::BindDescriptorSets:
             {
-                case CommandID::BeginQuery:
-                {
-                    const BeginQueryParams *params = getParamPtr<BeginQueryParams>(currentCommand);
-                    vkCmdBeginQuery(cmdBuffer, params->queryPool, params->query, params->flags);
-                    break;
-                }
-                case CommandID::BindComputePipeline:
-                {
-                    const BindPipelineParams *params =
-                        getParamPtr<BindPipelineParams>(currentCommand);
-                    vkCmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, params->pipeline);
-                    break;
-                }
-                case CommandID::BindDescriptorSets:
-                {
-                    const BindDescriptorSetParams *params =
-                        getParamPtr<BindDescriptorSetParams>(currentCommand);
-                    vkCmdBindDescriptorSets(cmdBuffer, params->bindPoint, params->layout,
-                                            params->firstSet, params->descriptorSetCount,
-                                            params->descriptorSets, params->dynamicOffsetCount,
-                                            params->dynamicOffsets);
-                    break;
-                }
-                case CommandID::BindGraphicsPipeline:
-                {
-                    const BindPipelineParams *params =
-                        getParamPtr<BindPipelineParams>(currentCommand);
-                    vkCmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, params->pipeline);
-                    break;
-                }
-                case CommandID::BindIndexBuffer:
-                {
-                    const BindIndexBufferParams *params =
-                        getParamPtr<BindIndexBufferParams>(currentCommand);
-                    vkCmdBindIndexBuffer(cmdBuffer, params->buffer, params->offset,
-                                         params->indexType);
-                    break;
-                }
-                case CommandID::BindVertexBuffers:
-                {
-                    const BindVertexBuffersParams *params =
-                        getParamPtr<BindVertexBuffersParams>(currentCommand);
-                    const VkBuffer *buffers =
-                        Offset<VkBuffer>(params, sizeof(BindVertexBuffersParams));
-                    const VkDeviceSize *offsets =
-                        Offset<VkDeviceSize>(buffers, sizeof(VkBuffer) * params->bindingCount);
-                    vkCmdBindVertexBuffers(cmdBuffer, 0, params->bindingCount, buffers, offsets);
-                    break;
-                }
-                case CommandID::BlitImage:
-                {
-                    const BlitImageParams *params = getParamPtr<BlitImageParams>(currentCommand);
-                    vkCmdBlitImage(cmdBuffer, params->srcImage, params->srcImageLayout,
-                                   params->dstImage, params->dstImageLayout, params->regionCount,
-                                   params->pRegions, params->filter);
-                    break;
-                }
-                case CommandID::ClearAttachments:
-                {
-                    const ClearAttachmentsParams *params =
-                        getParamPtr<ClearAttachmentsParams>(currentCommand);
-                    vkCmdClearAttachments(cmdBuffer, params->attachmentCount, params->attachments,
-                                          params->rectCount, params->rects);
-                    break;
-                }
-                case CommandID::ClearColorImage:
-                {
-                    const ClearColorImageParams *params =
-                        getParamPtr<ClearColorImageParams>(currentCommand);
-                    vkCmdClearColorImage(cmdBuffer, params->image, params->imageLayout,
-                                         &params->color, params->rangeCount, params->ranges);
-                    break;
-                }
-                case CommandID::ClearDepthStencilImage:
-                {
-                    const ClearDepthStencilImageParams *params =
-                        getParamPtr<ClearDepthStencilImageParams>(currentCommand);
-                    vkCmdClearDepthStencilImage(cmdBuffer, params->image, params->imageLayout,
-                                                &params->depthStencil, params->rangeCount,
-                                                params->ranges);
-                    break;
-                }
-                case CommandID::CopyBuffer:
-                {
-                    const CopyBufferParams *params = getParamPtr<CopyBufferParams>(currentCommand);
-                    vkCmdCopyBuffer(cmdBuffer, params->srcBuffer, params->destBuffer,
-                                    params->regionCount, params->regions);
-                    break;
-                }
-                case CommandID::CopyBufferToImage:
-                {
-                    const CopyBufferToImageParams *params =
-                        getParamPtr<CopyBufferToImageParams>(currentCommand);
-                    vkCmdCopyBufferToImage(cmdBuffer, params->srcBuffer, params->dstImage,
-                                           params->dstImageLayout, params->regionCount,
-                                           params->regions);
-                    break;
-                }
-                case CommandID::CopyImage:
-                {
-                    const CopyImageParams *params = getParamPtr<CopyImageParams>(currentCommand);
-                    vkCmdCopyImage(cmdBuffer, params->srcImage, params->srcImageLayout,
-                                   params->dstImage, params->dstImageLayout, params->regionCount,
-                                   params->regions);
-                    break;
-                }
-                case CommandID::CopyImageToBuffer:
-                {
-                    const CopyImageToBufferParams *params =
-                        getParamPtr<CopyImageToBufferParams>(currentCommand);
-                    vkCmdCopyImageToBuffer(cmdBuffer, params->srcImage, params->srcImageLayout,
-                                           params->dstBuffer, params->regionCount, params->regions);
-                    break;
-                }
-                case CommandID::Dispatch:
-                {
-                    const DispatchParams *params = getParamPtr<DispatchParams>(currentCommand);
-                    vkCmdDispatch(cmdBuffer, params->groupCountX, params->groupCountY,
-                                  params->groupCountZ);
-                    break;
-                }
-                case CommandID::Draw:
-                {
-                    const DrawParams *params = getParamPtr<DrawParams>(currentCommand);
-                    vkCmdDraw(cmdBuffer, params->vertexCount, 1, params->firstVertex, 0);
-                    break;
-                }
-                case CommandID::DrawIndexed:
-                {
-                    const DrawIndexedParams *params =
-                        getParamPtr<DrawIndexedParams>(currentCommand);
-                    vkCmdDrawIndexed(cmdBuffer, params->indexCount, 1, 0, 0, 0);
-                    break;
-                }
-                case CommandID::DrawIndexedInstanced:
-                {
-                    const DrawIndexedInstancedParams *params =
-                        getParamPtr<DrawIndexedInstancedParams>(currentCommand);
-                    vkCmdDrawIndexed(cmdBuffer, params->indexCount, params->instanceCount, 0, 0, 0);
-                    break;
-                }
-                case CommandID::DrawInstanced:
-                {
-                    const DrawInstancedParams *params =
-                        getParamPtr<DrawInstancedParams>(currentCommand);
-                    vkCmdDraw(cmdBuffer, params->vertexCount, params->instanceCount,
-                              params->firstVertex, 0);
-                    break;
-                }
-                case CommandID::EndQuery:
-                {
-                    const EndQueryParams *params = getParamPtr<EndQueryParams>(currentCommand);
-                    vkCmdEndQuery(cmdBuffer, params->queryPool, params->query);
-                    break;
-                }
-                case CommandID::ImageBarrier:
-                {
-                    const ImageBarrierParams *params =
-                        getParamPtr<ImageBarrierParams>(currentCommand);
-                    vkCmdPipelineBarrier(cmdBuffer, params->srcStageMask, params->dstStageMask, 0,
-                                         0, nullptr, 0, nullptr, 1, &params->imageMemoryBarrier);
-                    break;
-                }
-                case CommandID::PipelineBarrier:
-                {
-                    const PipelineBarrierParams *params =
-                        getParamPtr<PipelineBarrierParams>(currentCommand);
-                    vkCmdPipelineBarrier(
-                        cmdBuffer, params->srcStageMask, params->dstStageMask,
-                        params->dependencyFlags, params->memoryBarrierCount, params->memoryBarriers,
-                        params->bufferMemoryBarrierCount, params->bufferMemoryBarriers,
-                        params->imageMemoryBarrierCount, params->imageMemoryBarriers);
-                    break;
-                }
-                case CommandID::PushConstants:
-                {
-                    const PushConstantsParams *params =
-                        getParamPtr<PushConstantsParams>(currentCommand);
-                    vkCmdPushConstants(cmdBuffer, params->layout, params->flag, params->offset,
-                                       params->size, params->data);
-                    break;
-                }
-                case CommandID::ResetEvent:
-                {
-                    const ResetEventParams *params = getParamPtr<ResetEventParams>(currentCommand);
-                    vkCmdResetEvent(cmdBuffer, params->event, params->stageMask);
-                    break;
-                }
-                case CommandID::ResetQueryPool:
-                {
-                    const ResetQueryPoolParams *params =
-                        getParamPtr<ResetQueryPoolParams>(currentCommand);
-                    vkCmdResetQueryPool(cmdBuffer, params->queryPool, params->firstQuery,
-                                        params->queryCount);
-                    break;
-                }
-                case CommandID::SetEvent:
-                {
-                    const SetEventParams *params = getParamPtr<SetEventParams>(currentCommand);
-                    vkCmdSetEvent(cmdBuffer, params->event, params->stageMask);
-                    break;
-                }
-                case CommandID::SetScissor:
-                {
-                    const SetScissorParams *params = getParamPtr<SetScissorParams>(currentCommand);
-                    vkCmdSetScissor(cmdBuffer, params->firstScissor, params->scissorCount,
-                                    params->scissors);
-                    break;
-                }
-                case CommandID::SetViewport:
-                {
-                    const SetViewportParams *params =
-                        getParamPtr<SetViewportParams>(currentCommand);
-                    vkCmdSetViewport(cmdBuffer, params->firstViewport, params->viewportCount,
-                                     params->viewports);
-                    break;
-                }
-                case CommandID::UpdateBuffer:
-                {
-                    const UpdateBufferParams *params =
-                        getParamPtr<UpdateBufferParams>(currentCommand);
-                    vkCmdUpdateBuffer(cmdBuffer, params->buffer, params->dstOffset,
-                                      params->dataSize, params->data);
-                    break;
-                }
-                case CommandID::WaitEvents:
-                {
-                    const WaitEventsParams *params = getParamPtr<WaitEventsParams>(currentCommand);
-                    vkCmdWaitEvents(cmdBuffer, params->eventCount, params->events,
-                                    params->srcStageMask, params->dstStageMask,
-                                    params->memoryBarrierCount, params->memoryBarriers,
-                                    params->bufferMemoryBarrierCount, params->bufferMemoryBarriers,
-                                    params->imageMemoryBarrierCount, params->imageMemoryBarriers);
-                    break;
-                }
-                case CommandID::WriteTimestamp:
-                {
-                    const WriteTimestampParams *params =
-                        getParamPtr<WriteTimestampParams>(currentCommand);
-                    vkCmdWriteTimestamp(cmdBuffer, params->pipelineStage, params->queryPool,
-                                        params->query);
-                    break;
-                }
-                default:
-                {
-                    UNREACHABLE();
-                    break;
-                }
+                BindDescriptorSetParams *params =
+                    getParamPtr<BindDescriptorSetParams>(currentCommand);
+                vkCmdBindDescriptorSets(cmdBuffer, params->bindPoint, params->layout,
+                                        params->firstSet, params->descriptorSetCount,
+                                        params->descriptorSets, params->dynamicOffsetCount,
+                                        params->dynamicOffsets);
+                break;
+            }
+            case CommandID::BindIndexBuffer:
+            {
+                BindIndexBufferParams *params = getParamPtr<BindIndexBufferParams>(currentCommand);
+                vkCmdBindIndexBuffer(cmdBuffer, params->buffer, params->offset, params->indexType);
+                break;
+            }
+            case CommandID::BindPipeline:
+            {
+                BindPipelineParams *params = getParamPtr<BindPipelineParams>(currentCommand);
+                vkCmdBindPipeline(cmdBuffer, params->pipelineBindPoint, params->pipeline);
+                break;
+            }
+            case CommandID::BindVertexBuffers:
+            {
+                BindVertexBuffersParams *params =
+                    getParamPtr<BindVertexBuffersParams>(currentCommand);
+                vkCmdBindVertexBuffers(cmdBuffer, params->firstBinding, params->bindingCount,
+                                       params->buffers, params->offsets);
+                break;
+            }
+            case CommandID::BlitImage:
+            {
+                BlitImageParams *params = getParamPtr<BlitImageParams>(currentCommand);
+                vkCmdBlitImage(cmdBuffer, params->srcImage, params->srcImageLayout,
+                               params->dstImage, params->dstImageLayout, params->regionCount,
+                               params->pRegions, params->filter);
+                break;
+            }
+            case CommandID::CopyBuffer:
+            {
+                CopyBufferParams *params = getParamPtr<CopyBufferParams>(currentCommand);
+                vkCmdCopyBuffer(cmdBuffer, params->srcBuffer, params->destBuffer,
+                                params->regionCount, params->regions);
+                break;
+            }
+            case CommandID::CopyBufferToImage:
+            {
+                CopyBufferToImageParams *params =
+                    getParamPtr<CopyBufferToImageParams>(currentCommand);
+                vkCmdCopyBufferToImage(cmdBuffer, params->srcBuffer, params->dstImage,
+                                       params->dstImageLayout, params->regionCount,
+                                       params->regions);
+                break;
+            }
+            case CommandID::CopyImage:
+            {
+                CopyImageParams *params = getParamPtr<CopyImageParams>(currentCommand);
+                vkCmdCopyImage(cmdBuffer, params->srcImage, params->srcImageLayout,
+                               params->dstImage, params->dstImageLayout, params->regionCount,
+                               params->regions);
+                break;
+            }
+            case CommandID::CopyImageToBuffer:
+            {
+                CopyImageToBufferParams *params =
+                    getParamPtr<CopyImageToBufferParams>(currentCommand);
+                vkCmdCopyImageToBuffer(cmdBuffer, params->srcImage, params->srcImageLayout,
+                                       params->dstBuffer, params->regionCount, params->regions);
+                break;
+            }
+            case CommandID::ClearAttachments:
+            {
+                ClearAttachmentsParams *params =
+                    getParamPtr<ClearAttachmentsParams>(currentCommand);
+                vkCmdClearAttachments(cmdBuffer, params->attachmentCount, params->attachments,
+                                      params->rectCount, params->rects);
+                break;
+            }
+            case CommandID::ClearColorImage:
+            {
+                ClearColorImageParams *params = getParamPtr<ClearColorImageParams>(currentCommand);
+                vkCmdClearColorImage(cmdBuffer, params->image, params->imageLayout, &params->color,
+                                     params->rangeCount, params->ranges);
+                break;
+            }
+            case CommandID::ClearDepthStencilImage:
+            {
+                ClearDepthStencilImageParams *params =
+                    getParamPtr<ClearDepthStencilImageParams>(currentCommand);
+                vkCmdClearDepthStencilImage(cmdBuffer, params->image, params->imageLayout,
+                                            &params->depthStencil, params->rangeCount,
+                                            params->ranges);
+                break;
+            }
+            case CommandID::UpdateBuffer:
+            {
+                UpdateBufferParams *params = getParamPtr<UpdateBufferParams>(currentCommand);
+                vkCmdUpdateBuffer(cmdBuffer, params->buffer, params->dstOffset, params->dataSize,
+                                  params->data);
+                break;
+            }
+            case CommandID::PushConstants:
+            {
+                PushConstantsParams *params = getParamPtr<PushConstantsParams>(currentCommand);
+                vkCmdPushConstants(cmdBuffer, params->layout, params->flag, params->offset,
+                                   params->size, params->data);
+                break;
+            }
+            case CommandID::SetViewport:
+            {
+                SetViewportParams *params = getParamPtr<SetViewportParams>(currentCommand);
+                vkCmdSetViewport(cmdBuffer, params->firstViewport, params->viewportCount,
+                                 params->viewports);
+                break;
+            }
+            case CommandID::SetScissor:
+            {
+                SetScissorParams *params = getParamPtr<SetScissorParams>(currentCommand);
+                vkCmdSetScissor(cmdBuffer, params->firstScissor, params->scissorCount,
+                                params->scissors);
+                break;
+            }
+            case CommandID::Draw:
+            {
+                DrawParams *params = getParamPtr<DrawParams>(currentCommand);
+                vkCmdDraw(cmdBuffer, params->vertexCount, params->instanceCount,
+                          params->firstVertex, params->firstInstance);
+                break;
+            }
+            case CommandID::DrawIndexed:
+            {
+                DrawIndexedParams *params = getParamPtr<DrawIndexedParams>(currentCommand);
+                vkCmdDrawIndexed(cmdBuffer, params->indexCount, params->instanceCount,
+                                 params->firstIndex, params->vertexOffset, params->firstInstance);
+                break;
+            }
+            case CommandID::Dispatch:
+            {
+                DispatchParams *params = getParamPtr<DispatchParams>(currentCommand);
+                vkCmdDispatch(cmdBuffer, params->groupCountX, params->groupCountY,
+                              params->groupCountZ);
+                break;
+            }
+            case CommandID::PipelinBarrier:
+            {
+                PipelineBarrierParams *params = getParamPtr<PipelineBarrierParams>(currentCommand);
+                vkCmdPipelineBarrier(cmdBuffer, params->srcStageMask, params->dstStageMask,
+                                     params->dependencyFlags, params->memoryBarrierCount,
+                                     params->memoryBarriers, params->bufferMemoryBarrierCount,
+                                     params->bufferMemoryBarriers, params->imageMemoryBarrierCount,
+                                     params->imageMemoryBarriers);
+                break;
+            }
+            case CommandID::SetEvent:
+            {
+                SetEventParams *params = getParamPtr<SetEventParams>(currentCommand);
+                vkCmdSetEvent(cmdBuffer, params->event, params->stageMask);
+                break;
+            }
+            case CommandID::ResetEvent:
+            {
+                ResetEventParams *params = getParamPtr<ResetEventParams>(currentCommand);
+                vkCmdResetEvent(cmdBuffer, params->event, params->stageMask);
+                break;
+            }
+            case CommandID::WaitEvents:
+            {
+                WaitEventsParams *params = getParamPtr<WaitEventsParams>(currentCommand);
+                vkCmdWaitEvents(cmdBuffer, params->eventCount, params->events, params->srcStageMask,
+                                params->dstStageMask, params->memoryBarrierCount,
+                                params->memoryBarriers, params->bufferMemoryBarrierCount,
+                                params->bufferMemoryBarriers, params->imageMemoryBarrierCount,
+                                params->imageMemoryBarriers);
+                break;
+            }
+            case CommandID::ResetQueryPool:
+            {
+                ResetQueryPoolParams *params = getParamPtr<ResetQueryPoolParams>(currentCommand);
+                vkCmdResetQueryPool(cmdBuffer, params->queryPool, params->firstQuery,
+                                    params->queryCount);
+                break;
+            }
+            case CommandID::BeginQuery:
+            {
+                BeginQueryParams *params = getParamPtr<BeginQueryParams>(currentCommand);
+                vkCmdBeginQuery(cmdBuffer, params->queryPool, params->query, params->flags);
+                break;
+            }
+            case CommandID::EndQuery:
+            {
+                EndQueryParams *params = getParamPtr<EndQueryParams>(currentCommand);
+                vkCmdEndQuery(cmdBuffer, params->queryPool, params->query);
+                break;
+            }
+            case CommandID::WriteTimestamp:
+            {
+                WriteTimestampParams *params = getParamPtr<WriteTimestampParams>(currentCommand);
+                vkCmdWriteTimestamp(cmdBuffer, params->pipelineStage, params->queryPool,
+                                    params->query);
+                break;
+            }
+            default:
+            {
+                UNREACHABLE();
+                break;
             }
         }
     }
diff --git a/src/libANGLE/renderer/vulkan/SecondaryCommandBuffer.h b/src/libANGLE/renderer/vulkan/SecondaryCommandBuffer.h
index 3a52d5b..86661de 100644
--- a/src/libANGLE/renderer/vulkan/SecondaryCommandBuffer.h
+++ b/src/libANGLE/renderer/vulkan/SecondaryCommandBuffer.h
@@ -22,46 +22,40 @@
 namespace vk
 {
 
-enum class CommandID : uint16_t
+enum class CommandID
 {
-    // Invalid cmd used to mark end of sequence of commands
-    Invalid = 0,
-    BeginQuery,
-    BindComputePipeline,
-    BindDescriptorSets,
-    BindGraphicsPipeline,
-    BindIndexBuffer,
-    BindVertexBuffers,
-    BlitImage,
-    ClearAttachments,
-    ClearColorImage,
-    ClearDepthStencilImage,
-    CopyBuffer,
-    CopyBufferToImage,
-    CopyImage,
-    CopyImageToBuffer,
-    Dispatch,
-    Draw,
-    DrawIndexed,
-    DrawIndexedInstanced,
-    DrawInstanced,
-    EndQuery,
-    ImageBarrier,
-    PipelineBarrier,
-    PushConstants,
-    ResetEvent,
-    ResetQueryPool,
-    SetEvent,
-    SetScissor,
-    SetViewport,
-    UpdateBuffer,
-    WaitEvents,
-    WriteTimestamp,
+    // State update cmds
+    BindDescriptorSets     = 0,
+    BindIndexBuffer        = 1,
+    BindPipeline           = 2,
+    BindVertexBuffers      = 3,
+    BlitImage              = 4,
+    CopyBuffer             = 5,
+    CopyBufferToImage      = 6,
+    CopyImage              = 7,
+    CopyImageToBuffer      = 8,
+    ClearAttachments       = 9,
+    ClearColorImage        = 10,
+    ClearDepthStencilImage = 11,
+    UpdateBuffer           = 12,
+    PushConstants          = 13,
+    SetViewport            = 14,
+    SetScissor             = 15,
+    // Draw/dispatch cmds
+    Draw        = 16,
+    DrawIndexed = 17,
+    Dispatch    = 18,
+    // Sync & Query cmds
+    PipelinBarrier = 19,
+    ResetEvent     = 20,
+    SetEvent       = 21,
+    WaitEvents     = 22,
+    ResetQueryPool = 23,
+    BeginQuery     = 24,
+    EndQuery       = 25,
+    WriteTimestamp = 26,
 };
 
-#define VERIFY_4_BYTE_ALIGNMENT(StructName) \
-    static_assert((sizeof(StructName) % 4) == 0, "Check StructName alignment");
-
 // Structs to encapsulate parameters for different commands
 // This makes it easy to know the size of params & to copy params
 // TODO: Could optimize the size of some of these structs through bit-packing
@@ -76,7 +70,6 @@
     uint32_t dynamicOffsetCount;
     const uint32_t *dynamicOffsets;
 };
-VERIFY_4_BYTE_ALIGNMENT(BindDescriptorSetParams)
 
 struct BindIndexBufferParams
 {
@@ -84,20 +77,20 @@
     VkDeviceSize offset;
     VkIndexType indexType;
 };
-VERIFY_4_BYTE_ALIGNMENT(BindIndexBufferParams)
 
 struct BindPipelineParams
 {
+    VkPipelineBindPoint pipelineBindPoint;
     VkPipeline pipeline;
 };
-VERIFY_4_BYTE_ALIGNMENT(BindPipelineParams)
 
 struct BindVertexBuffersParams
 {
-    // ANGLE always has firstBinding of 0 so not storing that currently
+    uint32_t firstBinding;
     uint32_t bindingCount;
+    const VkBuffer *buffers;
+    const VkDeviceSize *offsets;
 };
-VERIFY_4_BYTE_ALIGNMENT(BindVertexBuffersParams)
 
 struct BlitImageParams
 {
@@ -109,7 +102,6 @@
     const VkImageBlit *pRegions;
     VkFilter filter;
 };
-VERIFY_4_BYTE_ALIGNMENT(BlitImageParams)
 
 struct CopyBufferParams
 {
@@ -118,7 +110,6 @@
     uint32_t regionCount;
     const VkBufferCopy *regions;
 };
-VERIFY_4_BYTE_ALIGNMENT(CopyBufferParams)
 
 struct CopyBufferToImageParams
 {
@@ -128,7 +119,6 @@
     uint32_t regionCount;
     const VkBufferImageCopy *regions;
 };
-VERIFY_4_BYTE_ALIGNMENT(CopyBufferToImageParams)
 
 struct CopyImageParams
 {
@@ -139,7 +129,6 @@
     uint32_t regionCount;
     const VkImageCopy *regions;
 };
-VERIFY_4_BYTE_ALIGNMENT(CopyImageParams)
 
 struct CopyImageToBufferParams
 {
@@ -149,7 +138,6 @@
     uint32_t regionCount;
     const VkBufferImageCopy *regions;
 };
-VERIFY_4_BYTE_ALIGNMENT(CopyImageToBufferParams)
 
 struct ClearAttachmentsParams
 {
@@ -158,7 +146,6 @@
     uint32_t rectCount;
     const VkClearRect *rects;
 };
-VERIFY_4_BYTE_ALIGNMENT(ClearAttachmentsParams)
 
 struct ClearColorImageParams
 {
@@ -168,7 +155,6 @@
     uint32_t rangeCount;
     const VkImageSubresourceRange *ranges;
 };
-VERIFY_4_BYTE_ALIGNMENT(ClearColorImageParams)
 
 struct ClearDepthStencilImageParams
 {
@@ -178,7 +164,6 @@
     uint32_t rangeCount;
     const VkImageSubresourceRange *ranges;
 };
-VERIFY_4_BYTE_ALIGNMENT(ClearDepthStencilImageParams)
 
 struct UpdateBufferParams
 {
@@ -187,7 +172,6 @@
     VkDeviceSize dataSize;
     const void *data;
 };
-VERIFY_4_BYTE_ALIGNMENT(UpdateBufferParams)
 
 struct PushConstantsParams
 {
@@ -197,7 +181,6 @@
     uint32_t size;
     const void *data;
 };
-VERIFY_4_BYTE_ALIGNMENT(PushConstantsParams)
 
 struct SetViewportParams
 {
@@ -205,7 +188,6 @@
     uint32_t viewportCount;
     const VkViewport *viewports;
 };
-VERIFY_4_BYTE_ALIGNMENT(SetViewportParams)
 
 struct SetScissorParams
 {
@@ -213,35 +195,23 @@
     uint32_t scissorCount;
     const VkRect2D *scissors;
 };
-VERIFY_4_BYTE_ALIGNMENT(SetScissorParams)
 
 struct DrawParams
 {
     uint32_t vertexCount;
-    uint32_t firstVertex;
-};
-VERIFY_4_BYTE_ALIGNMENT(DrawParams)
-
-struct DrawInstancedParams
-{
-    uint32_t vertexCount;
     uint32_t instanceCount;
     uint32_t firstVertex;
+    uint32_t firstInstance;
 };
-VERIFY_4_BYTE_ALIGNMENT(DrawInstancedParams)
 
 struct DrawIndexedParams
 {
     uint32_t indexCount;
-};
-VERIFY_4_BYTE_ALIGNMENT(DrawIndexedParams)
-
-struct DrawIndexedInstancedParams
-{
-    uint32_t indexCount;
     uint32_t instanceCount;
+    uint32_t firstIndex;
+    int32_t vertexOffset;
+    uint32_t firstInstance;
 };
-VERIFY_4_BYTE_ALIGNMENT(DrawIndexedInstancedParams)
 
 struct DispatchParams
 {
@@ -249,7 +219,6 @@
     uint32_t groupCountY;
     uint32_t groupCountZ;
 };
-VERIFY_4_BYTE_ALIGNMENT(DispatchParams)
 
 struct PipelineBarrierParams
 {
@@ -263,29 +232,18 @@
     uint32_t imageMemoryBarrierCount;
     const VkImageMemoryBarrier *imageMemoryBarriers;
 };
-VERIFY_4_BYTE_ALIGNMENT(PipelineBarrierParams)
-
-struct ImageBarrierParams
-{
-    VkPipelineStageFlags srcStageMask;
-    VkPipelineStageFlags dstStageMask;
-    VkImageMemoryBarrier imageMemoryBarrier;
-};
-VERIFY_4_BYTE_ALIGNMENT(ImageBarrierParams)
 
 struct SetEventParams
 {
     VkEvent event;
     VkPipelineStageFlags stageMask;
 };
-VERIFY_4_BYTE_ALIGNMENT(SetEventParams)
 
 struct ResetEventParams
 {
     VkEvent event;
     VkPipelineStageFlags stageMask;
 };
-VERIFY_4_BYTE_ALIGNMENT(ResetEventParams)
 
 struct WaitEventsParams
 {
@@ -300,7 +258,6 @@
     uint32_t imageMemoryBarrierCount;
     const VkImageMemoryBarrier *imageMemoryBarriers;
 };
-VERIFY_4_BYTE_ALIGNMENT(WaitEventsParams)
 
 struct ResetQueryPoolParams
 {
@@ -308,7 +265,6 @@
     uint32_t firstQuery;
     uint32_t queryCount;
 };
-VERIFY_4_BYTE_ALIGNMENT(ResetQueryPoolParams)
 
 struct BeginQueryParams
 {
@@ -316,14 +272,12 @@
     uint32_t query;
     VkQueryControlFlags flags;
 };
-VERIFY_4_BYTE_ALIGNMENT(BeginQueryParams)
 
 struct EndQueryParams
 {
     VkQueryPool queryPool;
     uint32_t query;
 };
-VERIFY_4_BYTE_ALIGNMENT(EndQueryParams)
 
 struct WriteTimestampParams
 {
@@ -331,34 +285,19 @@
     VkQueryPool queryPool;
     uint32_t query;
 };
-VERIFY_4_BYTE_ALIGNMENT(WriteTimestampParams)
 
 // Header for every cmd in custom cmd buffer
 struct CommandHeader
 {
     CommandID id;
-    uint16_t size;
+    CommandHeader *next;
 };
 
-static_assert(sizeof(CommandHeader) == 4, "Check CommandHeader size");
-
-template <typename DestT, typename T>
-ANGLE_INLINE DestT *Offset(T *ptr, size_t bytes)
-{
-    return reinterpret_cast<DestT *>((reinterpret_cast<uint8_t *>(ptr) + bytes));
-}
-
-template <typename DestT, typename T>
-ANGLE_INLINE const DestT *Offset(const T *ptr, size_t bytes)
-{
-    return reinterpret_cast<const DestT *>((reinterpret_cast<const uint8_t *>(ptr) + bytes));
-}
-
 class SecondaryCommandBuffer final : angle::NonCopyable
 {
   public:
-    SecondaryCommandBuffer();
-    ~SecondaryCommandBuffer();
+    SecondaryCommandBuffer() : mHead(nullptr), mLast(nullptr), mAllocator(nullptr) {}
+    ~SecondaryCommandBuffer() {}
 
     // Add commands
     void bindDescriptorSets(VkPipelineBindPoint bindPoint,
@@ -371,9 +310,7 @@
 
     void bindIndexBuffer(const Buffer &buffer, VkDeviceSize offset, VkIndexType indexType);
 
-    void bindGraphicsPipeline(const Pipeline &pipeline);
-
-    void bindComputePipeline(const Pipeline &pipeline);
+    void bindPipeline(VkPipelineBindPoint pipelineBindPoint, const Pipeline &pipeline);
 
     void bindVertexBuffers(uint32_t firstBinding,
                            uint32_t bindingCount,
@@ -443,13 +380,16 @@
     void setViewport(uint32_t firstViewport, uint32_t viewportCount, const VkViewport *viewports);
     void setScissor(uint32_t firstScissor, uint32_t scissorCount, const VkRect2D *scissors);
 
-    void draw(uint32_t vertexCount, uint32_t firstVertex);
+    void draw(uint32_t vertexCount,
+              uint32_t instanceCount,
+              uint32_t firstVertex,
+              uint32_t firstInstance);
 
-    void drawInstanced(uint32_t vertexCount, uint32_t instanceCount, uint32_t firstVertex);
-
-    void drawIndexed(uint32_t indexCount);
-
-    void drawIndexedInstanced(uint32_t indexCount, uint32_t instanceCount);
+    void drawIndexed(uint32_t indexCount,
+                     uint32_t instanceCount,
+                     uint32_t firstIndex,
+                     int32_t vertexOffset,
+                     uint32_t firstInstance);
 
     void dispatch(uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ);
 
@@ -463,10 +403,6 @@
                          uint32_t imageMemoryBarrierCount,
                          const VkImageMemoryBarrier *imageMemoryBarriers);
 
-    void imageBarrier(VkPipelineStageFlags srcStageMask,
-                      VkPipelineStageFlags dstStageMask,
-                      VkImageMemoryBarrier *imageMemoryBarrier);
-
     void setEvent(VkEvent event, VkPipelineStageFlags stageMask);
     void resetEvent(VkEvent event, VkPipelineStageFlags stageMask);
     void waitEvents(uint32_t eventCount,
@@ -491,87 +427,25 @@
 
     // Parse the cmds in this cmd buffer into given primary cmd buffer for execution
     void executeCommands(VkCommandBuffer cmdBuffer);
-    // Pool Alloc uses 16kB pages w/ 16byte header = 16368bytes. To minimize waste
-    //  using a 16368/12 = 1364. Also better perf than 1024 due to fewer block allocations
-    static constexpr size_t kBlockSize = 1364;
-    // Make sure block size is 4-byte aligned to avoid Android errors
-    static_assert((kBlockSize % 4) == 0, "Check kBlockSize alignment");
-
     // Initialize the SecondaryCommandBuffer by setting the allocator it will use
-    void initialize(angle::PoolAllocator *allocator)
-    {
-        ASSERT(allocator);
-        mAllocator = allocator;
-        allocateNewBlock();
-        // Set first command to Invalid to start
-        reinterpret_cast<CommandHeader *>(mCurrentWritePointer)->id = CommandID::Invalid;
-    }
-
+    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:
-    template <class StructType>
-    ANGLE_INLINE StructType *commonInit(CommandID cmdID, size_t allocationSize)
-    {
-        mCurrentBytesRemaining -= allocationSize;
-
-        CommandHeader *header = reinterpret_cast<CommandHeader *>(mCurrentWritePointer);
-        header->id            = cmdID;
-        header->size          = static_cast<uint16_t>(allocationSize);
-        ASSERT(allocationSize <= std::numeric_limits<uint16_t>::max());
-
-        mCurrentWritePointer += allocationSize;
-        // Set next cmd header to Invalid (0) so cmd sequence will be terminated
-        reinterpret_cast<CommandHeader *>(mCurrentWritePointer)->id = CommandID::Invalid;
-        return Offset<StructType>(header, sizeof(CommandHeader));
-    }
-    ANGLE_INLINE void allocateNewBlock()
-    {
-        ASSERT(mAllocator);
-        mCurrentWritePointer   = mAllocator->fastAllocate(kBlockSize);
-        mCurrentBytesRemaining = kBlockSize;
-        mCommands.push_back(reinterpret_cast<CommandHeader *>(mCurrentWritePointer));
-    }
-
     // Allocate and initialize memory for given commandID & variable param size
     //  returning a pointer to the start of the commands parameter data and updating
     //  mPtrCmdData to just past the fixed parameter data.
     template <class StructType>
-    ANGLE_INLINE StructType *initCommand(CommandID cmdID, size_t variableSize)
-    {
-        constexpr size_t fixedAllocationSize = sizeof(StructType) + sizeof(CommandHeader);
-        const size_t allocationSize          = fixedAllocationSize + variableSize;
-        // Make sure we have enough room to mark follow-on header "Invalid"
-        if (mCurrentBytesRemaining <= (allocationSize + sizeof(CommandHeader)))
-        {
-            allocateNewBlock();
-        }
-        mPtrCmdData = mCurrentWritePointer + fixedAllocationSize;
-        return commonInit<StructType>(cmdID, allocationSize);
-    }
-
-    // Initialize a command that doesn't have variable-sized ptr data
-    template <class StructType>
-    ANGLE_INLINE StructType *initCommand(CommandID cmdID)
-    {
-        constexpr size_t allocationSize = sizeof(StructType) + sizeof(CommandHeader);
-        // Make sure we have enough room to mark follow-on header "Invalid"
-        if (mCurrentBytesRemaining <= (allocationSize + sizeof(CommandHeader)))
-        {
-            allocateNewBlock();
-        }
-        return commonInit<StructType>(cmdID, allocationSize);
-    }
-
+    StructType *initCommand(CommandID cmdID, size_t variableSize);
     // Return a ptr to the parameter type
     template <class StructType>
-    const StructType *getParamPtr(const CommandHeader *header) const
+    StructType *getParamPtr(CommandHeader *header)
     {
-        return reinterpret_cast<const StructType *>(reinterpret_cast<const uint8_t *>(header) +
-                                                    sizeof(CommandHeader));
+        return reinterpret_cast<StructType *>(reinterpret_cast<char *>(header) +
+                                              sizeof(CommandHeader));
     }
     // Copy sizeInBytes data from paramData to mPtrCmdData and assign *writePtr
     //  to mPtrCmdData. Then increment mPtrCmdData by sizeInBytes.
@@ -579,132 +453,18 @@
     template <class PtrType>
     void storePointerParameter(const PtrType *paramData,
                                const PtrType **writePtr,
-                               size_t sizeInBytes)
-    {
-        if (sizeInBytes == 0)
-            return;
-        *writePtr = reinterpret_cast<const PtrType *>(mPtrCmdData);
-        memcpy(mPtrCmdData, paramData, sizeInBytes);
-        mPtrCmdData += sizeInBytes;
-    }
+                               size_t sizeInBytes);
 
-    std::vector<CommandHeader *> mCommands;
-
-    // Allocator used by this class. If non-null then the class is valid.
+    // Pointer to start of cmd buffer
+    CommandHeader *mHead;
+    // Last command inserted in cmd buffer
+    CommandHeader *mLast;
     angle::PoolAllocator *mAllocator;
-
-    uint8_t *mCurrentWritePointer;
-    size_t mCurrentBytesRemaining;
-
     // Ptr to write variable ptr data section of cmd into.
     //  This is set to just past fixed parameter data when initCommand() is called
     uint8_t *mPtrCmdData;
 };
 
-ANGLE_INLINE SecondaryCommandBuffer::SecondaryCommandBuffer()
-    : mAllocator(nullptr), mCurrentWritePointer(nullptr), mCurrentBytesRemaining(0)
-{}
-ANGLE_INLINE SecondaryCommandBuffer::~SecondaryCommandBuffer() {}
-
-ANGLE_INLINE void SecondaryCommandBuffer::bindDescriptorSets(VkPipelineBindPoint bindPoint,
-                                                             const PipelineLayout &layout,
-                                                             uint32_t firstSet,
-                                                             uint32_t descriptorSetCount,
-                                                             const VkDescriptorSet *descriptorSets,
-                                                             uint32_t dynamicOffsetCount,
-                                                             const uint32_t *dynamicOffsets)
-{
-    size_t descSize   = descriptorSetCount * sizeof(VkDescriptorSet);
-    size_t offsetSize = dynamicOffsetCount * sizeof(uint32_t);
-    size_t varSize    = descSize + offsetSize;
-    BindDescriptorSetParams *paramStruct =
-        initCommand<BindDescriptorSetParams>(CommandID::BindDescriptorSets, varSize);
-    // Copy params into memory
-    paramStruct->bindPoint          = bindPoint;
-    paramStruct->layout             = layout.getHandle();
-    paramStruct->firstSet           = firstSet;
-    paramStruct->descriptorSetCount = descriptorSetCount;
-    paramStruct->dynamicOffsetCount = dynamicOffsetCount;
-    // Copy variable sized data
-    storePointerParameter(descriptorSets, &paramStruct->descriptorSets, descSize);
-    storePointerParameter(dynamicOffsets, &paramStruct->dynamicOffsets, offsetSize);
-}
-
-ANGLE_INLINE void SecondaryCommandBuffer::bindIndexBuffer(const Buffer &buffer,
-                                                          VkDeviceSize offset,
-                                                          VkIndexType indexType)
-{
-    BindIndexBufferParams *paramStruct =
-        initCommand<BindIndexBufferParams>(CommandID::BindIndexBuffer);
-    paramStruct->buffer    = buffer.getHandle();
-    paramStruct->offset    = offset;
-    paramStruct->indexType = indexType;
-}
-
-ANGLE_INLINE void SecondaryCommandBuffer::bindGraphicsPipeline(const Pipeline &pipeline)
-{
-    BindPipelineParams *paramStruct =
-        initCommand<BindPipelineParams>(CommandID::BindGraphicsPipeline);
-    paramStruct->pipeline = pipeline.getHandle();
-}
-
-ANGLE_INLINE void SecondaryCommandBuffer::bindComputePipeline(const Pipeline &pipeline)
-{
-    BindPipelineParams *paramStruct =
-        initCommand<BindPipelineParams>(CommandID::BindComputePipeline);
-    paramStruct->pipeline = pipeline.getHandle();
-}
-
-ANGLE_INLINE void SecondaryCommandBuffer::bindVertexBuffers(uint32_t firstBinding,
-                                                            uint32_t bindingCount,
-                                                            const VkBuffer *buffers,
-                                                            const VkDeviceSize *offsets)
-{
-    ASSERT(firstBinding == 0);
-    size_t buffersSize                   = bindingCount * sizeof(VkBuffer);
-    size_t offsetsSize                   = bindingCount * sizeof(VkDeviceSize);
-    BindVertexBuffersParams *paramStruct = initCommand<BindVertexBuffersParams>(
-        CommandID::BindVertexBuffers, buffersSize + offsetsSize);
-    // Copy params
-    paramStruct->bindingCount = bindingCount;
-    uint8_t *writePointer     = Offset<uint8_t>(paramStruct, sizeof(BindVertexBuffersParams));
-    memcpy(writePointer, buffers, buffersSize);
-    writePointer += buffersSize;
-    memcpy(writePointer, offsets, offsetsSize);
-}
-
-ANGLE_INLINE void SecondaryCommandBuffer::draw(uint32_t vertexCount, uint32_t firstVertex)
-{
-    DrawParams *paramStruct  = initCommand<DrawParams>(CommandID::Draw);
-    paramStruct->vertexCount = vertexCount;
-    paramStruct->firstVertex = firstVertex;
-}
-
-ANGLE_INLINE void SecondaryCommandBuffer::drawInstanced(uint32_t vertexCount,
-                                                        uint32_t instanceCount,
-                                                        uint32_t firstVertex)
-{
-    DrawInstancedParams *paramStruct = initCommand<DrawInstancedParams>(CommandID::DrawInstanced);
-    paramStruct->vertexCount         = vertexCount;
-    paramStruct->instanceCount       = instanceCount;
-    paramStruct->firstVertex         = firstVertex;
-}
-
-ANGLE_INLINE void SecondaryCommandBuffer::drawIndexed(uint32_t indexCount)
-{
-    DrawIndexedParams *paramStruct = initCommand<DrawIndexedParams>(CommandID::DrawIndexed);
-    paramStruct->indexCount        = indexCount;
-}
-
-ANGLE_INLINE void SecondaryCommandBuffer::drawIndexedInstanced(uint32_t indexCount,
-                                                               uint32_t instanceCount)
-{
-    DrawIndexedInstancedParams *paramStruct =
-        initCommand<DrawIndexedInstancedParams>(CommandID::DrawIndexedInstanced);
-    paramStruct->indexCount    = indexCount;
-    paramStruct->instanceCount = instanceCount;
-}
-
 }  // namespace vk
 }  // namespace rx
 
diff --git a/src/libANGLE/renderer/vulkan/SurfaceVk.cpp b/src/libANGLE/renderer/vulkan/SurfaceVk.cpp
index 7194ae6..7c711c4 100644
--- a/src/libANGLE/renderer/vulkan/SurfaceVk.cpp
+++ b/src/libANGLE/renderer/vulkan/SurfaceVk.cpp
@@ -503,18 +503,18 @@
     swapchainInfo.imageFormat              = nativeFormat;
     swapchainInfo.imageColorSpace          = VK_COLORSPACE_SRGB_NONLINEAR_KHR;
     // Note: Vulkan doesn't allow 0-width/height swapchains.
-    swapchainInfo.imageExtent.width     = std::max(extents.width, 1);
-    swapchainInfo.imageExtent.height    = std::max(extents.height, 1);
-    swapchainInfo.imageArrayLayers      = 1;
-    swapchainInfo.imageUsage            = kImageUsageFlags;
-    swapchainInfo.imageSharingMode      = VK_SHARING_MODE_EXCLUSIVE;
-    swapchainInfo.queueFamilyIndexCount = 0;
-    swapchainInfo.pQueueFamilyIndices   = nullptr;
-    swapchainInfo.preTransform          = mPreTransform;
-    swapchainInfo.compositeAlpha        = mCompositeAlpha;
-    swapchainInfo.presentMode           = mDesiredSwapchainPresentMode;
-    swapchainInfo.clipped               = VK_TRUE;
-    swapchainInfo.oldSwapchain          = oldSwapchain;
+    swapchainInfo.imageExtent.width        = std::max(extents.width, 1);
+    swapchainInfo.imageExtent.height       = std::max(extents.height, 1);
+    swapchainInfo.imageArrayLayers         = 1;
+    swapchainInfo.imageUsage               = kImageUsageFlags;
+    swapchainInfo.imageSharingMode         = VK_SHARING_MODE_EXCLUSIVE;
+    swapchainInfo.queueFamilyIndexCount    = 0;
+    swapchainInfo.pQueueFamilyIndices      = nullptr;
+    swapchainInfo.preTransform             = mPreTransform;
+    swapchainInfo.compositeAlpha           = mCompositeAlpha;
+    swapchainInfo.presentMode              = mDesiredSwapchainPresentMode;
+    swapchainInfo.clipped                  = VK_TRUE;
+    swapchainInfo.oldSwapchain             = oldSwapchain;
 
     // TODO(syoussefi): Once EGL_SWAP_BEHAVIOR_PRESERVED_BIT is supported, the contents of the old
     // swapchain need to carry over to the new one.  http://anglebug.com/2942
@@ -738,7 +738,7 @@
     std::vector<VkRectLayerKHR> vk_rects;
     if (renderer->getFeatures().supportsIncrementalPresent && (n_rects > 0))
     {
-        EGLint *egl_rects            = rects;
+        EGLint *egl_rects = rects;
         presentRegion.rectangleCount = n_rects;
         vk_rects.resize(n_rects);
         for (EGLint rect = 0; rect < n_rects; rect++)
diff --git a/src/libANGLE/renderer/vulkan/TextureVk.cpp b/src/libANGLE/renderer/vulkan/TextureVk.cpp
index 2011e20..de083b4 100644
--- a/src/libANGLE/renderer/vulkan/TextureVk.cpp
+++ b/src/libANGLE/renderer/vulkan/TextureVk.cpp
@@ -1004,7 +1004,7 @@
             sourceRowPitch, imageData + bufferOffset));
     }
 
-    CommandBufferT *commandBuffer = nullptr;
+    CommandBufferT *commandBuffer;
     ANGLE_TRY(mImage->recordCommands(contextVk, &commandBuffer));
     return mImage->flushStagedUpdates(contextVk, getNativeImageLevel(0), getLevelCount(),
                                       commandBuffer);
diff --git a/src/libANGLE/renderer/vulkan/UtilsVk.cpp b/src/libANGLE/renderer/vulkan/UtilsVk.cpp
index 87fe1f0..1656af4 100644
--- a/src/libANGLE/renderer/vulkan/UtilsVk.cpp
+++ b/src/libANGLE/renderer/vulkan/UtilsVk.cpp
@@ -335,7 +335,7 @@
         program->setShader(gl::ShaderType::Compute, fsCsShader);
         ANGLE_TRY(program->getComputePipeline(context, pipelineLayout.get(), &pipelineAndSerial));
         pipelineAndSerial->updateSerial(serial);
-        commandBuffer->bindComputePipeline(pipelineAndSerial->get());
+        commandBuffer->bindPipeline(bindPoint, pipelineAndSerial->get());
     }
     else
     {
@@ -350,7 +350,7 @@
             context, &renderer->getRenderPassCache(), renderer->getPipelineCache(), serial,
             pipelineLayout.get(), *pipelineDesc, gl::AttributesMask(), &descPtr, &helper));
         helper->updateSerial(serial);
-        commandBuffer->bindGraphicsPipeline(helper->getPipeline());
+        commandBuffer->bindPipeline(bindPoint, helper->getPipeline());
     }
 
     if (descriptorSet != VK_NULL_HANDLE)
@@ -657,7 +657,9 @@
     ANGLE_TRY(setupProgram(contextVk, Function::ImageClear, fragmentShader, vertexShader,
                            &mImageClearProgram, &pipelineDesc, VK_NULL_HANDLE, &shaderParams,
                            sizeof(shaderParams), commandBuffer));
-    commandBuffer->draw(6, 0);
+
+    commandBuffer->draw(6, 1, 0, 0);
+
     return angle::Result::Continue;
 }
 
@@ -781,7 +783,9 @@
     ANGLE_TRY(setupProgram(contextVk, Function::ImageCopy, fragmentShader, vertexShader,
                            &mImageCopyPrograms[flags], &pipelineDesc, descriptorSet, &shaderParams,
                            sizeof(shaderParams), commandBuffer));
-    commandBuffer->draw(6, 0);
+
+    commandBuffer->draw(6, 1, 0, 0);
+
     descriptorPoolBinding.reset();
 
     return angle::Result::Continue;
diff --git a/src/libANGLE/renderer/vulkan/vk_helpers.cpp b/src/libANGLE/renderer/vulkan/vk_helpers.cpp
index 3b6a571..8d7c2de 100644
--- a/src/libANGLE/renderer/vulkan/vk_helpers.cpp
+++ b/src/libANGLE/renderer/vulkan/vk_helpers.cpp
@@ -1064,7 +1064,7 @@
 {
     // 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.
-    commandBuffer->drawIndexed(count + 1);
+    commandBuffer->drawIndexed(count + 1, 1, 0, 0, 0);
 }
 
 // BufferHelper implementation.
@@ -1603,9 +1603,10 @@
     imageMemoryBarrier.subresourceRange.baseArrayLayer = 0;
     imageMemoryBarrier.subresourceRange.layerCount     = mLayerCount;
 
-    commandBuffer->imageBarrier(transitionFrom.srcStageMask, transitionTo.dstStageMask,
-                                &imageMemoryBarrier);
-    mCurrentLayout           = newLayout;
+    commandBuffer->pipelineBarrier(transitionFrom.srcStageMask, transitionTo.dstStageMask, 0, 0,
+                                   nullptr, 0, nullptr, 1, &imageMemoryBarrier);
+
+    mCurrentLayout = newLayout;
     mCurrentQueueFamilyIndex = newQueueFamilyIndex;
 }
 
@@ -1613,6 +1614,7 @@
                              uint32_t baseMipLevel,
                              uint32_t levelCount,
                              CommandBufferT *commandBuffer)
+
 {
     clearColorLayer(color, baseMipLevel, levelCount, 0, mLayerCount, commandBuffer);
 }
@@ -1736,8 +1738,10 @@
         barrier.dstAccessMask                 = VK_ACCESS_TRANSFER_READ_BIT;
 
         // We can do it for all layers at once.
-        commandBuffer->imageBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
-                                    &barrier);
+        commandBuffer->pipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT,
+                                       VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, 1,
+                                       &barrier);
+
         VkImageBlit blit                   = {};
         blit.srcOffsets[0]                 = {0, 0, 0};
         blit.srcOffsets[1]                 = {mipWidth, mipHeight, 1};
@@ -1766,8 +1770,9 @@
     barrier.newLayout                     = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
 
     // We can do it for all layers at once.
-    commandBuffer->imageBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
-                                &barrier);
+    commandBuffer->pipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
+                                   0, 0, nullptr, 0, nullptr, 1, &barrier);
+
     // This is just changing the internal state of the image helper so that the next call
     // to changeLayout will use this layout as the "oldLayout" argument.
     mCurrentLayout = ImageLayout::TransferSrc;
diff --git a/src/libANGLE/renderer/vulkan/vk_helpers.h b/src/libANGLE/renderer/vulkan/vk_helpers.h
index 3b77a38..1b71c0f 100644
--- a/src/libANGLE/renderer/vulkan/vk_helpers.h
+++ b/src/libANGLE/renderer/vulkan/vk_helpers.h
@@ -626,7 +626,6 @@
                            VkImageAspectFlags clearAspectFlags,
                            const VkClearDepthStencilValue &depthStencil,
                            CommandBufferT *commandBuffer);
-
     gl::Extents getSize(const gl::ImageIndex &index) const;
 
     static void Copy(ImageHelper *srcImage,
diff --git a/src/libANGLE/renderer/vulkan/vk_wrapper.h b/src/libANGLE/renderer/vulkan/vk_wrapper.h
index 3a38015..beceaa0 100644
--- a/src/libANGLE/renderer/vulkan/vk_wrapper.h
+++ b/src/libANGLE/renderer/vulkan/vk_wrapper.h
@@ -180,9 +180,7 @@
                          const VkBufferMemoryBarrier *bufferMemoryBarriers,
                          uint32_t imageMemoryBarrierCount,
                          const VkImageMemoryBarrier *imageMemoryBarriers);
-    void imageBarrier(VkPipelineStageFlags srcStageMask,
-                      VkPipelineStageFlags dstStageMask,
-                      VkImageMemoryBarrier *imageMemoryBarrier);
+
     void clearColorImage(const Image &image,
                          VkImageLayout imageLayout,
                          const VkClearColorValue &color,
@@ -228,21 +226,16 @@
               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);
 
     void dispatch(uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ);
 
     void bindPipeline(VkPipelineBindPoint pipelineBindPoint, const Pipeline &pipeline);
-    void bindGraphicsPipeline(const Pipeline &pipeline);
-    void bindComputePipeline(const Pipeline &pipeline);
 
     void bindVertexBuffers(uint32_t firstBinding,
                            uint32_t bindingCount,
@@ -580,15 +573,6 @@
                          imageMemoryBarrierCount, imageMemoryBarriers);
 }
 
-ANGLE_INLINE void CommandBuffer::imageBarrier(VkPipelineStageFlags srcStageMask,
-                                              VkPipelineStageFlags dstStageMask,
-                                              VkImageMemoryBarrier *imageMemoryBarrier)
-{
-    ASSERT(valid());
-    vkCmdPipelineBarrier(mHandle, srcStageMask, dstStageMask, 0, 0, nullptr, 0, nullptr, 1,
-                         imageMemoryBarrier);
-}
-
 ANGLE_INLINE void CommandBuffer::destroy(VkDevice device)
 {
     releaseHandle();
@@ -824,20 +808,6 @@
     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,
@@ -848,18 +818,6 @@
     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)
@@ -875,18 +833,6 @@
     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,
diff --git a/src/tests/gl_tests/StateChangeTest.cpp b/src/tests/gl_tests/StateChangeTest.cpp
index 6e127b6..650908d 100644
--- a/src/tests/gl_tests/StateChangeTest.cpp
+++ b/src/tests/gl_tests/StateChangeTest.cpp
@@ -1404,8 +1404,6 @@
 // Tests updating a buffer's contents while in use, without redefining it.
 TEST_P(SimpleStateChangeTest, UpdateBufferInUse)
 {
-    // tobine: Started failing w/ custom cmd buffers. http://anglebug.com/3255
-    ANGLE_SKIP_TEST_IF(IsAMD() && IsWindows() && IsVulkan());
     std::vector<GLColor> redColorData(6, GLColor::red);
 
     GLBuffer buffer;