Construct VertexAttributeDescriptor, in order to match web idl

The parameters about vertex attribute were encapsulated in
VertexAttributeDescriptor in web idl. This change construct
this descriptor accordingly.

BUG=dawn:107

Change-Id: Ia1c6e53af951d8f2a0c0b69bdca09291c2661e50
Reviewed-on: https://dawn-review.googlesource.com/c/4620
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Reviewed-by: Kai Ninomiya <kainino@chromium.org>
Commit-Queue: Yunchao He <yunchao.he@intel.com>
diff --git a/dawn.json b/dawn.json
index fa0c664..f9c4003 100644
--- a/dawn.json
+++ b/dawn.json
@@ -594,6 +594,16 @@
             {"value": 1, "name": "uint32"}
         ]
     },
+    "vertex attribute descriptor": {
+        "category": "structure",
+        "extensible": false,
+        "members": [
+            {"name": "shader location", "type": "uint32_t"},
+            {"name": "input slot", "type": "uint32_t"},
+            {"name": "offset", "type": "uint32_t"},
+            {"name": "format", "type": "vertex format"}
+        ]
+    },
     "input state": {
         "category": "object"
     },
@@ -607,10 +617,7 @@
             {
                 "name": "set attribute",
                 "args": [
-                    {"name": "shader location", "type": "uint32_t"},
-                    {"name": "binding slot", "type": "uint32_t"},
-                    {"name": "format", "type": "vertex format"},
-                    {"name": "offset", "type": "uint32_t"}
+                    {"name": "attribute", "type": "vertex attribute descriptor", "annotation": "const*"}
                 ]
             },
             {
diff --git a/examples/ComputeBoids.cpp b/examples/ComputeBoids.cpp
index ce5668c..fd5b906 100644
--- a/examples/ComputeBoids.cpp
+++ b/examples/ComputeBoids.cpp
@@ -114,13 +114,31 @@
         }
     )");
 
+    dawn::VertexAttributeDescriptor attribute1;
+    attribute1.shaderLocation = 0;
+    attribute1.inputSlot = 0;
+    attribute1.offset = offsetof(Particle, pos);
+    attribute1.format = dawn::VertexFormat::FloatR32G32;
+
+    dawn::VertexAttributeDescriptor attribute2;
+    attribute2.shaderLocation = 1;
+    attribute2.inputSlot = 0;
+    attribute2.offset = offsetof(Particle, vel);
+    attribute2.format = dawn::VertexFormat::FloatR32G32;
+
+    dawn::VertexAttributeDescriptor attribute3;
+    attribute3.shaderLocation = 2;
+    attribute3.inputSlot = 1;
+    attribute3.offset = 0;
+    attribute3.format = dawn::VertexFormat::FloatR32G32;
+
     dawn::InputState inputState = device.CreateInputStateBuilder()
-        .SetAttribute(0, 0, dawn::VertexFormat::FloatR32G32, offsetof(Particle, pos))
-        .SetAttribute(1, 0, dawn::VertexFormat::FloatR32G32, offsetof(Particle, vel))
-        .SetInput(0, sizeof(Particle), dawn::InputStepMode::Instance)
-        .SetAttribute(2, 1, dawn::VertexFormat::FloatR32G32, 0)
-        .SetInput(1, sizeof(glm::vec2), dawn::InputStepMode::Vertex)
-        .GetResult();
+                                      .SetAttribute(&attribute1)
+                                      .SetAttribute(&attribute2)
+                                      .SetInput(0, sizeof(Particle), dawn::InputStepMode::Instance)
+                                      .SetAttribute(&attribute3)
+                                      .SetInput(1, sizeof(glm::vec2), dawn::InputStepMode::Vertex)
+                                      .GetResult();
 
     depthStencilView = CreateDefaultDepthStencilView(device);
 
diff --git a/examples/CppHelloTriangle.cpp b/examples/CppHelloTriangle.cpp
index 7aca392..3719199 100644
--- a/examples/CppHelloTriangle.cpp
+++ b/examples/CppHelloTriangle.cpp
@@ -111,10 +111,15 @@
             fragColor = texture(sampler2D(myTexture, mySampler), gl_FragCoord.xy / vec2(640.0, 480.0));
         })");
 
+    dawn::VertexAttributeDescriptor attribute;
+    attribute.shaderLocation = 0;
+    attribute.inputSlot = 0;
+    attribute.offset = 0;
+    attribute.format = dawn::VertexFormat::FloatR32G32B32A32;
     auto inputState = device.CreateInputStateBuilder()
-        .SetAttribute(0, 0, dawn::VertexFormat::FloatR32G32B32A32, 0)
-        .SetInput(0, 4 * sizeof(float), dawn::InputStepMode::Vertex)
-        .GetResult();
+                          .SetAttribute(&attribute)
+                          .SetInput(0, 4 * sizeof(float), dawn::InputStepMode::Vertex)
+                          .GetResult();
 
     auto bgl = utils::MakeBindGroupLayout(
         device, {
diff --git a/examples/CubeReflection.cpp b/examples/CubeReflection.cpp
index 511baaf..c2d4ec9 100644
--- a/examples/CubeReflection.cpp
+++ b/examples/CubeReflection.cpp
@@ -156,11 +156,23 @@
             fragColor = vec4(mix(f_col, vec3(0.5, 0.5, 0.5), 0.5), 1.0);
         })");
 
+    dawn::VertexAttributeDescriptor attribute1;
+    attribute1.shaderLocation = 0;
+    attribute1.inputSlot = 0;
+    attribute1.offset = 0;
+    attribute1.format = dawn::VertexFormat::FloatR32G32B32;
+
+    dawn::VertexAttributeDescriptor attribute2;
+    attribute2.shaderLocation = 1;
+    attribute2.inputSlot = 0;
+    attribute2.offset = 3 * sizeof(float);
+    attribute2.format = dawn::VertexFormat::FloatR32G32B32;
+
     auto inputState = device.CreateInputStateBuilder()
-        .SetAttribute(0, 0, dawn::VertexFormat::FloatR32G32B32, 0)
-        .SetAttribute(1, 0, dawn::VertexFormat::FloatR32G32B32, 3 * sizeof(float))
-        .SetInput(0, 6 * sizeof(float), dawn::InputStepMode::Vertex)
-        .GetResult();
+                          .SetAttribute(&attribute1)
+                          .SetAttribute(&attribute2)
+                          .SetInput(0, 6 * sizeof(float), dawn::InputStepMode::Vertex)
+                          .GetResult();
 
     auto bgl = utils::MakeBindGroupLayout(
         device, {
diff --git a/examples/glTFViewer/glTFViewer.cpp b/examples/glTFViewer/glTFViewer.cpp
index acefd2a..d436cf4 100644
--- a/examples/glTFViewer/glTFViewer.cpp
+++ b/examples/glTFViewer/glTFViewer.cpp
@@ -247,16 +247,25 @@
                 fprintf(stderr, "unsupported technique parameter type %d\n", iParameter.type);
                 continue;
             }
+            dawn::VertexAttributeDescriptor attribute;
+            attribute.offset = 0;
+            attribute.format = format;
             if (iParameter.semantic == "POSITION") {
-                builder.SetAttribute(0, 0, format, 0);
+                attribute.shaderLocation = 0;
+                attribute.inputSlot = 0;
+                builder.SetAttribute(&attribute);
                 builder.SetInput(0, static_cast<uint32_t>(stridePos), dawn::InputStepMode::Vertex);
                 slotsSet.set(0);
             } else if (iParameter.semantic == "NORMAL") {
-                builder.SetAttribute(1, 1, format, 0);
+                attribute.shaderLocation = 1;
+                attribute.inputSlot = 1;
+                builder.SetAttribute(&attribute);
                 builder.SetInput(1, static_cast<uint32_t>(strideNor), dawn::InputStepMode::Vertex);
                 slotsSet.set(1);
             } else if (iParameter.semantic == "TEXCOORD_0") {
-                builder.SetAttribute(2, 2, format, 0);
+                attribute.shaderLocation = 2;
+                attribute.inputSlot = 2;
+                builder.SetAttribute(&attribute);
                 builder.SetInput(2, static_cast<uint32_t>(strideTxc), dawn::InputStepMode::Vertex);
                 slotsSet.set(2);
             } else {
@@ -268,7 +277,13 @@
             if (slotsSet[i]) {
                 continue;
             }
-            builder.SetAttribute(i, i, dawn::VertexFormat::FloatR32G32B32A32, 0);
+            dawn::VertexAttributeDescriptor attribute;
+            attribute.offset = 0;
+            attribute.shaderLocation = i;
+            attribute.inputSlot = i;
+            attribute.format = dawn::VertexFormat::FloatR32G32B32A32;
+
+            builder.SetAttribute(&attribute);
             builder.SetInput(i, 0, dawn::InputStepMode::Vertex);
         }
         auto inputState = builder.GetResult();
diff --git a/src/dawn_native/InputState.cpp b/src/dawn_native/InputState.cpp
index 6e818f9..fb55b39 100644
--- a/src/dawn_native/InputState.cpp
+++ b/src/dawn_native/InputState.cpp
@@ -117,7 +117,7 @@
     InputStateBase* InputStateBuilder::GetResultImpl() {
         for (uint32_t location = 0; location < kMaxVertexAttributes; ++location) {
             if (mAttributesSetMask[location] &&
-                !mInputsSetMask[mAttributeInfos[location].bindingSlot]) {
+                !mInputsSetMask[mAttributeInfos[location].inputSlot]) {
                 HandleError("Attribute uses unset input");
                 return nullptr;
             }
@@ -126,28 +126,25 @@
         return GetDevice()->CreateInputState(this);
     }
 
-    void InputStateBuilder::SetAttribute(uint32_t shaderLocation,
-                                         uint32_t bindingSlot,
-                                         dawn::VertexFormat format,
-                                         uint32_t offset) {
-        if (shaderLocation >= kMaxVertexAttributes) {
+    void InputStateBuilder::SetAttribute(const VertexAttributeDescriptor* attribute) {
+        if (attribute->shaderLocation >= kMaxVertexAttributes) {
             HandleError("Setting attribute out of bounds");
             return;
         }
-        if (bindingSlot >= kMaxVertexInputs) {
+        if (attribute->inputSlot >= kMaxVertexInputs) {
             HandleError("Binding slot out of bounds");
             return;
         }
-        if (mAttributesSetMask[shaderLocation]) {
+        if (mAttributesSetMask[attribute->shaderLocation]) {
             HandleError("Setting already set attribute");
             return;
         }
 
-        mAttributesSetMask.set(shaderLocation);
-        auto& info = mAttributeInfos[shaderLocation];
-        info.bindingSlot = bindingSlot;
-        info.format = format;
-        info.offset = offset;
+        mAttributesSetMask.set(attribute->shaderLocation);
+        auto& info = mAttributeInfos[attribute->shaderLocation];
+        info.inputSlot = attribute->inputSlot;
+        info.offset = attribute->offset;
+        info.format = attribute->format;
     }
 
     void InputStateBuilder::SetInput(uint32_t bindingSlot,
diff --git a/src/dawn_native/InputState.h b/src/dawn_native/InputState.h
index 05519b2..a9ca43a 100644
--- a/src/dawn_native/InputState.h
+++ b/src/dawn_native/InputState.h
@@ -37,7 +37,7 @@
         InputStateBase(InputStateBuilder* builder);
 
         struct AttributeInfo {
-            uint32_t bindingSlot;
+            uint32_t inputSlot;
             dawn::VertexFormat format;
             uint32_t offset;
         };
@@ -64,10 +64,7 @@
         InputStateBuilder(DeviceBase* device);
 
         // Dawn API
-        void SetAttribute(uint32_t shaderLocation,
-                          uint32_t bindingSlot,
-                          dawn::VertexFormat format,
-                          uint32_t offset);
+        void SetAttribute(const VertexAttributeDescriptor* attribute);
         void SetInput(uint32_t bindingSlot, uint32_t stride, dawn::InputStepMode stepMode);
 
       private:
diff --git a/src/dawn_native/d3d12/InputStateD3D12.cpp b/src/dawn_native/d3d12/InputStateD3D12.cpp
index 3469f9e..9178423 100644
--- a/src/dawn_native/d3d12/InputStateD3D12.cpp
+++ b/src/dawn_native/d3d12/InputStateD3D12.cpp
@@ -78,9 +78,9 @@
             inputElementDescriptor.SemanticName = "TEXCOORD";
             inputElementDescriptor.SemanticIndex = static_cast<uint32_t>(i);
             inputElementDescriptor.Format = VertexFormatType(attribute.format);
-            inputElementDescriptor.InputSlot = attribute.bindingSlot;
+            inputElementDescriptor.InputSlot = attribute.inputSlot;
 
-            const InputInfo& input = GetInput(attribute.bindingSlot);
+            const InputInfo& input = GetInput(attribute.inputSlot);
 
             inputElementDescriptor.AlignedByteOffset = attribute.offset;
             inputElementDescriptor.InputSlotClass = InputStepModeFunction(input.stepMode);
diff --git a/src/dawn_native/metal/InputStateMTL.mm b/src/dawn_native/metal/InputStateMTL.mm
index 1dd94d2..d21b2e7 100644
--- a/src/dawn_native/metal/InputStateMTL.mm
+++ b/src/dawn_native/metal/InputStateMTL.mm
@@ -71,7 +71,7 @@
             auto attribDesc = [MTLVertexAttributeDescriptor new];
             attribDesc.format = VertexFormatType(info.format);
             attribDesc.offset = info.offset;
-            attribDesc.bufferIndex = kMaxBindingsPerGroup + info.bindingSlot;
+            attribDesc.bufferIndex = kMaxBindingsPerGroup + info.inputSlot;
             mMtlVertexDescriptor.attributes[i] = attribDesc;
             [attribDesc release];
         }
diff --git a/src/dawn_native/opengl/InputStateGL.cpp b/src/dawn_native/opengl/InputStateGL.cpp
index 6ecaf8f..f9052e2 100644
--- a/src/dawn_native/opengl/InputStateGL.cpp
+++ b/src/dawn_native/opengl/InputStateGL.cpp
@@ -29,8 +29,8 @@
             auto attribute = GetAttribute(location);
             glEnableVertexAttribArray(location);
 
-            attributesUsingInput[attribute.bindingSlot][location] = true;
-            auto input = GetInput(attribute.bindingSlot);
+            attributesUsingInput[attribute.inputSlot][location] = true;
+            auto input = GetInput(attribute.inputSlot);
 
             if (input.stride == 0) {
                 // Emulate a stride of zero (constant vertex attribute) by
diff --git a/src/dawn_native/vulkan/InputStateVk.cpp b/src/dawn_native/vulkan/InputStateVk.cpp
index 1852702..2e8b5f5 100644
--- a/src/dawn_native/vulkan/InputStateVk.cpp
+++ b/src/dawn_native/vulkan/InputStateVk.cpp
@@ -85,7 +85,7 @@
 
             auto& attributeDesc = mAttributes[attributeCount];
             attributeDesc.location = i;
-            attributeDesc.binding = attributeInfo.bindingSlot;
+            attributeDesc.binding = attributeInfo.inputSlot;
             attributeDesc.format = VulkanVertexFormat(attributeInfo.format);
             attributeDesc.offset = attributeInfo.offset;
 
diff --git a/src/tests/end2end/DrawIndexedTests.cpp b/src/tests/end2end/DrawIndexedTests.cpp
index 4d0701c..b824b9a 100644
--- a/src/tests/end2end/DrawIndexedTests.cpp
+++ b/src/tests/end2end/DrawIndexedTests.cpp
@@ -26,10 +26,17 @@
 
             renderPass = utils::CreateBasicRenderPass(device, kRTSize, kRTSize);
 
-            dawn::InputState inputState = device.CreateInputStateBuilder()
-                .SetInput(0, 4 * sizeof(float), dawn::InputStepMode::Vertex)
-                .SetAttribute(0, 0, dawn::VertexFormat::FloatR32G32B32A32, 0)
-                .GetResult();
+            dawn::VertexAttributeDescriptor attribute;
+            attribute.shaderLocation = 0;
+            attribute.inputSlot = 0;
+            attribute.offset = 0;
+            attribute.format = dawn::VertexFormat::FloatR32G32B32A32;
+
+            dawn::InputState inputState =
+                device.CreateInputStateBuilder()
+                    .SetInput(0, 4 * sizeof(float), dawn::InputStepMode::Vertex)
+                    .SetAttribute(&attribute)
+                    .GetResult();
 
             dawn::ShaderModule vsModule = utils::CreateShaderModule(device, dawn::ShaderStage::Vertex, R"(
                 #version 450
diff --git a/src/tests/end2end/DrawTests.cpp b/src/tests/end2end/DrawTests.cpp
index 0df0d90..7f818dc 100644
--- a/src/tests/end2end/DrawTests.cpp
+++ b/src/tests/end2end/DrawTests.cpp
@@ -26,10 +26,16 @@
 
         renderPass = utils::CreateBasicRenderPass(device, kRTSize, kRTSize);
 
+        dawn::VertexAttributeDescriptor attribute;
+        attribute.shaderLocation = 0;
+        attribute.inputSlot = 0;
+        attribute.offset = 0;
+        attribute.format = dawn::VertexFormat::FloatR32G32B32A32;
+
         dawn::InputState inputState =
             device.CreateInputStateBuilder()
                 .SetInput(0, 4 * sizeof(float), dawn::InputStepMode::Vertex)
-                .SetAttribute(0, 0, dawn::VertexFormat::FloatR32G32B32A32, 0)
+                .SetAttribute(&attribute)
                 .GetResult();
 
         dawn::ShaderModule vsModule =
diff --git a/src/tests/end2end/IndexFormatTests.cpp b/src/tests/end2end/IndexFormatTests.cpp
index 4191862..8e5fb10 100644
--- a/src/tests/end2end/IndexFormatTests.cpp
+++ b/src/tests/end2end/IndexFormatTests.cpp
@@ -31,10 +31,17 @@
         utils::BasicRenderPass renderPass;
 
         dawn::RenderPipeline MakeTestPipeline(dawn::IndexFormat format) {
-            dawn::InputState inputState = device.CreateInputStateBuilder()
-                .SetInput(0, 4 * sizeof(float), dawn::InputStepMode::Vertex)
-                .SetAttribute(0, 0, dawn::VertexFormat::FloatR32G32B32A32, 0)
-                .GetResult();
+            dawn::VertexAttributeDescriptor attribute;
+            attribute.shaderLocation = 0;
+            attribute.inputSlot = 0;
+            attribute.offset = 0;
+            attribute.format = dawn::VertexFormat::FloatR32G32B32A32;
+
+            dawn::InputState inputState =
+                device.CreateInputStateBuilder()
+                    .SetInput(0, 4 * sizeof(float), dawn::InputStepMode::Vertex)
+                    .SetAttribute(&attribute)
+                    .GetResult();
 
             dawn::ShaderModule vsModule = utils::CreateShaderModule(device, dawn::ShaderStage::Vertex, R"(
                 #version 450
diff --git a/src/tests/end2end/InputStateTests.cpp b/src/tests/end2end/InputStateTests.cpp
index 180d8a8..73a2b61 100644
--- a/src/tests/end2end/InputStateTests.cpp
+++ b/src/tests/end2end/InputStateTests.cpp
@@ -149,7 +149,13 @@
             }
 
             for (const auto& attribute : attributes) {
-                builder.SetAttribute(attribute.location, attribute.slot, attribute.format, attribute.offset);
+                dawn::VertexAttributeDescriptor descriptor;
+                descriptor.shaderLocation = attribute.location;
+                descriptor.inputSlot = attribute.slot;
+                descriptor.offset = attribute.offset;
+                descriptor.format = attribute.format;
+
+                builder.SetAttribute(&descriptor);
             }
 
             return builder.GetResult();
diff --git a/src/tests/end2end/PrimitiveTopologyTests.cpp b/src/tests/end2end/PrimitiveTopologyTests.cpp
index 465f502..193414e 100644
--- a/src/tests/end2end/PrimitiveTopologyTests.cpp
+++ b/src/tests/end2end/PrimitiveTopologyTests.cpp
@@ -165,10 +165,16 @@
                     fragColor = vec4(0.0, 1.0, 0.0, 1.0);
                 })");
 
+            dawn::VertexAttributeDescriptor attribute;
+            attribute.shaderLocation = 0;
+            attribute.inputSlot = 0;
+            attribute.offset = 0;
+            attribute.format = dawn::VertexFormat::FloatR32G32B32A32;
+
             inputState = device.CreateInputStateBuilder()
-                .SetAttribute(0, 0, dawn::VertexFormat::FloatR32G32B32A32, 0)
-                .SetInput(0, 4 * sizeof(float), dawn::InputStepMode::Vertex)
-                .GetResult();
+                             .SetAttribute(&attribute)
+                             .SetInput(0, 4 * sizeof(float), dawn::InputStepMode::Vertex)
+                             .GetResult();
 
             vertexBuffer = utils::CreateBufferFromData(device, kVertices, sizeof(kVertices), dawn::BufferUsageBit::Vertex);
         }
diff --git a/src/tests/unittests/validation/InputStateValidationTests.cpp b/src/tests/unittests/validation/InputStateValidationTests.cpp
index eb62128..c4909f1 100644
--- a/src/tests/unittests/validation/InputStateValidationTests.cpp
+++ b/src/tests/unittests/validation/InputStateValidationTests.cpp
@@ -60,11 +60,23 @@
 
 // Check validation that pipeline vertex inputs are backed by attributes in the input state
 TEST_F(InputStateTest, PipelineCompatibility) {
+    dawn::VertexAttributeDescriptor attribute1;
+    attribute1.shaderLocation = 0;
+    attribute1.inputSlot = 0;
+    attribute1.offset = 0;
+    attribute1.format = dawn::VertexFormat::FloatR32;
+
+    dawn::VertexAttributeDescriptor attribute2;
+    attribute2.shaderLocation = 1;
+    attribute2.inputSlot = 0;
+    attribute2.offset = sizeof(float);
+    attribute2.format = dawn::VertexFormat::FloatR32;
+
     dawn::InputState state = AssertWillBeSuccess(device.CreateInputStateBuilder())
-        .SetInput(0, 2 * sizeof(float), dawn::InputStepMode::Vertex)
-        .SetAttribute(0, 0, dawn::VertexFormat::FloatR32, 0)
-        .SetAttribute(1, 0, dawn::VertexFormat::FloatR32, sizeof(float))
-        .GetResult();
+                                 .SetInput(0, 2 * sizeof(float), dawn::InputStepMode::Vertex)
+                                 .SetAttribute(&attribute1)
+                                 .SetAttribute(&attribute2)
+                                 .GetResult();
 
     // Control case: pipeline with one input per attribute
     CreatePipeline(true, state, R"(
@@ -103,9 +115,15 @@
         .GetResult();
 
     // Works ok with attributes at a large-ish offset
+    dawn::VertexAttributeDescriptor attribute;
+    attribute.shaderLocation = 0;
+    attribute.inputSlot = 0;
+    attribute.offset = 128;
+    attribute.format = dawn::VertexFormat::FloatR32;
+
     AssertWillBeSuccess(device.CreateInputStateBuilder())
         .SetInput(0, 0, dawn::InputStepMode::Vertex)
-        .SetAttribute(0, 0, dawn::VertexFormat::FloatR32, 128)
+        .SetAttribute(&attribute)
         .GetResult();
 }
 
@@ -139,60 +157,87 @@
 // Test that we cannot set an already set attribute
 TEST_F(InputStateTest, AlreadySetAttribute) {
     // Control case, setting last attribute
+    dawn::VertexAttributeDescriptor attribute;
+    attribute.shaderLocation = 0;
+    attribute.inputSlot = 0;
+    attribute.offset = 0;
+    attribute.format = dawn::VertexFormat::FloatR32;
+
     AssertWillBeSuccess(device.CreateInputStateBuilder())
         .SetInput(0, 0, dawn::InputStepMode::Vertex)
-        .SetAttribute(0, 0, dawn::VertexFormat::FloatR32, 0)
+        .SetAttribute(&attribute)
         .GetResult();
 
     // Oh no, attribute 0 is set twice
     AssertWillBeError(device.CreateInputStateBuilder())
         .SetInput(0, 0, dawn::InputStepMode::Vertex)
-        .SetAttribute(0, 0, dawn::VertexFormat::FloatR32, 0)
-        .SetAttribute(0, 0, dawn::VertexFormat::FloatR32, 0)
+        .SetAttribute(&attribute)
+        .SetAttribute(&attribute)
         .GetResult();
 }
 
 // Check out of bounds condition on SetAttribute
 TEST_F(InputStateTest, SetAttributeOutOfBounds) {
     // Control case, setting last attribute
+    dawn::VertexAttributeDescriptor attribute;
+    attribute.shaderLocation = kMaxVertexAttributes - 1;
+    attribute.inputSlot = 0;
+    attribute.offset = 0;
+    attribute.format = dawn::VertexFormat::FloatR32;
+
     AssertWillBeSuccess(device.CreateInputStateBuilder())
         .SetInput(0, 0, dawn::InputStepMode::Vertex)
-        .SetAttribute(kMaxVertexAttributes - 1, 0, dawn::VertexFormat::FloatR32, 0)
+        .SetAttribute(&attribute)
         .GetResult();
 
     // Test OOB
+    attribute.shaderLocation = kMaxVertexAttributes;
     AssertWillBeError(device.CreateInputStateBuilder())
         .SetInput(0, 0, dawn::InputStepMode::Vertex)
-        .SetAttribute(kMaxVertexAttributes, 0, dawn::VertexFormat::FloatR32, 0)
+        .SetAttribute(&attribute)
         .GetResult();
 }
 
 // Check that all attributes must be backed by an input
 TEST_F(InputStateTest, RequireInputForAttribute) {
     // Control case
+    dawn::VertexAttributeDescriptor attribute;
+    attribute.shaderLocation = 0;
+    attribute.inputSlot = 0;
+    attribute.offset = 0;
+    attribute.format = dawn::VertexFormat::FloatR32;
+
     AssertWillBeSuccess(device.CreateInputStateBuilder())
         .SetInput(0, 0, dawn::InputStepMode::Vertex)
-        .SetAttribute(0, 0, dawn::VertexFormat::FloatR32, 0)
+        .SetAttribute(&attribute)
         .GetResult();
 
     // Attribute 0 uses input 1 which doesn't exist
+    attribute.inputSlot = 1;
     AssertWillBeError(device.CreateInputStateBuilder())
         .SetInput(0, 0, dawn::InputStepMode::Vertex)
-        .SetAttribute(0, 1, dawn::VertexFormat::FloatR32, 0)
+        .SetAttribute(&attribute)
         .GetResult();
 }
 
 // Check OOB checks for an attribute's input
 TEST_F(InputStateTest, SetAttributeOOBCheckForInputs) {
     // Control case
+    dawn::VertexAttributeDescriptor attribute;
+    attribute.shaderLocation = 0;
+    attribute.inputSlot = 0;
+    attribute.offset = 0;
+    attribute.format = dawn::VertexFormat::FloatR32;
+
     AssertWillBeSuccess(device.CreateInputStateBuilder())
         .SetInput(0, 0, dawn::InputStepMode::Vertex)
-        .SetAttribute(0, 0, dawn::VertexFormat::FloatR32, 0)
+        .SetAttribute(&attribute)
         .GetResult();
 
     // Could crash if we didn't check for OOB
+    attribute.inputSlot = 1000000;
     AssertWillBeError(device.CreateInputStateBuilder())
         .SetInput(0, 0, dawn::InputStepMode::Vertex)
-        .SetAttribute(0, 1000000, dawn::VertexFormat::FloatR32, 0)
+        .SetAttribute(&attribute)
         .GetResult();
 }
diff --git a/src/tests/unittests/validation/VertexBufferValidationTests.cpp b/src/tests/unittests/validation/VertexBufferValidationTests.cpp
index 4526891..8b0b053 100644
--- a/src/tests/unittests/validation/VertexBufferValidationTests.cpp
+++ b/src/tests/unittests/validation/VertexBufferValidationTests.cpp
@@ -71,8 +71,14 @@
 
         dawn::InputState MakeInputState(unsigned int numInputs) {
             auto builder = device.CreateInputStateBuilder();
+            dawn::VertexAttributeDescriptor attribute;
+            attribute.offset = 0;
+            attribute.format = dawn::VertexFormat::FloatR32G32B32;
+
             for (unsigned int i = 0; i < numInputs; ++i) {
-                builder.SetAttribute(i, i, dawn::VertexFormat::FloatR32G32B32, 0);
+                attribute.shaderLocation = i;
+                attribute.inputSlot = i;
+                builder.SetAttribute(&attribute);
                 builder.SetInput(i, 0, dawn::InputStepMode::Vertex);
             }
             return builder.GetResult();