Vulkan: Minimal dirty bits for ContextVk.

Currently this won't speed up performance much, if at all, since we
don't even really support state changes. It sets the stage for using
a pipeline cache later, with better state change support. It also
makes implementing descriptor sets for Textures a bit simpler, since
we can just update descriptor sets when the dirty bits tell us of a
Texture change.

Add cache structures to VertexArrayVk and ContextVk so we only need
to update the structures before we create a new pipeline. When we
support pipeline caching, we will most likely be updating a compact
representation for fast cache query.

BUG=angleproject:1898
BUG=angleproject:2167

Change-Id: Id545f2c67c06d8b6e8b7eb63ca70464f6b9a51f6
Reviewed-on: https://chromium-review.googlesource.com/713586
Commit-Queue: Jamie Madill <jmadill@chromium.org>
Reviewed-by: Frank Henigman <fjhenigman@chromium.org>
diff --git a/src/libANGLE/renderer/vulkan/VertexArrayVk.cpp b/src/libANGLE/renderer/vulkan/VertexArrayVk.cpp
index 896dd56..309766a 100644
--- a/src/libANGLE/renderer/vulkan/VertexArrayVk.cpp
+++ b/src/libANGLE/renderer/vulkan/VertexArrayVk.cpp
@@ -14,6 +14,7 @@
 #include "libANGLE/Context.h"
 #include "libANGLE/renderer/vulkan/BufferVk.h"
 #include "libANGLE/renderer/vulkan/ContextVk.h"
+#include "libANGLE/renderer/vulkan/formatutilsvk.h"
 
 namespace rx
 {
@@ -21,8 +22,11 @@
 VertexArrayVk::VertexArrayVk(const gl::VertexArrayState &state)
     : VertexArrayImpl(state),
       mCurrentVertexBufferHandlesCache(state.getMaxAttribs(), VK_NULL_HANDLE),
-      mCurrentVkBuffersCache(state.getMaxAttribs(), nullptr)
+      mCurrentVkBuffersCache(state.getMaxAttribs(), nullptr),
+      mCurrentVertexDescsValid(false)
 {
+    mCurrentVertexBindingDescs.reserve(state.getMaxAttribs());
+    mCurrentVertexAttribDescs.reserve(state.getMaxAttribs());
 }
 
 void VertexArrayVk::destroy(const gl::Context *context)
@@ -39,6 +43,9 @@
     auto contextVk = GetImplAs<ContextVk>(context);
     contextVk->invalidateCurrentPipeline();
 
+    // Invalidate the vertex descriptions.
+    invalidateVertexDescriptions();
+
     // Rebuild current attribute buffers cache. This will fail horribly if the buffer changes.
     // TODO(jmadill): Handle buffer storage changes.
     const auto &attribs  = mState.getVertexAttributes();
@@ -53,6 +60,7 @@
 
         const auto &attrib  = attribs[attribIndex];
         const auto &binding = bindings[attrib.bindingIndex];
+
         if (attrib.enabled)
         {
             gl::Buffer *bufferGL = binding.getBuffer().get();
@@ -90,4 +98,66 @@
     }
 }
 
+void VertexArrayVk::invalidateVertexDescriptions()
+{
+    mCurrentVertexDescsValid = false;
+    mCurrentVertexBindingDescs.clear();
+    mCurrentVertexAttribDescs.clear();
+}
+
+void VertexArrayVk::updateVertexDescriptions(const gl::Context *context)
+{
+    if (mCurrentVertexDescsValid)
+    {
+        return;
+    }
+
+    const auto &attribs  = mState.getVertexAttributes();
+    const auto &bindings = mState.getVertexBindings();
+
+    const gl::Program *programGL = context->getGLState().getProgram();
+
+    for (auto attribIndex : programGL->getActiveAttribLocationsMask())
+    {
+        const auto &attrib  = attribs[attribIndex];
+        const auto &binding = bindings[attrib.bindingIndex];
+        if (attrib.enabled)
+        {
+            VkVertexInputBindingDescription bindingDesc;
+            bindingDesc.binding = static_cast<uint32_t>(mCurrentVertexBindingDescs.size());
+            bindingDesc.stride  = static_cast<uint32_t>(gl::ComputeVertexAttributeTypeSize(attrib));
+            bindingDesc.inputRate = (binding.getDivisor() > 0 ? VK_VERTEX_INPUT_RATE_INSTANCE
+                                                              : VK_VERTEX_INPUT_RATE_VERTEX);
+
+            gl::VertexFormatType vertexFormatType = gl::GetVertexFormatType(attrib);
+
+            VkVertexInputAttributeDescription attribDesc;
+            attribDesc.binding  = bindingDesc.binding;
+            attribDesc.format   = vk::GetNativeVertexFormat(vertexFormatType);
+            attribDesc.location = static_cast<uint32_t>(attribIndex);
+            attribDesc.offset =
+                static_cast<uint32_t>(ComputeVertexAttributeOffset(attrib, binding));
+
+            mCurrentVertexBindingDescs.push_back(bindingDesc);
+            mCurrentVertexAttribDescs.push_back(attribDesc);
+        }
+        else
+        {
+            UNIMPLEMENTED();
+        }
+    }
+
+    mCurrentVertexDescsValid = true;
+}
+
+const std::vector<VkVertexInputBindingDescription> &VertexArrayVk::getVertexBindingDescs() const
+{
+    return mCurrentVertexBindingDescs;
+}
+
+const std::vector<VkVertexInputAttributeDescription> &VertexArrayVk::getVertexAttribDescs() const
+{
+    return mCurrentVertexAttribDescs;
+}
+
 }  // namespace rx