Reland "Fix zero stride in input state for Metal validation"

Update stride value to max(attribute.offset + sizeof(attribute) for
each attribute) when input stride is 0 in Metal backend

BUG=dawn:75
TEST=dawn_end2end_tests

Change-Id: I449532807f7fba1bca22106f2c38d496b8cbf01f
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/7020
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Reviewed-by: Kai Ninomiya <kainino@chromium.org>
Commit-Queue: Hao Li <hao.x.li@intel.com>
diff --git a/src/dawn_native/metal/RenderPipelineMTL.mm b/src/dawn_native/metal/RenderPipelineMTL.mm
index b96416c..0a92c93 100644
--- a/src/dawn_native/metal/RenderPipelineMTL.mm
+++ b/src/dawn_native/metal/RenderPipelineMTL.mm
@@ -421,12 +421,23 @@
             auto layoutDesc = [MTLVertexBufferLayoutDescriptor new];
             if (info.stride == 0) {
                 // For MTLVertexStepFunctionConstant, the stepRate must be 0,
-                // but the stride must NOT be 0, so I made up a value (256).
-                // TODO(cwallez@chromium.org): the made up value will need to be at least
-                //    max(attrib.offset + sizeof(attrib) for each attrib)
+                // but the stride must NOT be 0, so we made up it with
+                // max(attrib.offset + sizeof(attrib) for each attrib)
+                size_t max_stride = 0;
+                for (uint32_t attribIndex : IterateBitSet(GetAttributesSetMask())) {
+                    const VertexAttributeDescriptor& attrib = GetAttribute(attribIndex);
+                    // Only use the attributes that use the current input
+                    if (attrib.inputSlot != info.inputSlot) {
+                        continue;
+                    }
+                    max_stride = std::max(max_stride,
+                                          VertexFormatSize(attrib.format) + size_t(attrib.offset));
+                }
                 layoutDesc.stepFunction = MTLVertexStepFunctionConstant;
                 layoutDesc.stepRate = 0;
-                layoutDesc.stride = 256;
+                // Metal requires the stride must be a multiple of 4 bytes, align it with next
+                // multiple of 4 if it's not.
+                layoutDesc.stride = Align(max_stride, 4);
             } else {
                 layoutDesc.stepFunction = InputStepModeFunction(info.stepMode);
                 layoutDesc.stepRate = 1;