Vulkan: invalidate translation buffers for SSBOs

Translation buffers weren't being marked dirty after running a compute
shader in which they are bound as SSBOs.
This change invalidates all SSBOs after a draw or compute call.

Bug: angleproject:3739
Change-Id: I66b56df7e619b55afc7e3da6b5613b6d050e06bb
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/1717144
Reviewed-by: Shahbaz Youssefi <syoussefi@chromium.org>
Reviewed-by: Jamie Madill <jmadill@chromium.org>
Commit-Queue: James Dong <dongja@google.com>
diff --git a/src/libANGLE/Buffer.cpp b/src/libANGLE/Buffer.cpp
index 9ffcddb..7e036b9 100644
--- a/src/libANGLE/Buffer.cpp
+++ b/src/libANGLE/Buffer.cpp
@@ -210,20 +210,14 @@
     return angle::Result::Continue;
 }
 
-void Buffer::onTransformFeedback()
+void Buffer::onDataChanged()
 {
     mIndexRangeCache.clear();
 
     // Notify when data changes.
     onStateChange(angle::SubjectMessage::ContentsChanged);
-}
 
-void Buffer::onPixelPack()
-{
-    mIndexRangeCache.clear();
-
-    // Notify when data changes.
-    onStateChange(angle::SubjectMessage::ContentsChanged);
+    mImpl->onDataChanged();
 }
 
 angle::Result Buffer::getIndexRange(const gl::Context *context,
diff --git a/src/libANGLE/Buffer.h b/src/libANGLE/Buffer.h
index ef3eefe..e43ddf6 100644
--- a/src/libANGLE/Buffer.h
+++ b/src/libANGLE/Buffer.h
@@ -100,8 +100,7 @@
     angle::Result unmap(const Context *context, GLboolean *result);
 
     // These are called when another operation changes Buffer data.
-    void onTransformFeedback();
-    void onPixelPack();
+    void onDataChanged();
 
     angle::Result getIndexRange(const gl::Context *context,
                                 DrawElementsType type,
diff --git a/src/libANGLE/Context.cpp b/src/libANGLE/Context.cpp
index d6edd72..d83f863 100644
--- a/src/libANGLE/Context.cpp
+++ b/src/libANGLE/Context.cpp
@@ -2244,6 +2244,7 @@
     ANGLE_CONTEXT_TRY(
         mImplementation->drawArraysInstanced(this, mode, first, count, instanceCount));
     MarkTransformFeedbackBufferUsage(this, count, instanceCount);
+    MarkShaderStorageBufferUsage(this);
 }
 
 void Context::drawElementsInstanced(PrimitiveMode mode,
@@ -2261,6 +2262,7 @@
     ANGLE_CONTEXT_TRY(prepareForDraw(mode));
     ANGLE_CONTEXT_TRY(
         mImplementation->drawElementsInstanced(this, mode, count, type, indices, instances));
+    MarkShaderStorageBufferUsage(this);
 }
 
 void Context::drawRangeElements(PrimitiveMode mode,
@@ -2279,18 +2281,21 @@
     ANGLE_CONTEXT_TRY(prepareForDraw(mode));
     ANGLE_CONTEXT_TRY(
         mImplementation->drawRangeElements(this, mode, start, end, count, type, indices));
+    MarkShaderStorageBufferUsage(this);
 }
 
 void Context::drawArraysIndirect(PrimitiveMode mode, const void *indirect)
 {
     ANGLE_CONTEXT_TRY(prepareForDraw(mode));
     ANGLE_CONTEXT_TRY(mImplementation->drawArraysIndirect(this, mode, indirect));
+    MarkShaderStorageBufferUsage(this);
 }
 
 void Context::drawElementsIndirect(PrimitiveMode mode, DrawElementsType type, const void *indirect)
 {
     ANGLE_CONTEXT_TRY(prepareForDraw(mode));
     ANGLE_CONTEXT_TRY(mImplementation->drawElementsIndirect(this, mode, type, indirect));
+    MarkShaderStorageBufferUsage(this);
 }
 
 void Context::flush()
@@ -5395,12 +5400,16 @@
 
     ANGLE_CONTEXT_TRY(prepareForDispatch());
     ANGLE_CONTEXT_TRY(mImplementation->dispatchCompute(this, numGroupsX, numGroupsY, numGroupsZ));
+
+    MarkShaderStorageBufferUsage(this);
 }
 
 void Context::dispatchComputeIndirect(GLintptr indirect)
 {
     ANGLE_CONTEXT_TRY(prepareForDispatch());
     ANGLE_CONTEXT_TRY(mImplementation->dispatchComputeIndirect(this, indirect));
+
+    MarkShaderStorageBufferUsage(this);
 }
 
 void Context::texStorage2D(TextureType target,
@@ -5456,6 +5465,7 @@
             ANGLE_CONTEXT_TRY(
                 mImplementation->drawArrays(this, mode, firsts[drawID], counts[drawID]));
             MarkTransformFeedbackBufferUsage(this, counts[drawID], 1);
+            MarkShaderStorageBufferUsage(this);
         }
     }
     else
@@ -5469,6 +5479,7 @@
             ANGLE_CONTEXT_TRY(
                 mImplementation->drawArrays(this, mode, firsts[drawID], counts[drawID]));
             MarkTransformFeedbackBufferUsage(this, counts[drawID], 1);
+            MarkShaderStorageBufferUsage(this);
         }
     }
 }
@@ -5494,6 +5505,7 @@
             ANGLE_CONTEXT_TRY(mImplementation->drawArraysInstanced(
                 this, mode, firsts[drawID], counts[drawID], instanceCounts[drawID]));
             MarkTransformFeedbackBufferUsage(this, counts[drawID], instanceCounts[drawID]);
+            MarkShaderStorageBufferUsage(this);
         }
     }
     else
@@ -5507,6 +5519,7 @@
             ANGLE_CONTEXT_TRY(mImplementation->drawArraysInstanced(
                 this, mode, firsts[drawID], counts[drawID], instanceCounts[drawID]));
             MarkTransformFeedbackBufferUsage(this, counts[drawID], instanceCounts[drawID]);
+            MarkShaderStorageBufferUsage(this);
         }
     }
 }
@@ -5531,6 +5544,7 @@
             programObject->setDrawIDUniform(drawID);
             ANGLE_CONTEXT_TRY(
                 mImplementation->drawElements(this, mode, counts[drawID], type, indices[drawID]));
+            MarkShaderStorageBufferUsage(this);
         }
     }
     else
@@ -5543,6 +5557,7 @@
             }
             ANGLE_CONTEXT_TRY(
                 mImplementation->drawElements(this, mode, counts[drawID], type, indices[drawID]));
+            MarkShaderStorageBufferUsage(this);
         }
     }
 }
@@ -5568,6 +5583,7 @@
             programObject->setDrawIDUniform(drawID);
             ANGLE_CONTEXT_TRY(mImplementation->drawElementsInstanced(
                 this, mode, counts[drawID], type, indices[drawID], instanceCounts[drawID]));
+            MarkShaderStorageBufferUsage(this);
         }
     }
     else
@@ -5580,6 +5596,7 @@
             }
             ANGLE_CONTEXT_TRY(mImplementation->drawElementsInstanced(
                 this, mode, counts[drawID], type, indices[drawID], instanceCounts[drawID]));
+            MarkShaderStorageBufferUsage(this);
         }
     }
 }
@@ -8705,6 +8722,7 @@
     updateVertexElementLimits(context);
     updateBasicDrawStatesError();
     updateValidDrawModes(context);
+    updateActiveShaderStorageBufferIndices(context);
 }
 
 void StateCache::onVertexArrayFormatChange(Context *context)
@@ -8934,4 +8952,17 @@
         }};
     }
 }
+
+void StateCache::updateActiveShaderStorageBufferIndices(Context *context)
+{
+    mCachedActiveShaderStorageBufferIndices.reset();
+    Program *program = context->getState().getProgram();
+    if (program)
+    {
+        for (const InterfaceBlock &block : program->getState().getShaderStorageBlocks())
+        {
+            mCachedActiveShaderStorageBufferIndices.set(block.binding);
+        }
+    }
+}
 }  // namespace gl
diff --git a/src/libANGLE/Context.h b/src/libANGLE/Context.h
index 4ae7c7e..1a972bc 100644
--- a/src/libANGLE/Context.h
+++ b/src/libANGLE/Context.h
@@ -247,6 +247,13 @@
         return mCachedIntegerVertexAttribTypesValidation[type];
     }
 
+    // Places that can trigger updateActiveShaderStorageBufferIndices:
+    // 1. onProgramExecutableChange.
+    StorageBuffersMask getActiveShaderStorageBufferIndices() const
+    {
+        return mCachedActiveShaderStorageBufferIndices;
+    }
+
     // State change notifications.
     void onVertexArrayBindingChange(Context *context);
     void onProgramExecutableChange(Context *context);
@@ -278,6 +285,7 @@
     void updateBasicDrawElementsError();
     void updateTransformFeedbackActiveUnpaused(Context *context);
     void updateVertexAttribTypesValidation(Context *context);
+    void updateActiveShaderStorageBufferIndices(Context *context);
 
     void setValidDrawModes(bool pointsOK, bool linesOK, bool trisOK, bool lineAdjOK, bool triAdjOK);
 
@@ -295,6 +303,7 @@
     mutable intptr_t mCachedBasicDrawStatesError;
     mutable intptr_t mCachedBasicDrawElementsError;
     bool mCachedTransformFeedbackActiveUnpaused;
+    StorageBuffersMask mCachedActiveShaderStorageBufferIndices;
 
     // Reserve an extra slot at the end of these maps for invalid enum.
     angle::PackedEnumMap<PrimitiveMode, bool, angle::EnumSize<PrimitiveMode>() + 1>
diff --git a/src/libANGLE/Context.inl.h b/src/libANGLE/Context.inl.h
index 4738160..af72e72 100644
--- a/src/libANGLE/Context.inl.h
+++ b/src/libANGLE/Context.inl.h
@@ -46,6 +46,18 @@
     }
 }
 
+ANGLE_INLINE void MarkShaderStorageBufferUsage(const Context *context)
+{
+    for (size_t index : context->getStateCache().getActiveShaderStorageBufferIndices())
+    {
+        gl::Buffer *buffer = context->getState().getIndexedShaderStorageBuffer(index).get();
+        if (buffer)
+        {
+            buffer->onDataChanged();
+        }
+    }
+}
+
 // Return true if the draw is a no-op, else return false.
 //  A no-op draw occurs if the count of vertices is less than the minimum required to
 //  have a valid primitive for this mode (0 for points, 0-1 for lines, 0-2 for tris).
diff --git a/src/libANGLE/Framebuffer.cpp b/src/libANGLE/Framebuffer.cpp
index 64acc8a..0346894 100644
--- a/src/libANGLE/Framebuffer.cpp
+++ b/src/libANGLE/Framebuffer.cpp
@@ -1512,7 +1512,7 @@
     Buffer *unpackBuffer = context->getState().getTargetBuffer(BufferBinding::PixelUnpack);
     if (unpackBuffer)
     {
-        unpackBuffer->onPixelPack();
+        unpackBuffer->onDataChanged();
     }
 
     return angle::Result::Continue;
diff --git a/src/libANGLE/TransformFeedback.cpp b/src/libANGLE/TransformFeedback.cpp
index 3222f14..129f9c0 100644
--- a/src/libANGLE/TransformFeedback.cpp
+++ b/src/libANGLE/TransformFeedback.cpp
@@ -214,7 +214,7 @@
     {
         if (buffer.get() != nullptr)
         {
-            buffer->onTransformFeedback();
+            buffer->onDataChanged();
         }
     }
 }
diff --git a/src/libANGLE/angletypes.h b/src/libANGLE/angletypes.h
index d859073..8c36ab1 100644
--- a/src/libANGLE/angletypes.h
+++ b/src/libANGLE/angletypes.h
@@ -387,6 +387,9 @@
 // Used in Framebuffer / Program
 using DrawBufferMask = angle::BitSet<IMPLEMENTATION_MAX_DRAW_BUFFERS>;
 
+// Used in StateCache
+using StorageBuffersMask = angle::BitSet<IMPLEMENTATION_MAX_SHADER_STORAGE_BUFFER_BINDINGS>;
+
 template <typename T>
 using TexLevelArray = std::array<T, IMPLEMENTATION_MAX_TEXTURE_LEVELS>;
 
diff --git a/src/libANGLE/renderer/BufferImpl.h b/src/libANGLE/renderer/BufferImpl.h
index 77b7737..ae52f7f 100644
--- a/src/libANGLE/renderer/BufferImpl.h
+++ b/src/libANGLE/renderer/BufferImpl.h
@@ -68,6 +68,8 @@
     // Override if accurate native memory size information is available
     virtual GLint64 getMemorySize() const;
 
+    virtual void onDataChanged() {}
+
   protected:
     const gl::BufferState &mState;
 };
diff --git a/src/libANGLE/renderer/vulkan/BufferVk.cpp b/src/libANGLE/renderer/vulkan/BufferVk.cpp
index cc555a3..6f84f89 100644
--- a/src/libANGLE/renderer/vulkan/BufferVk.cpp
+++ b/src/libANGLE/renderer/vulkan/BufferVk.cpp
@@ -377,4 +377,9 @@
     }
 }
 
+void BufferVk::onDataChanged()
+{
+    markConversionBuffersDirty();
+}
+
 }  // namespace rx
diff --git a/src/libANGLE/renderer/vulkan/BufferVk.h b/src/libANGLE/renderer/vulkan/BufferVk.h
index cd4a593..fecf5eb 100644
--- a/src/libANGLE/renderer/vulkan/BufferVk.h
+++ b/src/libANGLE/renderer/vulkan/BufferVk.h
@@ -79,6 +79,8 @@
 
     GLint64 getSize() const { return mState.getSize(); }
 
+    void onDataChanged() override;
+
     const vk::BufferHelper &getBuffer() const
     {
         ASSERT(mBuffer.valid());
diff --git a/src/libANGLE/renderer/vulkan/RendererVk.cpp b/src/libANGLE/renderer/vulkan/RendererVk.cpp
index c1aeca4..11beebe 100644
--- a/src/libANGLE/renderer/vulkan/RendererVk.cpp
+++ b/src/libANGLE/renderer/vulkan/RendererVk.cpp
@@ -1123,6 +1123,13 @@
         maxVersion = std::min(maxVersion, gl::Version(3, 0));
     }
 
+    // ES3.1 requires at least a maximum offset of at least 2047.
+    // If the Vulkan implementation can't support that, we cannot support 3.1.
+    if (mPhysicalDeviceProperties.limits.maxVertexInputAttributeOffset < 2047)
+    {
+        maxVersion = std::min(maxVersion, gl::Version(3, 0));
+    }
+
     // Limit to ES2.0 if there are any blockers for 3.0.
 
     // If the command buffer doesn't support queries, we can't support ES3.
diff --git a/src/libANGLE/renderer/vulkan/vk_caps_utils.cpp b/src/libANGLE/renderer/vulkan/vk_caps_utils.cpp
index 5dac9f0..4b79129 100644
--- a/src/libANGLE/renderer/vulkan/vk_caps_utils.cpp
+++ b/src/libANGLE/renderer/vulkan/vk_caps_utils.cpp
@@ -142,8 +142,13 @@
 
     mNativeCaps.maxVertexAttributes           = limitsVk.maxVertexInputAttributes;
     mNativeCaps.maxVertexAttribBindings       = limitsVk.maxVertexInputBindings;
-    mNativeCaps.maxVertexAttribRelativeOffset = limitsVk.maxVertexInputAttributeOffset;
-    mNativeCaps.maxVertexAttribStride         = limitsVk.maxVertexInputBindingStride;
+    // Offset and stride are stored as uint16_t in PackedAttribDesc.
+    mNativeCaps.maxVertexAttribRelativeOffset =
+        std::min(static_cast<uint32_t>(std::numeric_limits<uint16_t>::max()),
+                 limitsVk.maxVertexInputAttributeOffset);
+    mNativeCaps.maxVertexAttribStride =
+        std::min(static_cast<uint32_t>(std::numeric_limits<uint16_t>::max()),
+                 limitsVk.maxVertexInputBindingStride);
 
     mNativeCaps.maxElementsIndices  = std::numeric_limits<GLint>::max();
     mNativeCaps.maxElementsVertices = std::numeric_limits<GLint>::max();
diff --git a/src/tests/gl_tests/VertexAttributeTest.cpp b/src/tests/gl_tests/VertexAttributeTest.cpp
index 8bc914b..e55cfeb 100644
--- a/src/tests/gl_tests/VertexAttributeTest.cpp
+++ b/src/tests/gl_tests/VertexAttributeTest.cpp
@@ -1358,7 +1358,7 @@
     glUseProgram(computeProgram);
     glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, testBuffer);
     glDispatchCompute(1, 1, 1);
-    glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT);
+    glMemoryBarrier(GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT);
 
     // Draw again to verify that testBuffer has been changed.
     glUseProgram(mProgram);
@@ -1449,6 +1449,8 @@
 // Verify that only updating a binding without updating the bound format won't mess up this draw.
 TEST_P(VertexAttributeTestES31, OnlyUpdateBindingByBindVertexBuffer)
 {
+    ANGLE_SKIP_TEST_IF(IsVulkan());  // anglebug.com/3598 - vertex attrib binding
+
     // Default binding index for test
     constexpr GLint kTestBinding = 10;
     initOnlyUpdateBindingTest(kTestBinding);
@@ -1486,6 +1488,8 @@
 // Verify that only updating a binding without updating the bound format won't mess up this draw.
 TEST_P(VertexAttributeTestES31, OnlyUpdateBindingByVertexAttribPointer)
 {
+    ANGLE_SKIP_TEST_IF(IsVulkan());  // anglebug.com/3598 - vertex attrib binding
+
     // Default binding index for test
     constexpr GLint kTestBinding = 10;
     initOnlyUpdateBindingTest(kTestBinding);
@@ -2053,7 +2057,11 @@
                        ES3_OPENGLES(),
                        ES3_VULKAN());
 
-ANGLE_INSTANTIATE_TEST(VertexAttributeTestES31, ES31_D3D11(), ES31_OPENGL(), ES31_OPENGLES());
+ANGLE_INSTANTIATE_TEST(VertexAttributeTestES31,
+                       ES31_D3D11(),
+                       ES31_OPENGL(),
+                       ES31_OPENGLES(),
+                       ES31_VULKAN());
 
 ANGLE_INSTANTIATE_TEST(VertexAttributeCachingTest,
                        ES2_D3D9(),