Fix handling of dynamic vertex stride

Vertex and instance stride are derived from the vertex attribute stride
based on input rate.  For dynamic vertex stride, input rate was ignored, causing test failures in ANGLE.

Bug: angleproject:5906
Change-Id: Ie99a9d3ee9efed06fae459316d1d5db6001a3edc
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/65869
Tested-by: Alexis Hétu <sugoi@google.com>
Presubmit-Ready: Alexis Hétu <sugoi@google.com>
Commit-Queue: Alexis Hétu <sugoi@google.com>
Kokoro-Result: kokoro <noreply+kokoro@google.com>
Reviewed-by: Nicolas Capens <nicolascapens@google.com>
diff --git a/src/Device/Context.cpp b/src/Device/Context.cpp
index 1d25cc3..7bca3a8 100644
--- a/src/Device/Context.cpp
+++ b/src/Device/Context.cpp
@@ -173,9 +173,11 @@
 	// when considering attributes. TODO: unfuse buffers from attributes in backend, is old GL model.
 	uint32_t vertexStrides[MAX_VERTEX_INPUT_BINDINGS];
 	uint32_t instanceStrides[MAX_VERTEX_INPUT_BINDINGS];
+	VkVertexInputRate inputRates[MAX_VERTEX_INPUT_BINDINGS];
 	for(uint32_t i = 0; i < vertexInputState->vertexBindingDescriptionCount; i++)
 	{
 		auto const &desc = vertexInputState->pVertexBindingDescriptions[i];
+		inputRates[desc.binding] = desc.inputRate;
 		vertexStrides[desc.binding] = desc.inputRate == VK_VERTEX_INPUT_RATE_VERTEX ? desc.stride : 0;
 		instanceStrides[desc.binding] = desc.inputRate == VK_VERTEX_INPUT_RATE_INSTANCE ? desc.stride : 0;
 	}
@@ -187,6 +189,7 @@
 		input.format = desc.format;
 		input.offset = desc.offset;
 		input.binding = desc.binding;
+		input.inputRate = inputRates[desc.binding];
 		input.vertexStride = vertexStrides[desc.binding];
 		input.instanceStride = instanceStrides[desc.binding];
 	}
@@ -201,7 +204,7 @@
 	descriptorDynamicOffsets = ddo;
 }
 
-void Inputs::bindVertexInputs(int firstInstance)
+void Inputs::bindVertexInputs(int firstInstance, bool dynamicInstanceStride)
 {
 	for(uint32_t i = 0; i < MAX_VERTEX_INPUT_BINDINGS; i++)
 	{
@@ -210,7 +213,7 @@
 		{
 			const auto &vertexInput = vertexInputBindings[attrib.binding];
 			VkDeviceSize offset = attrib.offset + vertexInput.offset +
-			                      attrib.instanceStride * firstInstance;
+			                      getInstanceStride(i, dynamicInstanceStride) * firstInstance;
 			attrib.buffer = vertexInput.buffer ? vertexInput.buffer->getOffsetPointer(offset) : nullptr;
 
 			VkDeviceSize size = vertexInput.buffer ? vertexInput.buffer->getSize() : 0;
@@ -228,16 +231,18 @@
 }
 
 // TODO(b/137740918): Optimize instancing to use a single draw call.
-void Inputs::advanceInstanceAttributes()
+void Inputs::advanceInstanceAttributes(bool dynamicInstanceStride)
 {
 	for(uint32_t i = 0; i < vk::MAX_VERTEX_INPUT_BINDINGS; i++)
 	{
 		auto &attrib = stream[i];
-		if((attrib.format != VK_FORMAT_UNDEFINED) && attrib.instanceStride && (attrib.instanceStride < attrib.robustnessSize))
+
+		VkDeviceSize instanceStride = getInstanceStride(i, dynamicInstanceStride);
+		if((attrib.format != VK_FORMAT_UNDEFINED) && instanceStride && (instanceStride < attrib.robustnessSize))
 		{
-			// Under the casts: attrib.buffer += attrib.instanceStride
-			attrib.buffer = (void const *)((uintptr_t)attrib.buffer + attrib.instanceStride);
-			attrib.robustnessSize -= attrib.instanceStride;
+			// Under the casts: attrib.buffer += instanceStride
+			attrib.buffer = (void const *)((uintptr_t)attrib.buffer + instanceStride);
+			attrib.robustnessSize -= instanceStride;
 		}
 	}
 }
@@ -343,7 +348,7 @@
 VkDeviceSize Inputs::getVertexStride(uint32_t i, bool dynamicVertexStride) const
 {
 	auto &attrib = stream[i];
-	if(attrib.format != VK_FORMAT_UNDEFINED)
+	if(attrib.format != VK_FORMAT_UNDEFINED && attrib.inputRate == VK_VERTEX_INPUT_RATE_VERTEX)
 	{
 		if(dynamicVertexStride)
 		{
@@ -358,6 +363,24 @@
 	return 0;
 }
 
+VkDeviceSize Inputs::getInstanceStride(uint32_t i, bool dynamicInstanceStride) const
+{
+	auto &attrib = stream[i];
+	if(attrib.format != VK_FORMAT_UNDEFINED && attrib.inputRate == VK_VERTEX_INPUT_RATE_INSTANCE)
+	{
+		if(dynamicInstanceStride)
+		{
+			return vertexInputBindings[attrib.binding].stride;
+		}
+		else
+		{
+			return attrib.instanceStride;
+		}
+	}
+
+	return 0;
+}
+
 GraphicsState::GraphicsState(const Device *device, const VkGraphicsPipelineCreateInfo *pCreateInfo,
                              const PipelineLayout *layout, bool robustBufferAccess)
     : pipelineLayout(layout)
diff --git a/src/Device/Context.hpp b/src/Device/Context.hpp
index 5111da3..1e30d58 100644
--- a/src/Device/Context.hpp
+++ b/src/Device/Context.hpp
@@ -74,10 +74,11 @@
 	inline const DescriptorSet::DynamicOffsets &getDescriptorDynamicOffsets() const { return descriptorDynamicOffsets; }
 	inline const sw::Stream &getStream(uint32_t i) const { return stream[i]; }
 
-	void bindVertexInputs(int firstInstance);
+	void bindVertexInputs(int firstInstance, bool dynamicInstanceStride);
 	void setVertexInputBinding(const VertexInputBinding vertexInputBindings[]);
-	void advanceInstanceAttributes();
+	void advanceInstanceAttributes(bool dynamicInstanceStride);
 	VkDeviceSize getVertexStride(uint32_t i, bool dynamicVertexStride) const;
+	VkDeviceSize getInstanceStride(uint32_t i, bool dynamicVertexStride) const;
 
 private:
 	VertexInputBinding vertexInputBindings[MAX_VERTEX_INPUT_BINDINGS] = {};
diff --git a/src/Device/Stream.hpp b/src/Device/Stream.hpp
index 1004080..2e6e490 100644
--- a/src/Device/Stream.hpp
+++ b/src/Device/Stream.hpp
@@ -23,6 +23,7 @@
 {
 	const void *buffer = nullptr;
 	unsigned int robustnessSize = 0;
+	VkVertexInputRate inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
 	unsigned int vertexStride = 0;
 	unsigned int instanceStride = 0;
 	VkFormat format = VK_FORMAT_UNDEFINED;
diff --git a/src/Vulkan/VkCommandBuffer.cpp b/src/Vulkan/VkCommandBuffer.cpp
index 9d84afc..a33315c 100644
--- a/src/Vulkan/VkCommandBuffer.cpp
+++ b/src/Vulkan/VkCommandBuffer.cpp
@@ -899,6 +899,7 @@
 		auto const &pipelineState = executionState.pipelineState[VK_PIPELINE_BIND_POINT_GRAPHICS];
 
 		auto *pipeline = static_cast<vk::GraphicsPipeline *>(pipelineState.pipeline);
+		bool hasDynamicVertexStride = pipeline->hasDynamicVertexStride();
 
 		vk::Attachments &attachments = pipeline->getAttachments();
 		executionState.bindAttachments(&attachments);
@@ -908,7 +909,7 @@
 		                            pipelineState.descriptorSets,
 		                            pipelineState.descriptorDynamicOffsets);
 		inputs.setVertexInputBinding(executionState.vertexInputBindings);
-		inputs.bindVertexInputs(firstInstance);
+		inputs.bindVertexInputs(firstInstance, hasDynamicVertexStride);
 
 		vk::IndexBuffer &indexBuffer = pipeline->getIndexBuffer();
 		indexBuffer.setIndexBufferBinding(executionState.indexBufferBinding, executionState.indexType);
@@ -935,7 +936,7 @@
 				}
 			}
 
-			inputs.advanceInstanceAttributes();
+			inputs.advanceInstanceAttributes(hasDynamicVertexStride);
 		}
 	}
 };
diff --git a/src/Vulkan/VkPipeline.hpp b/src/Vulkan/VkPipeline.hpp
index 5da734d..39e605d 100644
--- a/src/Vulkan/VkPipeline.hpp
+++ b/src/Vulkan/VkPipeline.hpp
@@ -98,6 +98,7 @@
 	const GraphicsState getState(const DynamicState &ds) const { return state.combineStates(ds); }
 
 	void getIndexBuffers(const vk::DynamicState &dynamicState, uint32_t count, uint32_t first, bool indexed, std::vector<std::pair<uint32_t, void *>> *indexBuffers) const;
+	bool hasDynamicVertexStride() const { return state.hasDynamicVertexStride(); }
 
 	IndexBuffer &getIndexBuffer() { return indexBuffer; }
 	const IndexBuffer &getIndexBuffer() const { return indexBuffer; }