Vulkan: Faster state transitions.

Implements a transition table from Pipeline Cache entry to
state change neighbouring Pipeline Cache entries. We use
a 64-bit mask to do a quick scan over the pipeline desc.
This ends up being a lot faster than doing a full hash
and memcmp over the pipeline description.

Note that there could be future optimizations to this design.
We might keep a hash map of the pipeline transitions instead
of a list. Or use a sorted list. This could speed up the search
when there are many transitions for cache entries. Also we could
skip the transition table and opt to do a full hash when there
are more than a configurable number of dirty states. This might
be a bit faster in some cases. Likely this will be something we
can add performance tests for in the future.

Documentation is also added in a README file for the Vulkan back
end. This will be extended over time.

Improves performance about 30-35% on the VBO state change test.

Bug: angleproject:3013
Change-Id: I793f9e3efd8887acf00ad60e4ac2502a54c95dee
Reviewed-on: https://chromium-review.googlesource.com/c/1369287
Commit-Queue: Jamie Madill <jmadill@chromium.org>
Reviewed-by: Yuly Novikov <ynovikov@chromium.org>
diff --git a/src/libANGLE/renderer/vulkan/UtilsVk.cpp b/src/libANGLE/renderer/vulkan/UtilsVk.cpp
index a59c2cf..7c2ba26 100644
--- a/src/libANGLE/renderer/vulkan/UtilsVk.cpp
+++ b/src/libANGLE/renderer/vulkan/UtilsVk.cpp
@@ -325,25 +325,30 @@
 
     Serial serial = renderer->getCurrentQueueSerial();
 
-    vk::PipelineAndSerial *pipelineAndSerial;
     if (isCompute)
     {
+        vk::PipelineAndSerial *pipelineAndSerial;
         program->setShader(gl::ShaderType::Compute, fsCsShader);
         ANGLE_TRY(program->getComputePipeline(context, pipelineLayout.get(), &pipelineAndSerial));
+        pipelineAndSerial->updateSerial(serial);
+        commandBuffer->bindPipeline(bindPoint, pipelineAndSerial->get());
     }
     else
     {
         program->setShader(gl::ShaderType::Vertex, vsShader);
         program->setShader(gl::ShaderType::Fragment, fsCsShader);
 
+        // This value is not used but is passed to getGraphicsPipeline to avoid a nullptr check.
+        const vk::GraphicsPipelineDesc *descPtr;
+        vk::PipelineHelper *helper;
+
         ANGLE_TRY(program->getGraphicsPipeline(
             context, &renderer->getRenderPassCache(), renderer->getPipelineCache(), serial,
-            pipelineLayout.get(), *pipelineDesc, gl::AttributesMask(), &pipelineAndSerial));
+            pipelineLayout.get(), *pipelineDesc, gl::AttributesMask(), &descPtr, &helper));
+        helper->updateSerial(serial);
+        commandBuffer->bindPipeline(bindPoint, helper->getPipeline());
     }
 
-    commandBuffer->bindPipeline(bindPoint, pipelineAndSerial->get());
-    pipelineAndSerial->updateSerial(serial);
-
     if (descriptorSet != VK_NULL_HANDLE)
     {
         commandBuffer->bindDescriptorSets(bindPoint, pipelineLayout.get(), 0, 1, &descriptorSet, 0,
@@ -619,8 +624,8 @@
 
     vk::GraphicsPipelineDesc pipelineDesc;
     pipelineDesc.initDefaults();
-    pipelineDesc.updateColorWriteMask(params.colorMaskFlags, *params.alphaMask);
-    pipelineDesc.updateRenderPassDesc(*params.renderPassDesc);
+    pipelineDesc.setColorWriteMask(params.colorMaskFlags, *params.alphaMask);
+    pipelineDesc.setRenderPassDesc(*params.renderPassDesc);
 
     vk::ShaderLibrary &shaderLibrary                    = renderer->getShaderLibrary();
     vk::RefCounted<vk::ShaderAndSerial> *vertexShader   = nullptr;
@@ -707,7 +712,7 @@
 
     vk::GraphicsPipelineDesc pipelineDesc;
     pipelineDesc.initDefaults();
-    pipelineDesc.updateRenderPassDesc(renderPassDesc);
+    pipelineDesc.setRenderPassDesc(renderPassDesc);
 
     gl::Rectangle renderArea;
     renderArea.x      = params.destOffset[0];