Update VertexInput (InputState) to match spec - Part 1

This is only a renaming: change VertexInput to VertexBuffer, and
change InputState to VertexInput.

The next two patches will do as follows:
1) change the structure of vertex input descriptor related stuff.
2) change num to count.

BUG=dawn:80, dawn:107

Change-Id: Ie76aa653a527759a9c3b4a4792e3254689f053b8
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/7420
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/BUILD.gn b/BUILD.gn
index 0110ac5..2ae8d92 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -573,7 +573,6 @@
     "src/tests/unittests/validation/DebugMarkerValidationTests.cpp",
     "src/tests/unittests/validation/DynamicStateCommandValidationTests.cpp",
     "src/tests/unittests/validation/FenceValidationTests.cpp",
-    "src/tests/unittests/validation/InputStateValidationTests.cpp",
     "src/tests/unittests/validation/PushConstantsValidationTests.cpp",
     "src/tests/unittests/validation/QueueSubmitValidationTests.cpp",
     "src/tests/unittests/validation/RenderPassDescriptorValidationTests.cpp",
@@ -587,6 +586,7 @@
     "src/tests/unittests/validation/ValidationTest.cpp",
     "src/tests/unittests/validation/ValidationTest.h",
     "src/tests/unittests/validation/VertexBufferValidationTests.cpp",
+    "src/tests/unittests/validation/VertexInputValidationTests.cpp",
     "src/tests/unittests/wire/WireArgumentTests.cpp",
     "src/tests/unittests/wire/WireBasicTests.cpp",
     "src/tests/unittests/wire/WireBufferMappingTests.cpp",
@@ -642,7 +642,6 @@
     "src/tests/end2end/DrawTests.cpp",
     "src/tests/end2end/FenceTests.cpp",
     "src/tests/end2end/IndexFormatTests.cpp",
-    "src/tests/end2end/InputStateTests.cpp",
     "src/tests/end2end/MultisampledRenderingTests.cpp",
     "src/tests/end2end/NonzeroTextureCreationTests.cpp",
     "src/tests/end2end/ObjectCachingTests.cpp",
@@ -654,6 +653,7 @@
     "src/tests/end2end/ScissorTests.cpp",
     "src/tests/end2end/TextureViewTests.cpp",
     "src/tests/end2end/VertexFormatTests.cpp",
+    "src/tests/end2end/VertexInputTests.cpp",
     "src/tests/end2end/ViewportOrientationTests.cpp",
   ]
 
diff --git a/dawn.json b/dawn.json
index b7a18ce..45bed41 100644
--- a/dawn.json
+++ b/dawn.json
@@ -597,7 +597,7 @@
             {"name": "format", "type": "vertex format"}
         ]
     },
-    "vertex input descriptor": {
+    "vertex buffer descriptor": {
         "category": "structure",
         "extensible": false,
         "members": [
@@ -606,15 +606,15 @@
             {"name": "step mode", "type": "input step mode"}
         ]
     },
-    "input state descriptor": {
+    "vertex input descriptor": {
         "category": "structure",
         "extensible": true,
         "members": [
             {"name": "index format", "type": "index format"},
             {"name": "num attributes", "type": "uint32_t"},
             {"name": "attributes", "type": "vertex attribute descriptor", "annotation": "const*", "length": "num attributes"},
-            {"name": "num inputs", "type": "uint32_t"},
-            {"name": "inputs", "type": "vertex input descriptor", "annotation": "const*", "length": "num inputs"}
+            {"name": "num buffers", "type": "uint32_t"},
+            {"name": "buffers", "type": "vertex buffer descriptor", "annotation": "const*", "length": "num buffers"}
         ]
     },
     "input step mode": {
@@ -864,7 +864,7 @@
             {"name": "layout", "type": "pipeline layout"},
             {"name": "vertex stage", "type": "pipeline stage descriptor", "annotation": "const*"},
             {"name": "fragment stage", "type": "pipeline stage descriptor", "annotation": "const*"},
-            {"name": "input state", "type": "input state descriptor", "annotation": "const*"},
+            {"name": "vertex input", "type": "vertex input descriptor", "annotation": "const*"},
             {"name": "primitive topology", "type": "primitive topology"},
             {"name": "rasterization state", "type": "rasterization state descriptor", "annotation": "const*"},
             {"name": "sample count", "type": "uint32_t"},
diff --git a/examples/CHelloTriangle.cpp b/examples/CHelloTriangle.cpp
index 5a5d8bb..d487253 100644
--- a/examples/CHelloTriangle.cpp
+++ b/examples/CHelloTriangle.cpp
@@ -93,14 +93,14 @@
         pl.bindGroupLayouts = nullptr;
         descriptor.layout = dawnDeviceCreatePipelineLayout(device, &pl);
 
-        DawnInputStateDescriptor inputState;
-        inputState.nextInChain = nullptr;
-        inputState.indexFormat = DAWN_INDEX_FORMAT_UINT32;
-        inputState.numInputs = 0;
-        inputState.inputs = nullptr;
-        inputState.numAttributes = 0;
-        inputState.attributes = nullptr;
-        descriptor.inputState = &inputState;
+        DawnVertexInputDescriptor vertexInput;
+        vertexInput.nextInChain = nullptr;
+        vertexInput.indexFormat = DAWN_INDEX_FORMAT_UINT32;
+        vertexInput.numBuffers = 0;
+        vertexInput.buffers = nullptr;
+        vertexInput.numAttributes = 0;
+        vertexInput.attributes = nullptr;
+        descriptor.vertexInput = &vertexInput;
 
         DawnRasterizationStateDescriptor rasterizationState;
         rasterizationState.nextInChain = nullptr;
diff --git a/examples/ComputeBoids.cpp b/examples/ComputeBoids.cpp
index ae4234c..beeffa4 100644
--- a/examples/ComputeBoids.cpp
+++ b/examples/ComputeBoids.cpp
@@ -120,20 +120,20 @@
     descriptor.cVertexStage.module = vsModule;
     descriptor.cFragmentStage.module = fsModule;
 
-    descriptor.cInputState.numAttributes = 3;
-    descriptor.cInputState.cAttributes[0].offset = offsetof(Particle, pos);
-    descriptor.cInputState.cAttributes[0].format = dawn::VertexFormat::Float2;
-    descriptor.cInputState.cAttributes[1].shaderLocation = 1;
-    descriptor.cInputState.cAttributes[1].offset = offsetof(Particle, vel);
-    descriptor.cInputState.cAttributes[1].format = dawn::VertexFormat::Float2;
-    descriptor.cInputState.cAttributes[2].shaderLocation = 2;
-    descriptor.cInputState.cAttributes[2].inputSlot = 1;
-    descriptor.cInputState.cAttributes[2].format = dawn::VertexFormat::Float2;
-    descriptor.cInputState.numInputs = 2;
-    descriptor.cInputState.cInputs[0].stride = sizeof(Particle);
-    descriptor.cInputState.cInputs[0].stepMode = dawn::InputStepMode::Instance;
-    descriptor.cInputState.cInputs[1].inputSlot = 1;
-    descriptor.cInputState.cInputs[1].stride = sizeof(glm::vec2);
+    descriptor.cVertexInput.numAttributes = 3;
+    descriptor.cVertexInput.cAttributes[0].offset = offsetof(Particle, pos);
+    descriptor.cVertexInput.cAttributes[0].format = dawn::VertexFormat::Float2;
+    descriptor.cVertexInput.cAttributes[1].shaderLocation = 1;
+    descriptor.cVertexInput.cAttributes[1].offset = offsetof(Particle, vel);
+    descriptor.cVertexInput.cAttributes[1].format = dawn::VertexFormat::Float2;
+    descriptor.cVertexInput.cAttributes[2].shaderLocation = 2;
+    descriptor.cVertexInput.cAttributes[2].inputSlot = 1;
+    descriptor.cVertexInput.cAttributes[2].format = dawn::VertexFormat::Float2;
+    descriptor.cVertexInput.numBuffers = 2;
+    descriptor.cVertexInput.cBuffers[0].stride = sizeof(Particle);
+    descriptor.cVertexInput.cBuffers[0].stepMode = dawn::InputStepMode::Instance;
+    descriptor.cVertexInput.cBuffers[1].inputSlot = 1;
+    descriptor.cVertexInput.cBuffers[1].stride = sizeof(glm::vec2);
     descriptor.depthStencilState = &descriptor.cDepthStencilState;
     descriptor.cDepthStencilState.format = dawn::TextureFormat::D32FloatS8Uint;
     descriptor.cColorStates[0]->format = GetPreferredSwapChainTextureFormat();
diff --git a/examples/CppHelloTriangle.cpp b/examples/CppHelloTriangle.cpp
index b560d79..a23b3e4 100644
--- a/examples/CppHelloTriangle.cpp
+++ b/examples/CppHelloTriangle.cpp
@@ -125,10 +125,10 @@
     descriptor.layout = utils::MakeBasicPipelineLayout(device, &bgl);
     descriptor.cVertexStage.module = vsModule;
     descriptor.cFragmentStage.module = fsModule;
-    descriptor.cInputState.numAttributes = 1;
-    descriptor.cInputState.cAttributes[0].format = dawn::VertexFormat::Float4;
-    descriptor.cInputState.numInputs = 1;
-    descriptor.cInputState.cInputs[0].stride = 4 * sizeof(float);
+    descriptor.cVertexInput.numAttributes = 1;
+    descriptor.cVertexInput.cAttributes[0].format = dawn::VertexFormat::Float4;
+    descriptor.cVertexInput.numBuffers = 1;
+    descriptor.cVertexInput.cBuffers[0].stride = 4 * sizeof(float);
     descriptor.depthStencilState = &descriptor.cDepthStencilState;
     descriptor.cDepthStencilState.format = dawn::TextureFormat::D32FloatS8Uint;
     descriptor.cColorStates[0]->format = GetPreferredSwapChainTextureFormat();
diff --git a/examples/CubeReflection.cpp b/examples/CubeReflection.cpp
index 56263d4..a848938 100644
--- a/examples/CubeReflection.cpp
+++ b/examples/CubeReflection.cpp
@@ -156,15 +156,15 @@
             fragColor = vec4(mix(f_col, vec3(0.5, 0.5, 0.5), 0.5), 1.0);
         })");
 
-    utils::ComboInputStateDescriptor inputState;
-    inputState.numAttributes = 2;
-    inputState.cAttributes[0].format = dawn::VertexFormat::Float3;
-    inputState.cAttributes[1].shaderLocation = 1;
-    inputState.cAttributes[1].offset = 3 * sizeof(float);
-    inputState.cAttributes[1].format = dawn::VertexFormat::Float3;
+    utils::ComboVertexInputDescriptor vertexInput;
+    vertexInput.numAttributes = 2;
+    vertexInput.cAttributes[0].format = dawn::VertexFormat::Float3;
+    vertexInput.cAttributes[1].shaderLocation = 1;
+    vertexInput.cAttributes[1].offset = 3 * sizeof(float);
+    vertexInput.cAttributes[1].format = dawn::VertexFormat::Float3;
 
-    inputState.numInputs = 1;
-    inputState.cInputs[0].stride = 6 * sizeof(float);
+    vertexInput.numBuffers = 1;
+    vertexInput.cBuffers[0].stride = 6 * sizeof(float);
 
     auto bgl = utils::MakeBindGroupLayout(
         device, {
@@ -201,7 +201,7 @@
     descriptor.layout = pl;
     descriptor.cVertexStage.module = vsModule;
     descriptor.cFragmentStage.module = fsModule;
-    descriptor.inputState = &inputState;
+    descriptor.vertexInput = &vertexInput;
     descriptor.depthStencilState = &descriptor.cDepthStencilState;
     descriptor.cDepthStencilState.format = dawn::TextureFormat::D32FloatS8Uint;
     descriptor.cColorStates[0]->format = GetPreferredSwapChainTextureFormat();
@@ -214,7 +214,7 @@
     pDescriptor.layout = pl;
     pDescriptor.cVertexStage.module = vsModule;
     pDescriptor.cFragmentStage.module = fsModule;
-    pDescriptor.inputState = &inputState;
+    pDescriptor.vertexInput = &vertexInput;
     pDescriptor.depthStencilState = &pDescriptor.cDepthStencilState;
     pDescriptor.cDepthStencilState.format = dawn::TextureFormat::D32FloatS8Uint;
     pDescriptor.cColorStates[0]->format = GetPreferredSwapChainTextureFormat();
@@ -228,7 +228,7 @@
     rfDescriptor.layout = pl;
     rfDescriptor.cVertexStage.module = vsModule;
     rfDescriptor.cFragmentStage.module = fsReflectionModule;
-    rfDescriptor.inputState = &inputState;
+    rfDescriptor.vertexInput = &vertexInput;
     rfDescriptor.depthStencilState = &rfDescriptor.cDepthStencilState;
     rfDescriptor.cDepthStencilState.format = dawn::TextureFormat::D32FloatS8Uint;
     rfDescriptor.cColorStates[0]->format = GetPreferredSwapChainTextureFormat();
diff --git a/src/common/Constants.h b/src/common/Constants.h
index 0a41dff..aa04501 100644
--- a/src/common/Constants.h
+++ b/src/common/Constants.h
@@ -24,12 +24,13 @@
 static constexpr uint32_t kMaxVertexAttributes = 16u;
 // Vulkan has a standalone limit named maxVertexInputAttributeOffset (2047u at least) for vertex
 // attribute offset. The limit might be meaningless because Vulkan has another limit named
-// maxVertexInputBindingStride (2048u at least). We use maxVertexAttributeEnd (2048u) here to verify
-// vertex attribute offset, which equals to maxOffset + smallest size of vertex format (char). We
-// may use maxVertexInputStride instead in future.
+// maxVertexInputBindingStride (2048u at least). We use maxVertexAttributeEnd (2048u) here to
+// verify vertex attribute offset, which equals to maxOffset + smallest size of vertex format
+// (char). We may use maxVertexInputBindingStride (maxVertexBufferStride below) instead to replace
+// maxVertexAttributeEnd in future.
 static constexpr uint32_t kMaxVertexAttributeEnd = 2048u;
-static constexpr uint32_t kMaxVertexInputs = 16u;
-static constexpr uint32_t kMaxVertexInputStride = 2048u;
+static constexpr uint32_t kMaxVertexBuffers = 16u;
+static constexpr uint32_t kMaxVertexBufferStride = 2048u;
 static constexpr uint32_t kNumStages = 3;
 static constexpr uint32_t kMaxColorAttachments = 4u;
 static constexpr uint32_t kTextureRowPitchAlignment = 256u;
diff --git a/src/dawn_native/CommandBufferStateTracker.h b/src/dawn_native/CommandBufferStateTracker.h
index f2580e4..2009dd7 100644
--- a/src/dawn_native/CommandBufferStateTracker.h
+++ b/src/dawn_native/CommandBufferStateTracker.h
@@ -53,7 +53,7 @@
         ValidationAspects mAspects;
 
         std::array<BindGroupBase*, kMaxBindGroups> mBindgroups = {};
-        std::bitset<kMaxVertexInputs> mInputsSet;
+        std::bitset<kMaxVertexBuffers> mInputsSet;
 
         PipelineLayoutBase* mLastPipelineLayout = nullptr;
         RenderPipelineBase* mLastRenderPipeline = nullptr;
diff --git a/src/dawn_native/RenderPipeline.cpp b/src/dawn_native/RenderPipeline.cpp
index e44d287..699c992 100644
--- a/src/dawn_native/RenderPipeline.cpp
+++ b/src/dawn_native/RenderPipeline.cpp
@@ -25,33 +25,33 @@
     // Helper functions
     namespace {
 
-        MaybeError ValidateVertexInputDescriptor(const VertexInputDescriptor* input,
-                                                 std::bitset<kMaxVertexInputs>* inputsSetMask) {
-            DAWN_TRY(ValidateInputStepMode(input->stepMode));
-            if (input->inputSlot >= kMaxVertexInputs) {
-                return DAWN_VALIDATION_ERROR("Setting input out of bounds");
+        MaybeError ValidateVertexBufferDescriptor(const VertexBufferDescriptor* buffer,
+                                                  std::bitset<kMaxVertexBuffers>* inputsSetMask) {
+            DAWN_TRY(ValidateInputStepMode(buffer->stepMode));
+            if (buffer->inputSlot >= kMaxVertexBuffers) {
+                return DAWN_VALIDATION_ERROR("Setting vertex buffer out of bounds");
             }
-            if (input->stride > kMaxVertexInputStride) {
+            if (buffer->stride > kMaxVertexBufferStride) {
                 return DAWN_VALIDATION_ERROR("Setting input stride out of bounds");
             }
-            if ((*inputsSetMask)[input->inputSlot]) {
-                return DAWN_VALIDATION_ERROR("Setting already set input");
+            if ((*inputsSetMask)[buffer->inputSlot]) {
+                return DAWN_VALIDATION_ERROR("Setting already set vertex buffer");
             }
 
-            inputsSetMask->set(input->inputSlot);
+            inputsSetMask->set(buffer->inputSlot);
             return {};
         }
 
         MaybeError ValidateVertexAttributeDescriptor(
             const VertexAttributeDescriptor* attribute,
-            const std::bitset<kMaxVertexInputs>* inputsSetMask,
+            const std::bitset<kMaxVertexBuffers>* inputsSetMask,
             std::bitset<kMaxVertexAttributes>* attributesSetMask) {
             DAWN_TRY(ValidateVertexFormat(attribute->format));
 
             if (attribute->shaderLocation >= kMaxVertexAttributes) {
                 return DAWN_VALIDATION_ERROR("Setting attribute out of bounds");
             }
-            if (attribute->inputSlot >= kMaxVertexInputs) {
+            if (attribute->inputSlot >= kMaxVertexBuffers) {
                 return DAWN_VALIDATION_ERROR("Binding slot out of bounds");
             }
             ASSERT(kMaxVertexAttributeEnd >= VertexFormatSize(attribute->format));
@@ -70,24 +70,24 @@
             return {};
         }
 
-        MaybeError ValidateInputStateDescriptor(
-            const InputStateDescriptor* descriptor,
-            std::bitset<kMaxVertexInputs>* inputsSetMask,
+        MaybeError ValidateVertexInputDescriptor(
+            const VertexInputDescriptor* descriptor,
+            std::bitset<kMaxVertexBuffers>* inputsSetMask,
             std::bitset<kMaxVertexAttributes>* attributesSetMask) {
             if (descriptor->nextInChain != nullptr) {
                 return DAWN_VALIDATION_ERROR("nextInChain must be nullptr");
             }
             DAWN_TRY(ValidateIndexFormat(descriptor->indexFormat));
 
-            if (descriptor->numInputs > kMaxVertexInputs) {
+            if (descriptor->numBuffers > kMaxVertexBuffers) {
                 return DAWN_VALIDATION_ERROR("Vertex Inputs number exceeds maximum");
             }
             if (descriptor->numAttributes > kMaxVertexAttributes) {
                 return DAWN_VALIDATION_ERROR("Vertex Attributes number exceeds maximum");
             }
 
-            for (uint32_t i = 0; i < descriptor->numInputs; ++i) {
-                DAWN_TRY(ValidateVertexInputDescriptor(&descriptor->inputs[i], inputsSetMask));
+            for (uint32_t i = 0; i < descriptor->numBuffers; ++i) {
+                DAWN_TRY(ValidateVertexBufferDescriptor(&descriptor->buffers[i], inputsSetMask));
             }
 
             for (uint32_t i = 0; i < descriptor->numAttributes; ++i) {
@@ -262,14 +262,14 @@
 
         DAWN_TRY(device->ValidateObject(descriptor->layout));
 
-        if (descriptor->inputState == nullptr) {
+        if (descriptor->vertexInput == nullptr) {
             return DAWN_VALIDATION_ERROR("Input state must not be null");
         }
 
-        std::bitset<kMaxVertexInputs> inputsSetMask;
+        std::bitset<kMaxVertexBuffers> inputsSetMask;
         std::bitset<kMaxVertexAttributes> attributesSetMask;
-        DAWN_TRY(ValidateInputStateDescriptor(descriptor->inputState, &inputsSetMask,
-                                              &attributesSetMask));
+        DAWN_TRY(ValidateVertexInputDescriptor(descriptor->vertexInput, &inputsSetMask,
+                                               &attributesSetMask));
         DAWN_TRY(ValidatePrimitiveTopology(descriptor->primitiveTopology));
         DAWN_TRY(ValidatePipelineStageDescriptor(device, descriptor->vertexStage,
                                                  descriptor->layout, dawn::ShaderStage::Vertex));
@@ -334,7 +334,7 @@
         : PipelineBase(device,
                        descriptor->layout,
                        dawn::ShaderStageBit::Vertex | dawn::ShaderStageBit::Fragment),
-          mInputState(*descriptor->inputState),
+          mVertexInput(*descriptor->vertexInput),
           mHasDepthStencilAttachment(descriptor->depthStencilState != nullptr),
           mPrimitiveTopology(descriptor->primitiveTopology),
           mRasterizationState(*descriptor->rasterizationState),
@@ -345,16 +345,16 @@
           mFragmentEntryPoint(descriptor->fragmentStage->entryPoint),
           mIsBlueprint(blueprint) {
         uint32_t location = 0;
-        for (uint32_t i = 0; i < mInputState.numAttributes; ++i) {
-            location = mInputState.attributes[i].shaderLocation;
+        for (uint32_t i = 0; i < mVertexInput.numAttributes; ++i) {
+            location = mVertexInput.attributes[i].shaderLocation;
             mAttributesSetMask.set(location);
-            mAttributeInfos[location] = mInputState.attributes[i];
+            mAttributeInfos[location] = mVertexInput.attributes[i];
         }
         uint32_t slot = 0;
-        for (uint32_t i = 0; i < mInputState.numInputs; ++i) {
-            slot = mInputState.inputs[i].inputSlot;
+        for (uint32_t i = 0; i < mVertexInput.numBuffers; ++i) {
+            slot = mVertexInput.buffers[i].inputSlot;
             mInputsSetMask.set(slot);
-            mInputInfos[slot] = mInputState.inputs[i];
+            mInputInfos[slot] = mVertexInput.buffers[i];
         }
 
         if (mHasDepthStencilAttachment) {
@@ -405,9 +405,9 @@
         }
     }
 
-    const InputStateDescriptor* RenderPipelineBase::GetInputStateDescriptor() const {
+    const VertexInputDescriptor* RenderPipelineBase::GetVertexInputDescriptor() const {
         ASSERT(!IsError());
-        return &mInputState;
+        return &mVertexInput;
     }
 
     const std::bitset<kMaxVertexAttributes>& RenderPipelineBase::GetAttributesSetMask() const {
@@ -421,12 +421,12 @@
         return mAttributeInfos[location];
     }
 
-    const std::bitset<kMaxVertexInputs>& RenderPipelineBase::GetInputsSetMask() const {
+    const std::bitset<kMaxVertexBuffers>& RenderPipelineBase::GetInputsSetMask() const {
         ASSERT(!IsError());
         return mInputsSetMask;
     }
 
-    const VertexInputDescriptor& RenderPipelineBase::GetInput(uint32_t slot) const {
+    const VertexBufferDescriptor& RenderPipelineBase::GetInput(uint32_t slot) const {
         ASSERT(!IsError());
         ASSERT(mInputsSetMask[slot]);
         return mInputInfos[slot];
@@ -561,11 +561,11 @@
 
         HashCombine(&hash, pipeline->mInputsSetMask);
         for (uint32_t i : IterateBitSet(pipeline->mInputsSetMask)) {
-            const VertexInputDescriptor& desc = pipeline->GetInput(i);
+            const VertexBufferDescriptor& desc = pipeline->GetInput(i);
             HashCombine(&hash, desc.inputSlot, desc.stride, desc.stepMode);
         }
 
-        HashCombine(&hash, pipeline->mInputState.indexFormat);
+        HashCombine(&hash, pipeline->mVertexInput.indexFormat);
 
         // Hash rasterization state
         {
@@ -660,15 +660,15 @@
         }
 
         for (uint32_t i : IterateBitSet(a->mInputsSetMask)) {
-            const VertexInputDescriptor& descA = a->GetInput(i);
-            const VertexInputDescriptor& descB = b->GetInput(i);
+            const VertexBufferDescriptor& descA = a->GetInput(i);
+            const VertexBufferDescriptor& descB = b->GetInput(i);
             if (descA.inputSlot != descB.inputSlot || descA.stride != descB.stride ||
                 descA.stepMode != descB.stepMode) {
                 return false;
             }
         }
 
-        if (a->mInputState.indexFormat != b->mInputState.indexFormat) {
+        if (a->mVertexInput.indexFormat != b->mVertexInput.indexFormat) {
             return false;
         }
 
diff --git a/src/dawn_native/RenderPipeline.h b/src/dawn_native/RenderPipeline.h
index 98fc1ad..df4bf58 100644
--- a/src/dawn_native/RenderPipeline.h
+++ b/src/dawn_native/RenderPipeline.h
@@ -47,11 +47,11 @@
 
         static RenderPipelineBase* MakeError(DeviceBase* device);
 
-        const InputStateDescriptor* GetInputStateDescriptor() const;
+        const VertexInputDescriptor* GetVertexInputDescriptor() const;
         const std::bitset<kMaxVertexAttributes>& GetAttributesSetMask() const;
         const VertexAttributeDescriptor& GetAttribute(uint32_t location) const;
-        const std::bitset<kMaxVertexInputs>& GetInputsSetMask() const;
-        const VertexInputDescriptor& GetInput(uint32_t slot) const;
+        const std::bitset<kMaxVertexBuffers>& GetInputsSetMask() const;
+        const VertexBufferDescriptor& GetInput(uint32_t slot) const;
 
         const ColorStateDescriptor* GetColorStateDescriptor(uint32_t attachmentSlot) const;
         const DepthStencilStateDescriptor* GetDepthStencilStateDescriptor() const;
@@ -69,7 +69,7 @@
         // attachments in the render pass. This returns whether it is the case.
         bool IsCompatibleWith(const BeginRenderPassCmd* renderPassCmd) const;
         std::bitset<kMaxVertexAttributes> GetAttributesUsingInput(uint32_t slot) const;
-        std::array<std::bitset<kMaxVertexAttributes>, kMaxVertexInputs> attributesUsingInput;
+        std::array<std::bitset<kMaxVertexAttributes>, kMaxVertexBuffers> attributesUsingInput;
 
         // Functors necessary for the unordered_set<RenderPipelineBase*>-based cache.
         struct HashFunc {
@@ -83,11 +83,11 @@
         RenderPipelineBase(DeviceBase* device, ObjectBase::ErrorTag tag);
 
         // Vertex input
-        InputStateDescriptor mInputState;
+        VertexInputDescriptor mVertexInput;
         std::bitset<kMaxVertexAttributes> mAttributesSetMask;
         std::array<VertexAttributeDescriptor, kMaxVertexAttributes> mAttributeInfos;
-        std::bitset<kMaxVertexInputs> mInputsSetMask;
-        std::array<VertexInputDescriptor, kMaxVertexInputs> mInputInfos;
+        std::bitset<kMaxVertexBuffers> mInputsSetMask;
+        std::array<VertexBufferDescriptor, kMaxVertexBuffers> mInputInfos;
 
         // Attachments
         bool mHasDepthStencilAttachment = false;
diff --git a/src/dawn_native/d3d12/CommandBufferD3D12.cpp b/src/dawn_native/d3d12/CommandBufferD3D12.cpp
index 18e6d1c..d9c7d52 100644
--- a/src/dawn_native/d3d12/CommandBufferD3D12.cpp
+++ b/src/dawn_native/d3d12/CommandBufferD3D12.cpp
@@ -653,7 +653,7 @@
         commandList->IASetVertexBuffers(startSlot, count,
                                         &vertexBuffersInfo->d3d12BufferViews[startSlot]);
 
-        vertexBuffersInfo->startSlot = kMaxVertexInputs;
+        vertexBuffersInfo->startSlot = kMaxVertexBuffers;
         vertexBuffersInfo->endSlot = 0;
     }
 
@@ -893,7 +893,7 @@
                     // this will break if the pipeline is changed for one with a different index
                     // format after SetIndexBuffer
                     bufferView.Format =
-                        DXGIIndexFormat(lastPipeline->GetInputStateDescriptor()->indexFormat);
+                        DXGIIndexFormat(lastPipeline->GetVertexInputDescriptor()->indexFormat);
 
                     commandList->IASetIndexBuffer(&bufferView);
                 } break;
diff --git a/src/dawn_native/d3d12/CommandBufferD3D12.h b/src/dawn_native/d3d12/CommandBufferD3D12.h
index 694f98c..ed50885 100644
--- a/src/dawn_native/d3d12/CommandBufferD3D12.h
+++ b/src/dawn_native/d3d12/CommandBufferD3D12.h
@@ -41,9 +41,9 @@
         // represent the union of the dirty ranges (the union may have non-dirty
         // data in the middle of the range).
         const RenderPipeline* lastRenderPipeline = nullptr;
-        uint32_t startSlot = kMaxVertexInputs;
+        uint32_t startSlot = kMaxVertexBuffers;
         uint32_t endSlot = 0;
-        std::array<D3D12_VERTEX_BUFFER_VIEW, kMaxVertexInputs> d3d12BufferViews = {};
+        std::array<D3D12_VERTEX_BUFFER_VIEW, kMaxVertexBuffers> d3d12BufferViews = {};
     };
 
     class CommandBuffer : public CommandBufferBase {
diff --git a/src/dawn_native/d3d12/RenderPipelineD3D12.cpp b/src/dawn_native/d3d12/RenderPipelineD3D12.cpp
index 5df00b1..c8b11ea 100644
--- a/src/dawn_native/d3d12/RenderPipelineD3D12.cpp
+++ b/src/dawn_native/d3d12/RenderPipelineD3D12.cpp
@@ -409,7 +409,7 @@
             inputElementDescriptor.Format = VertexFormatType(attribute.format);
             inputElementDescriptor.InputSlot = attribute.inputSlot;
 
-            const VertexInputDescriptor& input = GetInput(attribute.inputSlot);
+            const VertexBufferDescriptor& input = GetInput(attribute.inputSlot);
 
             inputElementDescriptor.AlignedByteOffset = attribute.offset;
             inputElementDescriptor.InputSlotClass = InputStepModeFunction(input.stepMode);
diff --git a/src/dawn_native/metal/CommandBufferMTL.mm b/src/dawn_native/metal/CommandBufferMTL.mm
index d44740e..1c30164 100644
--- a/src/dawn_native/metal/CommandBufferMTL.mm
+++ b/src/dawn_native/metal/CommandBufferMTL.mm
@@ -804,7 +804,7 @@
                 case Command::DrawIndexed: {
                     DrawIndexedCmd* draw = mCommands.NextCommand<DrawIndexedCmd>();
                     size_t formatSize =
-                        IndexFormatSize(lastPipeline->GetInputStateDescriptor()->indexFormat);
+                        IndexFormatSize(lastPipeline->GetVertexInputDescriptor()->indexFormat);
 
                     // The index and instance count must be non-zero, otherwise no-op
                     if (draw->indexCount != 0 && draw->instanceCount != 0) {
@@ -926,8 +926,8 @@
                     auto buffers = mCommands.NextData<Ref<BufferBase>>(cmd->count);
                     auto offsets = mCommands.NextData<uint64_t>(cmd->count);
 
-                    std::array<id<MTLBuffer>, kMaxVertexInputs> mtlBuffers;
-                    std::array<NSUInteger, kMaxVertexInputs> mtlOffsets;
+                    std::array<id<MTLBuffer>, kMaxVertexBuffers> mtlBuffers;
+                    std::array<NSUInteger, kMaxVertexBuffers> mtlOffsets;
 
                     // Perhaps an "array of vertex buffers(+offsets?)" should be
                     // a Dawn API primitive to avoid reconstructing this array?
diff --git a/src/dawn_native/metal/RenderPipelineMTL.mm b/src/dawn_native/metal/RenderPipelineMTL.mm
index 0a92c93..078a081 100644
--- a/src/dawn_native/metal/RenderPipelineMTL.mm
+++ b/src/dawn_native/metal/RenderPipelineMTL.mm
@@ -307,7 +307,7 @@
 
     RenderPipeline::RenderPipeline(Device* device, const RenderPipelineDescriptor* descriptor)
         : RenderPipelineBase(device, descriptor),
-          mMtlIndexType(MTLIndexFormat(GetInputStateDescriptor()->indexFormat)),
+          mMtlIndexType(MTLIndexFormat(GetVertexInputDescriptor()->indexFormat)),
           mMtlPrimitiveTopology(MTLPrimitiveTopology(GetPrimitiveTopology())),
           mMtlFrontFace(MTLFrontFace(GetFrontFace())),
           mMtlCullMode(ToMTLCullMode(GetCullMode())) {
@@ -416,7 +416,7 @@
         }
 
         for (uint32_t i : IterateBitSet(GetInputsSetMask())) {
-            const VertexInputDescriptor& info = GetInput(i);
+            const VertexBufferDescriptor& info = GetInput(i);
 
             auto layoutDesc = [MTLVertexBufferLayoutDescriptor new];
             if (info.stride == 0) {
diff --git a/src/dawn_native/opengl/CommandBufferGL.cpp b/src/dawn_native/opengl/CommandBufferGL.cpp
index 686f9db..7973d44 100644
--- a/src/dawn_native/opengl/CommandBufferGL.cpp
+++ b/src/dawn_native/opengl/CommandBufferGL.cpp
@@ -210,8 +210,8 @@
         };
 
         // Vertex buffers and index buffers are implemented as part of an OpenGL VAO that
-        // corresponds to an InputState. On the contrary in Dawn they are part of the global state.
-        // This means that we have to re-apply these buffers on an InputState change.
+        // corresponds to an VertexInput. On the contrary in Dawn they are part of the global state.
+        // This means that we have to re-apply these buffers on an VertexInput change.
         class InputBufferTracker {
           public:
             void OnSetIndexBuffer(BufferBase* buffer) {
@@ -230,7 +230,7 @@
                 }
 
                 // Use 64 bit masks and make sure there are no shift UB
-                static_assert(kMaxVertexInputs <= 8 * sizeof(unsigned long long) - 1, "");
+                static_assert(kMaxVertexBuffers <= 8 * sizeof(unsigned long long) - 1, "");
                 mDirtyVertexBuffers |= ((1ull << count) - 1ull) << startSlot;
             }
 
@@ -286,9 +286,9 @@
             bool mIndexBufferDirty = false;
             Buffer* mIndexBuffer = nullptr;
 
-            std::bitset<kMaxVertexInputs> mDirtyVertexBuffers;
-            std::array<Buffer*, kMaxVertexInputs> mVertexBuffers;
-            std::array<uint64_t, kMaxVertexInputs> mVertexBufferOffsets;
+            std::bitset<kMaxVertexBuffers> mDirtyVertexBuffers;
+            std::array<Buffer*, kMaxVertexBuffers> mVertexBuffers;
+            std::array<uint64_t, kMaxVertexBuffers> mVertexBufferOffsets;
 
             RenderPipelineBase* mLastPipeline = nullptr;
         };
@@ -772,7 +772,7 @@
                     inputBuffers.Apply();
 
                     dawn::IndexFormat indexFormat =
-                        lastPipeline->GetInputStateDescriptor()->indexFormat;
+                        lastPipeline->GetVertexInputDescriptor()->indexFormat;
                     size_t formatSize = IndexFormatSize(indexFormat);
                     GLenum formatType = IndexFormatType(indexFormat);
 
diff --git a/src/dawn_native/opengl/RenderPipelineGL.cpp b/src/dawn_native/opengl/RenderPipelineGL.cpp
index ada39b2..5e3f2d6 100644
--- a/src/dawn_native/opengl/RenderPipelineGL.cpp
+++ b/src/dawn_native/opengl/RenderPipelineGL.cpp
@@ -182,7 +182,7 @@
         modules[dawn::ShaderStage::Fragment] = ToBackend(descriptor->fragmentStage->module);
 
         PipelineGL::Initialize(ToBackend(GetLayout()), modules);
-        CreateVAOForInputState(descriptor->inputState);
+        CreateVAOForVertexInput(descriptor->vertexInput);
     }
 
     RenderPipeline::~RenderPipeline() {
@@ -194,7 +194,7 @@
         return mGlPrimitiveTopology;
     }
 
-    void RenderPipeline::CreateVAOForInputState(const InputStateDescriptor* inputState) {
+    void RenderPipeline::CreateVAOForVertexInput(const VertexInputDescriptor* vertexInput) {
         glGenVertexArrays(1, &mVertexArrayObject);
         glBindVertexArray(mVertexArrayObject);
         for (uint32_t location : IterateBitSet(GetAttributesSetMask())) {
diff --git a/src/dawn_native/opengl/RenderPipelineGL.h b/src/dawn_native/opengl/RenderPipelineGL.h
index dc51f6f..6dc3c14 100644
--- a/src/dawn_native/opengl/RenderPipelineGL.h
+++ b/src/dawn_native/opengl/RenderPipelineGL.h
@@ -38,7 +38,7 @@
         void ApplyNow(PersistentPipelineState& persistentPipelineState);
 
       private:
-        void CreateVAOForInputState(const InputStateDescriptor* inputState);
+        void CreateVAOForVertexInput(const VertexInputDescriptor* vertexInput);
 
         // TODO(yunchao.he@intel.com): vao need to be deduplicated between pipelines.
         GLuint mVertexArrayObject;
diff --git a/src/dawn_native/vulkan/CommandBufferVk.cpp b/src/dawn_native/vulkan/CommandBufferVk.cpp
index e65f537..3c81af4 100644
--- a/src/dawn_native/vulkan/CommandBufferVk.cpp
+++ b/src/dawn_native/vulkan/CommandBufferVk.cpp
@@ -575,7 +575,7 @@
                     // and rebind if needed on pipeline change
                     ASSERT(lastPipeline != nullptr);
                     VkIndexType indexType =
-                        VulkanIndexType(lastPipeline->GetInputStateDescriptor()->indexFormat);
+                        VulkanIndexType(lastPipeline->GetVertexInputDescriptor()->indexFormat);
                     device->fn.CmdBindIndexBuffer(
                         commands, indexBuffer, static_cast<VkDeviceSize>(cmd->offset), indexType);
                 } break;
@@ -613,8 +613,8 @@
                     auto buffers = mCommands.NextData<Ref<BufferBase>>(cmd->count);
                     auto offsets = mCommands.NextData<uint64_t>(cmd->count);
 
-                    std::array<VkBuffer, kMaxVertexInputs> vkBuffers;
-                    std::array<VkDeviceSize, kMaxVertexInputs> vkOffsets;
+                    std::array<VkBuffer, kMaxVertexBuffers> vkBuffers;
+                    std::array<VkDeviceSize, kMaxVertexBuffers> vkOffsets;
 
                     for (uint32_t i = 0; i < cmd->count; ++i) {
                         Buffer* buffer = ToBackend(buffers[i].Get());
diff --git a/src/dawn_native/vulkan/RenderPipelineVk.cpp b/src/dawn_native/vulkan/RenderPipelineVk.cpp
index e2cbca9..581e303 100644
--- a/src/dawn_native/vulkan/RenderPipelineVk.cpp
+++ b/src/dawn_native/vulkan/RenderPipelineVk.cpp
@@ -296,11 +296,11 @@
             shaderStages[1].pName = descriptor->fragmentStage->entryPoint;
         }
 
-        std::array<VkVertexInputBindingDescription, kMaxVertexInputs> mBindings;
+        std::array<VkVertexInputBindingDescription, kMaxVertexBuffers> mBindings;
         std::array<VkVertexInputAttributeDescription, kMaxVertexAttributes> mAttributes;
-        const InputStateDescriptor* inputState = GetInputStateDescriptor();
-        VkPipelineVertexInputStateCreateInfo inputStateCreateInfo =
-            ComputeInputStateDesc(inputState, &mBindings, &mAttributes);
+        const VertexInputDescriptor* vertexInput = GetVertexInputDescriptor();
+        VkPipelineVertexInputStateCreateInfo vertexInputCreateInfo =
+            ComputeVertexInputDesc(vertexInput, &mBindings, &mAttributes);
 
         VkPipelineInputAssemblyStateCreateInfo inputAssembly;
         inputAssembly.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
@@ -427,7 +427,7 @@
         createInfo.flags = 0;
         createInfo.stageCount = 2;
         createInfo.pStages = shaderStages;
-        createInfo.pVertexInputState = &inputStateCreateInfo;
+        createInfo.pVertexInputState = &vertexInputCreateInfo;
         createInfo.pInputAssemblyState = &inputAssembly;
         createInfo.pTessellationState = nullptr;
         createInfo.pViewportState = &viewport;
@@ -448,9 +448,9 @@
         }
     }
 
-    VkPipelineVertexInputStateCreateInfo RenderPipeline::ComputeInputStateDesc(
-        const InputStateDescriptor* inputState,
-        std::array<VkVertexInputBindingDescription, kMaxVertexInputs>* mBindings,
+    VkPipelineVertexInputStateCreateInfo RenderPipeline::ComputeVertexInputDesc(
+        const VertexInputDescriptor* vertexInput,
+        std::array<VkVertexInputBindingDescription, kMaxVertexBuffers>* mBindings,
         std::array<VkVertexInputAttributeDescription, kMaxVertexAttributes>* mAttributes) {
         // Fill in the "binding info" that will be chained in the create info
         uint32_t bindingCount = 0;
diff --git a/src/dawn_native/vulkan/RenderPipelineVk.h b/src/dawn_native/vulkan/RenderPipelineVk.h
index 5d58fa7..083c3ab 100644
--- a/src/dawn_native/vulkan/RenderPipelineVk.h
+++ b/src/dawn_native/vulkan/RenderPipelineVk.h
@@ -31,9 +31,9 @@
         VkPipeline GetHandle() const;
 
       private:
-        VkPipelineVertexInputStateCreateInfo ComputeInputStateDesc(
-            const InputStateDescriptor* inputState,
-            std::array<VkVertexInputBindingDescription, kMaxVertexInputs>* mBindings,
+        VkPipelineVertexInputStateCreateInfo ComputeVertexInputDesc(
+            const VertexInputDescriptor* vertexInput,
+            std::array<VkVertexInputBindingDescription, kMaxVertexBuffers>* mBindings,
             std::array<VkVertexInputAttributeDescription, kMaxVertexAttributes>* mAttributes);
 
         VkPipeline mHandle = VK_NULL_HANDLE;
diff --git a/src/tests/end2end/DestroyTests.cpp b/src/tests/end2end/DestroyTests.cpp
index 8bd4cda..3deaeaa 100644
--- a/src/tests/end2end/DestroyTests.cpp
+++ b/src/tests/end2end/DestroyTests.cpp
@@ -46,10 +46,10 @@
         descriptor.cVertexStage.module = vsModule;

         descriptor.cFragmentStage.module = fsModule;

         descriptor.primitiveTopology = dawn::PrimitiveTopology::TriangleStrip;

-        descriptor.cInputState.numInputs = 1;

-        descriptor.cInputState.cInputs[0].stride = 4 * sizeof(float);

-        descriptor.cInputState.numAttributes = 1;

-        descriptor.cInputState.cAttributes[0].format = dawn::VertexFormat::Float4;

+        descriptor.cVertexInput.numBuffers = 1;

+        descriptor.cVertexInput.cBuffers[0].stride = 4 * sizeof(float);

+        descriptor.cVertexInput.numAttributes = 1;

+        descriptor.cVertexInput.cAttributes[0].format = dawn::VertexFormat::Float4;

         descriptor.cColorStates[0]->format = renderPass.colorFormat;

 

         pipeline = device.CreateRenderPipeline(&descriptor);

diff --git a/src/tests/end2end/DrawIndexedTests.cpp b/src/tests/end2end/DrawIndexedTests.cpp
index 02421c7..44baa2b 100644
--- a/src/tests/end2end/DrawIndexedTests.cpp
+++ b/src/tests/end2end/DrawIndexedTests.cpp
@@ -46,10 +46,10 @@
             descriptor.cVertexStage.module = vsModule;
             descriptor.cFragmentStage.module = fsModule;
             descriptor.primitiveTopology = dawn::PrimitiveTopology::TriangleStrip;
-            descriptor.cInputState.numInputs = 1;
-            descriptor.cInputState.cInputs[0].stride = 4 * sizeof(float);
-            descriptor.cInputState.numAttributes = 1;
-            descriptor.cInputState.cAttributes[0].format = dawn::VertexFormat::Float4;
+            descriptor.cVertexInput.numBuffers = 1;
+            descriptor.cVertexInput.cBuffers[0].stride = 4 * sizeof(float);
+            descriptor.cVertexInput.numAttributes = 1;
+            descriptor.cVertexInput.cAttributes[0].format = dawn::VertexFormat::Float4;
             descriptor.cColorStates[0]->format = renderPass.colorFormat;
 
             pipeline = device.CreateRenderPipeline(&descriptor);
diff --git a/src/tests/end2end/DrawTests.cpp b/src/tests/end2end/DrawTests.cpp
index b2c36f7..c09e337 100644
--- a/src/tests/end2end/DrawTests.cpp
+++ b/src/tests/end2end/DrawTests.cpp
@@ -46,10 +46,10 @@
         descriptor.cVertexStage.module = vsModule;
         descriptor.cFragmentStage.module = fsModule;
         descriptor.primitiveTopology = dawn::PrimitiveTopology::TriangleStrip;
-        descriptor.cInputState.numInputs = 1;
-        descriptor.cInputState.cInputs[0].stride = 4 * sizeof(float);
-        descriptor.cInputState.numAttributes = 1;
-        descriptor.cInputState.cAttributes[0].format = dawn::VertexFormat::Float4;
+        descriptor.cVertexInput.numBuffers = 1;
+        descriptor.cVertexInput.cBuffers[0].stride = 4 * sizeof(float);
+        descriptor.cVertexInput.numAttributes = 1;
+        descriptor.cVertexInput.cAttributes[0].format = dawn::VertexFormat::Float4;
         descriptor.cColorStates[0]->format = renderPass.colorFormat;
 
         pipeline = device.CreateRenderPipeline(&descriptor);
diff --git a/src/tests/end2end/IndexFormatTests.cpp b/src/tests/end2end/IndexFormatTests.cpp
index d4b2acb..f7122c7 100644
--- a/src/tests/end2end/IndexFormatTests.cpp
+++ b/src/tests/end2end/IndexFormatTests.cpp
@@ -52,11 +52,11 @@
             descriptor.cVertexStage.module = vsModule;
             descriptor.cFragmentStage.module = fsModule;
             descriptor.primitiveTopology = dawn::PrimitiveTopology::TriangleStrip;
-            descriptor.cInputState.indexFormat = format;
-            descriptor.cInputState.numInputs = 1;
-            descriptor.cInputState.cInputs[0].stride = 4 * sizeof(float);
-            descriptor.cInputState.numAttributes = 1;
-            descriptor.cInputState.cAttributes[0].format = dawn::VertexFormat::Float4;
+            descriptor.cVertexInput.indexFormat = format;
+            descriptor.cVertexInput.numBuffers = 1;
+            descriptor.cVertexInput.cBuffers[0].stride = 4 * sizeof(float);
+            descriptor.cVertexInput.numAttributes = 1;
+            descriptor.cVertexInput.cAttributes[0].format = dawn::VertexFormat::Float4;
             descriptor.cColorStates[0]->format = renderPass.colorFormat;
 
             return device.CreateRenderPipeline(&descriptor);
diff --git a/src/tests/end2end/InputStateTests.cpp b/src/tests/end2end/InputStateTests.cpp
deleted file mode 100644
index c463dc1..0000000
--- a/src/tests/end2end/InputStateTests.cpp
+++ /dev/null
@@ -1,494 +0,0 @@
-// Copyright 2017 The Dawn Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "tests/DawnTest.h"
-
-#include "common/Assert.h"
-#include "utils/ComboRenderPipelineDescriptor.h"
-#include "utils/DawnHelpers.h"
-
-using dawn::InputStepMode;
-using dawn::VertexFormat;
-
-// Input state tests all work the same way: the test will render triangles in a grid up to 4x4. Each triangle
-// is position in the grid such that X will correspond to the "triangle number" and the Y to the instance number.
-// Each test will set up an input state and buffers, and the vertex shader will check that the vertex attributes
-// corresponds to predetermined values. On success it outputs green, otherwise red.
-//
-// The predetermined values are "K * gl_VertexID + componentIndex" for vertex-indexed buffers, and
-// "K * gl_InstanceID + componentIndex" for instance-indexed buffers.
-
-constexpr static unsigned int kRTSize = 400;
-constexpr static unsigned int kRTCellOffset = 50;
-constexpr static unsigned int kRTCellSize = 100;
-
-class InputStateTest : public DawnTest {
-    protected:
-        void SetUp() override {
-            DawnTest::SetUp();
-
-            renderPass = utils::CreateBasicRenderPass(device, kRTSize, kRTSize);
-        }
-
-        bool ShouldComponentBeDefault(VertexFormat format, int component) {
-            EXPECT_TRUE(component >= 0 && component < 4);
-            switch (format) {
-                case VertexFormat::Float4:
-                case VertexFormat::UChar4Norm:
-                    return component >= 4;
-                case VertexFormat::Float3:
-                    return component >= 3;
-                case VertexFormat::Float2:
-                case VertexFormat::UChar2Norm:
-                    return component >= 2;
-                case VertexFormat::Float:
-                    return component >= 1;
-                default:
-                    DAWN_UNREACHABLE();
-            }
-        }
-
-        struct ShaderTestSpec {
-            uint32_t location;
-            VertexFormat format;
-            InputStepMode step;
-        };
-        dawn::RenderPipeline MakeTestPipeline(const dawn::InputStateDescriptor& inputState,
-                                              int multiplier,
-                                              const std::vector<ShaderTestSpec>& testSpec) {
-            std::ostringstream vs;
-            vs << "#version 450\n";
-
-            // TODO(cwallez@chromium.org): this only handles float attributes, we should extend it to other types
-            // Adds line of the form
-            //    layout(location=1) in vec4 input1;
-            for (const auto& input : testSpec) {
-                vs << "layout(location=" << input.location << ") in vec4 input" << input.location << ";\n";
-            }
-
-            vs << "layout(location = 0) out vec4 color;\n";
-            vs << "void main() {\n";
-
-            // Hard code the triangle in the shader so that we don't have to add a vertex input for it.
-            // Also this places the triangle in the grid based on its VertexID and InstanceID
-            vs << "    const vec2 pos[3] = vec2[3](vec2(0.5f, 1.0f), vec2(0.0f, 0.0f), vec2(1.0f, 0.0f));\n";
-            vs << "    vec2 offset = vec2(float(gl_VertexIndex / 3), float(gl_InstanceIndex));\n";
-            vs << "    vec2 worldPos = pos[gl_VertexIndex % 3] + offset;\n";
-            vs << "    gl_Position = vec4(worldPos / 2 - vec2(1.0f), 0.0f, 1.0f);\n";
-
-            // Perform the checks by successively ANDing a boolean
-            vs << "    bool success = true;\n";
-            for (const auto& input : testSpec) {
-                for (int component = 0; component < 4; ++component) {
-                    vs << "    success = success && (input" << input.location << "[" << component << "] == ";
-                    if (ShouldComponentBeDefault(input.format, component)) {
-                        vs << (component == 3 ? "1.0f" : "0.0f");
-                    } else {
-                        if (input.step == InputStepMode::Vertex) {
-                            vs << multiplier << " * gl_VertexIndex + " << component << ".0f";
-                        } else {
-                            vs << multiplier << " * gl_InstanceIndex + " << component << ".0f";
-                        }
-                    }
-                    vs << ");\n";
-                }
-            }
-
-            // Choose the color
-            vs << "    if (success) {\n";
-            vs << "        color = vec4(0.0f, 1.0f, 0.0f, 1.0f);\n";
-            vs << "    } else {\n";
-            vs << "        color = vec4(1.0f, 0.0f, 0.0f, 1.0f);\n";
-            vs << "    }\n;";
-            vs << "}\n";
-
-            dawn::ShaderModule vsModule = utils::CreateShaderModule(device, dawn::ShaderStage::Vertex, vs.str().c_str());
-            dawn::ShaderModule fsModule = utils::CreateShaderModule(device, dawn::ShaderStage::Fragment, R"(
-                #version 450
-                layout(location = 0) in vec4 color;
-                layout(location = 0) out vec4 fragColor;
-                void main() {
-                    fragColor = color;
-                })"
-            );
-
-            utils::ComboRenderPipelineDescriptor descriptor(device);
-            descriptor.cVertexStage.module = vsModule;
-            descriptor.cFragmentStage.module = fsModule;
-            descriptor.inputState = &inputState;
-            descriptor.cColorStates[0]->format = renderPass.colorFormat;
-
-            return device.CreateRenderPipeline(&descriptor);
-        }
-
-        struct InputSpec {
-            uint32_t slot;
-            uint64_t stride;
-            InputStepMode step;
-        };
-        struct AttributeSpec {
-            uint32_t location;
-            uint32_t slot;
-            uint64_t offset;
-            VertexFormat format;
-        };
-
-        utils::ComboInputStateDescriptor MakeInputState(
-            const std::vector<InputSpec>& inputs,
-            const std::vector<AttributeSpec>& attributes) {
-            utils::ComboInputStateDescriptor inputState;
-            uint32_t numInputs = 0;
-            for (const auto& input : inputs) {
-                inputState.cInputs[numInputs].inputSlot = input.slot;
-                inputState.cInputs[numInputs].stride = input.stride;
-                inputState.cInputs[numInputs].stepMode = input.step;
-                numInputs++;
-            }
-
-            uint32_t numAttributes = 0;
-            for (const auto& attribute : attributes) {
-                inputState.cAttributes[numAttributes].shaderLocation = attribute.location;
-                inputState.cAttributes[numAttributes].inputSlot = attribute.slot;
-                inputState.cAttributes[numAttributes].offset = attribute.offset;
-                inputState.cAttributes[numAttributes].format = attribute.format;
-                numAttributes++;
-            }
-            inputState.numInputs = numInputs;
-            inputState.numAttributes = numAttributes;
-            return inputState;
-        }
-
-        template<typename T>
-        dawn::Buffer MakeVertexBuffer(std::vector<T> data) {
-            return utils::CreateBufferFromData(device, data.data(), static_cast<uint32_t>(data.size() * sizeof(T)), dawn::BufferUsageBit::Vertex);
-        }
-
-        struct DrawVertexBuffer {
-            uint32_t location;
-            dawn::Buffer* buffer;
-        };
-        void DoTestDraw(const dawn::RenderPipeline& pipeline, unsigned int triangles, unsigned int instances, std::vector<DrawVertexBuffer> vertexBuffers) {
-            EXPECT_LE(triangles, 4u);
-            EXPECT_LE(instances, 4u);
-
-            dawn::CommandEncoder encoder = device.CreateCommandEncoder();
-
-            dawn::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass.renderPassInfo);
-            pass.SetPipeline(pipeline);
-
-            uint64_t zeroOffset = 0;
-            for (const auto& buffer : vertexBuffers) {
-                pass.SetVertexBuffers(buffer.location, 1, buffer.buffer, &zeroOffset);
-            }
-
-            pass.Draw(triangles * 3, instances, 0, 0);
-            pass.EndPass();
-
-            dawn::CommandBuffer commands = encoder.Finish();
-            queue.Submit(1, &commands);
-
-            CheckResult(triangles, instances);
-        }
-
-        void CheckResult(unsigned int triangles, unsigned int instances) {
-            // Check that the center of each triangle is pure green, so that if a single vertex shader
-            // instance fails, linear interpolation makes the pixel check fail.
-            for (unsigned int triangle = 0; triangle < 4; triangle++) {
-                for (unsigned int instance = 0; instance < 4; instance++) {
-                    unsigned int x = kRTCellOffset + kRTCellSize * triangle;
-                    unsigned int y = kRTCellOffset + kRTCellSize * instance;
-                    if (triangle < triangles && instance < instances) {
-                        EXPECT_PIXEL_RGBA8_EQ(RGBA8(0, 255, 0, 255), renderPass.color, x, y);
-                    } else {
-                        EXPECT_PIXEL_RGBA8_EQ(RGBA8(0, 0, 0, 0), renderPass.color, x, y);
-                    }
-                }
-            }
-        }
-
-        utils::BasicRenderPass renderPass;
-};
-
-// Test compilation and usage of the fixture :)
-TEST_P(InputStateTest, Basic) {
-    utils::ComboInputStateDescriptor inputState = MakeInputState(
-        {{0, 4 * sizeof(float), InputStepMode::Vertex}}, {{0, 0, 0, VertexFormat::Float4}});
-    dawn::RenderPipeline pipeline = MakeTestPipeline(inputState, 1, {
-        {0, VertexFormat::Float4, InputStepMode::Vertex}
-    });
-
-    dawn::Buffer buffer0 = MakeVertexBuffer<float>({
-        0, 1, 2, 3,
-        1, 2, 3, 4,
-        2, 3, 4, 5
-    });
-    DoTestDraw(pipeline, 1, 1, {DrawVertexBuffer{0, &buffer0}});
-}
-
-// Test a stride of 0 works
-TEST_P(InputStateTest, ZeroStride) {
-    // This test was failing only on AMD but the OpenGL backend doesn't gather PCI info yet.
-    DAWN_SKIP_TEST_IF(IsLinux() && IsOpenGL());
-
-    utils::ComboInputStateDescriptor inputState =
-        MakeInputState({{0, 0, InputStepMode::Vertex}}, {{0, 0, 0, VertexFormat::Float4}});
-    dawn::RenderPipeline pipeline = MakeTestPipeline(inputState, 0, {
-        {0, VertexFormat::Float4, InputStepMode::Vertex}
-    });
-
-    dawn::Buffer buffer0 = MakeVertexBuffer<float>({
-        0, 1, 2, 3,
-    });
-    DoTestDraw(pipeline, 1, 1, {DrawVertexBuffer{0, &buffer0}});
-}
-
-// Test attributes defaults to (0, 0, 0, 1) if the input state doesn't have all components
-TEST_P(InputStateTest, AttributeExpanding) {
-    // This test was failing only on AMD but the OpenGL backend doesn't gather PCI info yet.
-    DAWN_SKIP_TEST_IF(IsLinux() && IsOpenGL());
-
-    // R32F case
-    {
-        utils::ComboInputStateDescriptor inputState =
-            MakeInputState({{0, 0, InputStepMode::Vertex}}, {{0, 0, 0, VertexFormat::Float}});
-        dawn::RenderPipeline pipeline = MakeTestPipeline(inputState, 0, {
-            {0, VertexFormat::Float, InputStepMode::Vertex}
-        });
-
-        dawn::Buffer buffer0 = MakeVertexBuffer<float>({
-            0, 1, 2, 3
-        });
-        DoTestDraw(pipeline, 1, 1, {DrawVertexBuffer{0, &buffer0}});
-    }
-    // RG32F case
-    {
-        utils::ComboInputStateDescriptor inputState =
-            MakeInputState({{0, 0, InputStepMode::Vertex}}, {{0, 0, 0, VertexFormat::Float2}});
-        dawn::RenderPipeline pipeline = MakeTestPipeline(inputState, 0, {
-            {0, VertexFormat::Float2, InputStepMode::Vertex}
-        });
-
-        dawn::Buffer buffer0 = MakeVertexBuffer<float>({
-            0, 1, 2, 3
-        });
-        DoTestDraw(pipeline, 1, 1, {DrawVertexBuffer{0, &buffer0}});
-    }
-    // RGB32F case
-    {
-        utils::ComboInputStateDescriptor inputState =
-            MakeInputState({{0, 0, InputStepMode::Vertex}}, {{0, 0, 0, VertexFormat::Float3}});
-        dawn::RenderPipeline pipeline = MakeTestPipeline(inputState, 0, {
-            {0, VertexFormat::Float3, InputStepMode::Vertex}
-        });
-
-        dawn::Buffer buffer0 = MakeVertexBuffer<float>({
-            0, 1, 2, 3
-        });
-        DoTestDraw(pipeline, 1, 1, {DrawVertexBuffer{0, &buffer0}});
-    }
-}
-
-// Test a stride larger than the attributes
-TEST_P(InputStateTest, StrideLargerThanAttributes) {
-    // This test was failing only on AMD but the OpenGL backend doesn't gather PCI info yet.
-    DAWN_SKIP_TEST_IF(IsLinux() && IsOpenGL());
-
-    utils::ComboInputStateDescriptor inputState = MakeInputState(
-        {{0, 8 * sizeof(float), InputStepMode::Vertex}}, {{0, 0, 0, VertexFormat::Float4}});
-    dawn::RenderPipeline pipeline = MakeTestPipeline(inputState, 1, {
-        {0, VertexFormat::Float4, InputStepMode::Vertex}
-    });
-
-    dawn::Buffer buffer0 = MakeVertexBuffer<float>({
-        0, 1, 2, 3, 0, 0, 0, 0,
-        1, 2, 3, 4, 0, 0, 0, 0,
-        2, 3, 4, 5, 0, 0, 0, 0,
-    });
-    DoTestDraw(pipeline, 1, 1, {DrawVertexBuffer{0, &buffer0}});
-}
-
-// Test two attributes at an offset, vertex version
-TEST_P(InputStateTest, TwoAttributesAtAnOffsetVertex) {
-    utils::ComboInputStateDescriptor inputState = MakeInputState(
-        {{0, 8 * sizeof(float), InputStepMode::Vertex}},
-        {{0, 0, 0, VertexFormat::Float4}, {1, 0, 4 * sizeof(float), VertexFormat::Float4}});
-    dawn::RenderPipeline pipeline = MakeTestPipeline(inputState, 1, {
-        {0, VertexFormat::Float4, InputStepMode::Vertex}
-    });
-
-    dawn::Buffer buffer0 = MakeVertexBuffer<float>({
-        0, 1, 2, 3, 0, 1, 2, 3,
-        1, 2, 3, 4, 1, 2, 3, 4,
-        2, 3, 4, 5, 2, 3, 4, 5,
-    });
-    DoTestDraw(pipeline, 1, 1, {DrawVertexBuffer{0, &buffer0}});
-}
-
-// Test two attributes at an offset, instance version
-TEST_P(InputStateTest, TwoAttributesAtAnOffsetInstance) {
-    utils::ComboInputStateDescriptor inputState = MakeInputState(
-        {{0, 8 * sizeof(float), InputStepMode::Instance}},
-        {{0, 0, 0, VertexFormat::Float4}, {1, 0, 4 * sizeof(float), VertexFormat::Float4}});
-    dawn::RenderPipeline pipeline = MakeTestPipeline(inputState, 1, {
-        {0, VertexFormat::Float4, InputStepMode::Instance}
-    });
-
-    dawn::Buffer buffer0 = MakeVertexBuffer<float>({
-        0, 1, 2, 3, 0, 1, 2, 3,
-        1, 2, 3, 4, 1, 2, 3, 4,
-        2, 3, 4, 5, 2, 3, 4, 5,
-    });
-    DoTestDraw(pipeline, 1, 1, {DrawVertexBuffer{0, &buffer0}});
-}
-
-// Test a pure-instance input state
-TEST_P(InputStateTest, PureInstance) {
-    utils::ComboInputStateDescriptor inputState = MakeInputState(
-        {{0, 4 * sizeof(float), InputStepMode::Instance}}, {{0, 0, 0, VertexFormat::Float4}});
-    dawn::RenderPipeline pipeline = MakeTestPipeline(inputState, 1, {
-        {0, VertexFormat::Float4, InputStepMode::Instance}
-    });
-
-    dawn::Buffer buffer0 = MakeVertexBuffer<float>({
-        0, 1, 2, 3,
-        1, 2, 3, 4,
-        2, 3, 4, 5,
-        3, 4, 5, 6,
-    });
-    DoTestDraw(pipeline, 1, 4, {DrawVertexBuffer{0, &buffer0}});
-}
-
-// Test with mixed everything, vertex vs. instance, different stride and offsets
-// different attribute types
-TEST_P(InputStateTest, MixedEverything) {
-    utils::ComboInputStateDescriptor inputState = MakeInputState(
-        {
-            {0, 12 * sizeof(float), InputStepMode::Vertex},
-            {1, 10 * sizeof(float), InputStepMode::Instance},
-        },
-        {{0, 0, 0, VertexFormat::Float},
-         {1, 0, 6 * sizeof(float), VertexFormat::Float2},
-         {2, 1, 0, VertexFormat::Float3},
-         {3, 1, 5 * sizeof(float), VertexFormat::Float4}});
-    dawn::RenderPipeline pipeline = MakeTestPipeline(inputState, 1, {
-        {0, VertexFormat::Float, InputStepMode::Vertex},
-        {1, VertexFormat::Float2, InputStepMode::Vertex},
-        {2, VertexFormat::Float3, InputStepMode::Instance},
-        {3, VertexFormat::Float4, InputStepMode::Instance}
-    });
-
-    dawn::Buffer buffer0 = MakeVertexBuffer<float>({
-        0, 1, 2, 3, 0, 0, 0, 1, 2, 3, 0, 0,
-        1, 2, 3, 4, 0, 0, 1, 2, 3, 4, 0, 0,
-        2, 3, 4, 5, 0, 0, 2, 3, 4, 5, 0, 0,
-        3, 4, 5, 6, 0, 0, 3, 4, 5, 6, 0, 0,
-    });
-    dawn::Buffer buffer1 = MakeVertexBuffer<float>({
-        0, 1, 2, 3, 0, 0, 1, 2, 3, 0,
-        1, 2, 3, 4, 0, 1, 2, 3, 4, 0,
-        2, 3, 4, 5, 0, 2, 3, 4, 5, 0,
-        3, 4, 5, 6, 0, 3, 4, 5, 6, 0,
-    });
-    DoTestDraw(pipeline, 1, 1, {{0, &buffer0}, {1, &buffer1}});
-}
-
-// Test input state is unaffected by unused vertex slot
-TEST_P(InputStateTest, UnusedVertexSlot) {
-    // Instance input state, using slot 1
-    utils::ComboInputStateDescriptor instanceInputState = MakeInputState(
-        {{1, 4 * sizeof(float), InputStepMode::Instance}}, {{0, 1, 0, VertexFormat::Float4}});
-    dawn::RenderPipeline instancePipeline = MakeTestPipeline(
-        instanceInputState, 1, {{0, VertexFormat::Float4, InputStepMode::Instance}});
-
-    dawn::Buffer buffer = MakeVertexBuffer<float>({
-        0, 1, 2, 3,
-        1, 2, 3, 4,
-        2, 3, 4, 5,
-        3, 4, 5, 6,
-    });
-
-    dawn::CommandEncoder encoder = device.CreateCommandEncoder();
-
-    dawn::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass.renderPassInfo);
-
-    uint64_t zeroOffset = 0;
-    pass.SetVertexBuffers(0, 1, &buffer, &zeroOffset);
-    pass.SetVertexBuffers(1, 1, &buffer, &zeroOffset);
-
-    pass.SetPipeline(instancePipeline);
-    pass.Draw(1 * 3, 4, 0, 0);
-
-    pass.EndPass();
-
-    dawn::CommandBuffer commands = encoder.Finish();
-    queue.Submit(1, &commands);
-
-    CheckResult(1, 4);
-}
-
-// Test setting a different pipeline with a different input state.
-// This was a problem with the D3D12 backend where SetVertexBuffers
-// was getting the input from the last set pipeline, not the current.
-// SetVertexBuffers should be reapplied when the input state changes.
-TEST_P(InputStateTest, MultiplePipelinesMixedInputState) {
-    // Basic input state, using slot 0
-    utils::ComboInputStateDescriptor vertexInputState = MakeInputState(
-        {{0, 4 * sizeof(float), InputStepMode::Vertex}}, {{0, 0, 0, VertexFormat::Float4}});
-    dawn::RenderPipeline vertexPipeline = MakeTestPipeline(
-        vertexInputState, 1, {{0, VertexFormat::Float4, InputStepMode::Vertex}});
-
-    // Instance input state, using slot 1
-    utils::ComboInputStateDescriptor instanceInputState = MakeInputState(
-        {{1, 4 * sizeof(float), InputStepMode::Instance}}, {{0, 1, 0, VertexFormat::Float4}});
-    dawn::RenderPipeline instancePipeline = MakeTestPipeline(
-        instanceInputState, 1, {{0, VertexFormat::Float4, InputStepMode::Instance}});
-
-    dawn::Buffer buffer = MakeVertexBuffer<float>({
-        0, 1, 2, 3,
-        1, 2, 3, 4,
-        2, 3, 4, 5,
-        3, 4, 5, 6,
-    });
-
-    dawn::CommandEncoder encoder = device.CreateCommandEncoder();
-
-    dawn::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass.renderPassInfo);
-
-    uint64_t zeroOffset = 0;
-    pass.SetVertexBuffers(0, 1, &buffer, &zeroOffset);
-    pass.SetVertexBuffers(1, 1, &buffer, &zeroOffset);
-
-    pass.SetPipeline(vertexPipeline);
-    pass.Draw(1 * 3, 1, 0, 0);
-
-    pass.SetPipeline(instancePipeline);
-    pass.Draw(1 * 3, 4, 0, 0);
-
-    pass.EndPass();
-
-    dawn::CommandBuffer commands = encoder.Finish();
-    queue.Submit(1, &commands);
-
-    CheckResult(1, 4);
-}
-
-DAWN_INSTANTIATE_TEST(InputStateTest, D3D12Backend, MetalBackend, OpenGLBackend, VulkanBackend);
-
-// TODO for the input state:
-//  - Add more vertex formats
-//  - Add checks that the stride is enough to contain all attributes
-//  - Add checks stride less than some limit
-//  - Add checks for alignement of vertex buffers and attributes if needed
-//  - Check for attribute narrowing
-//  - Check that the input state and the pipeline vertex input types match
diff --git a/src/tests/end2end/PrimitiveTopologyTests.cpp b/src/tests/end2end/PrimitiveTopologyTests.cpp
index 552715b..d0bd851 100644
--- a/src/tests/end2end/PrimitiveTopologyTests.cpp
+++ b/src/tests/end2end/PrimitiveTopologyTests.cpp
@@ -185,10 +185,10 @@
             descriptor.cVertexStage.module = vsModule;
             descriptor.cFragmentStage.module = fsModule;
             descriptor.primitiveTopology = primitiveTopology;
-            descriptor.cInputState.numInputs = 1;
-            descriptor.cInputState.cInputs[0].stride = 4 * sizeof(float);
-            descriptor.cInputState.numAttributes = 1;
-            descriptor.cInputState.cAttributes[0].format = dawn::VertexFormat::Float4;
+            descriptor.cVertexInput.numBuffers = 1;
+            descriptor.cVertexInput.cBuffers[0].stride = 4 * sizeof(float);
+            descriptor.cVertexInput.numAttributes = 1;
+            descriptor.cVertexInput.cAttributes[0].format = dawn::VertexFormat::Float4;
             descriptor.cColorStates[0]->format = renderPass.colorFormat;
 
             dawn::RenderPipeline pipeline = device.CreateRenderPipeline(&descriptor);
diff --git a/src/tests/end2end/VertexFormatTests.cpp b/src/tests/end2end/VertexFormatTests.cpp
index 6d20bb8..f65e126 100644
--- a/src/tests/end2end/VertexFormatTests.cpp
+++ b/src/tests/end2end/VertexFormatTests.cpp
@@ -362,10 +362,10 @@
         utils::ComboRenderPipelineDescriptor descriptor(device);
         descriptor.cVertexStage.module = vsModule;
         descriptor.cFragmentStage.module = fsModule;
-        descriptor.cInputState.numInputs = 1;
-        descriptor.cInputState.cInputs[0].stride = strideBytes;
-        descriptor.cInputState.numAttributes = 1;
-        descriptor.cInputState.cAttributes[0].format = format;
+        descriptor.cVertexInput.numBuffers = 1;
+        descriptor.cVertexInput.cBuffers[0].stride = strideBytes;
+        descriptor.cVertexInput.numAttributes = 1;
+        descriptor.cVertexInput.cAttributes[0].format = format;
         descriptor.cColorStates[0]->format = renderPass.colorFormat;
 
         return device.CreateRenderPipeline(&descriptor);
@@ -797,4 +797,4 @@
     DoVertexFormatTest(dawn::VertexFormat::Int4, vertexData, vertexData);
 }
 
-DAWN_INSTANTIATE_TEST(VertexFormatTest, D3D12Backend, MetalBackend, OpenGLBackend, VulkanBackend);
\ No newline at end of file
+DAWN_INSTANTIATE_TEST(VertexFormatTest, D3D12Backend, MetalBackend, OpenGLBackend, VulkanBackend);
diff --git a/src/tests/end2end/VertexInputTests.cpp b/src/tests/end2end/VertexInputTests.cpp
new file mode 100644
index 0000000..f23df73
--- /dev/null
+++ b/src/tests/end2end/VertexInputTests.cpp
@@ -0,0 +1,494 @@
+// Copyright 2017 The Dawn Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "tests/DawnTest.h"
+
+#include "common/Assert.h"
+#include "utils/ComboRenderPipelineDescriptor.h"
+#include "utils/DawnHelpers.h"
+
+using dawn::InputStepMode;
+using dawn::VertexFormat;
+
+// Input state tests all work the same way: the test will render triangles in a grid up to 4x4. Each triangle
+// is position in the grid such that X will correspond to the "triangle number" and the Y to the instance number.
+// Each test will set up an input state and buffers, and the vertex shader will check that the vertex attributes
+// corresponds to predetermined values. On success it outputs green, otherwise red.
+//
+// The predetermined values are "K * gl_VertexID + componentIndex" for vertex-indexed buffers, and
+// "K * gl_InstanceID + componentIndex" for instance-indexed buffers.
+
+constexpr static unsigned int kRTSize = 400;
+constexpr static unsigned int kRTCellOffset = 50;
+constexpr static unsigned int kRTCellSize = 100;
+
+class VertexInputTest : public DawnTest {
+  protected:
+    void SetUp() override {
+        DawnTest::SetUp();
+
+        renderPass = utils::CreateBasicRenderPass(device, kRTSize, kRTSize);
+    }
+
+    bool ShouldComponentBeDefault(VertexFormat format, int component) {
+        EXPECT_TRUE(component >= 0 && component < 4);
+        switch (format) {
+            case VertexFormat::Float4:
+            case VertexFormat::UChar4Norm:
+                return component >= 4;
+            case VertexFormat::Float3:
+                return component >= 3;
+            case VertexFormat::Float2:
+            case VertexFormat::UChar2Norm:
+                return component >= 2;
+            case VertexFormat::Float:
+                return component >= 1;
+            default:
+                DAWN_UNREACHABLE();
+        }
+    }
+
+    struct ShaderTestSpec {
+        uint32_t location;
+        VertexFormat format;
+        InputStepMode step;
+    };
+    dawn::RenderPipeline MakeTestPipeline(const dawn::VertexInputDescriptor& vertexInput,
+                                          int multiplier,
+                                          const std::vector<ShaderTestSpec>& testSpec) {
+        std::ostringstream vs;
+        vs << "#version 450\n";
+
+        // TODO(cwallez@chromium.org): this only handles float attributes, we should extend it to
+        // other types Adds line of the form
+        //    layout(location=1) in vec4 input1;
+        for (const auto& input : testSpec) {
+            vs << "layout(location=" << input.location << ") in vec4 input" << input.location
+               << ";\n";
+        }
+
+        vs << "layout(location = 0) out vec4 color;\n";
+        vs << "void main() {\n";
+
+        // Hard code the triangle in the shader so that we don't have to add a vertex input for it.
+        // Also this places the triangle in the grid based on its VertexID and InstanceID
+        vs << "    const vec2 pos[3] = vec2[3](vec2(0.5f, 1.0f), vec2(0.0f, 0.0f), vec2(1.0f, "
+              "0.0f));\n";
+        vs << "    vec2 offset = vec2(float(gl_VertexIndex / 3), float(gl_InstanceIndex));\n";
+        vs << "    vec2 worldPos = pos[gl_VertexIndex % 3] + offset;\n";
+        vs << "    gl_Position = vec4(worldPos / 2 - vec2(1.0f), 0.0f, 1.0f);\n";
+
+        // Perform the checks by successively ANDing a boolean
+        vs << "    bool success = true;\n";
+        for (const auto& input : testSpec) {
+            for (int component = 0; component < 4; ++component) {
+                vs << "    success = success && (input" << input.location << "[" << component
+                   << "] == ";
+                if (ShouldComponentBeDefault(input.format, component)) {
+                    vs << (component == 3 ? "1.0f" : "0.0f");
+                } else {
+                    if (input.step == InputStepMode::Vertex) {
+                        vs << multiplier << " * gl_VertexIndex + " << component << ".0f";
+                    } else {
+                        vs << multiplier << " * gl_InstanceIndex + " << component << ".0f";
+                    }
+                }
+                vs << ");\n";
+            }
+        }
+
+        // Choose the color
+        vs << "    if (success) {\n";
+        vs << "        color = vec4(0.0f, 1.0f, 0.0f, 1.0f);\n";
+        vs << "    } else {\n";
+        vs << "        color = vec4(1.0f, 0.0f, 0.0f, 1.0f);\n";
+        vs << "    }\n;";
+        vs << "}\n";
+
+        dawn::ShaderModule vsModule =
+            utils::CreateShaderModule(device, dawn::ShaderStage::Vertex, vs.str().c_str());
+        dawn::ShaderModule fsModule =
+            utils::CreateShaderModule(device, dawn::ShaderStage::Fragment, R"(
+                #version 450
+                layout(location = 0) in vec4 color;
+                layout(location = 0) out vec4 fragColor;
+                void main() {
+                    fragColor = color;
+                })");
+
+        utils::ComboRenderPipelineDescriptor descriptor(device);
+        descriptor.cVertexStage.module = vsModule;
+        descriptor.cFragmentStage.module = fsModule;
+        descriptor.vertexInput = &vertexInput;
+        descriptor.cColorStates[0]->format = renderPass.colorFormat;
+
+        return device.CreateRenderPipeline(&descriptor);
+    }
+
+    struct VertexBufferSpec {
+        uint32_t slot;
+        uint64_t stride;
+        InputStepMode step;
+    };
+    struct AttributeSpec {
+        uint32_t location;
+        uint32_t slot;
+        uint64_t offset;
+        VertexFormat format;
+    };
+
+    utils::ComboVertexInputDescriptor MakeVertexInput(
+        const std::vector<VertexBufferSpec>& buffers,
+        const std::vector<AttributeSpec>& attributes) {
+        utils::ComboVertexInputDescriptor vertexInput;
+        uint32_t numBuffers = 0;
+        for (const auto& buffer : buffers) {
+            vertexInput.cBuffers[numBuffers].inputSlot = buffer.slot;
+            vertexInput.cBuffers[numBuffers].stride = buffer.stride;
+            vertexInput.cBuffers[numBuffers].stepMode = buffer.step;
+            numBuffers++;
+        }
+
+        uint32_t numAttributes = 0;
+        for (const auto& attribute : attributes) {
+            vertexInput.cAttributes[numAttributes].shaderLocation = attribute.location;
+            vertexInput.cAttributes[numAttributes].inputSlot = attribute.slot;
+            vertexInput.cAttributes[numAttributes].offset = attribute.offset;
+            vertexInput.cAttributes[numAttributes].format = attribute.format;
+            numAttributes++;
+        }
+        vertexInput.numBuffers = numBuffers;
+        vertexInput.numAttributes = numAttributes;
+        return vertexInput;
+    }
+
+    template <typename T>
+    dawn::Buffer MakeVertexBuffer(std::vector<T> data) {
+        return utils::CreateBufferFromData(device, data.data(),
+                                           static_cast<uint32_t>(data.size() * sizeof(T)),
+                                           dawn::BufferUsageBit::Vertex);
+    }
+
+    struct DrawVertexBuffer {
+        uint32_t location;
+        dawn::Buffer* buffer;
+    };
+    void DoTestDraw(const dawn::RenderPipeline& pipeline,
+                    unsigned int triangles,
+                    unsigned int instances,
+                    std::vector<DrawVertexBuffer> vertexBuffers) {
+        EXPECT_LE(triangles, 4u);
+        EXPECT_LE(instances, 4u);
+
+        dawn::CommandEncoder encoder = device.CreateCommandEncoder();
+
+        dawn::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass.renderPassInfo);
+        pass.SetPipeline(pipeline);
+
+        uint64_t zeroOffset = 0;
+        for (const auto& buffer : vertexBuffers) {
+            pass.SetVertexBuffers(buffer.location, 1, buffer.buffer, &zeroOffset);
+        }
+
+        pass.Draw(triangles * 3, instances, 0, 0);
+        pass.EndPass();
+
+        dawn::CommandBuffer commands = encoder.Finish();
+        queue.Submit(1, &commands);
+
+        CheckResult(triangles, instances);
+    }
+
+    void CheckResult(unsigned int triangles, unsigned int instances) {
+        // Check that the center of each triangle is pure green, so that if a single vertex shader
+        // instance fails, linear interpolation makes the pixel check fail.
+        for (unsigned int triangle = 0; triangle < 4; triangle++) {
+            for (unsigned int instance = 0; instance < 4; instance++) {
+                unsigned int x = kRTCellOffset + kRTCellSize * triangle;
+                unsigned int y = kRTCellOffset + kRTCellSize * instance;
+                if (triangle < triangles && instance < instances) {
+                    EXPECT_PIXEL_RGBA8_EQ(RGBA8(0, 255, 0, 255), renderPass.color, x, y);
+                } else {
+                    EXPECT_PIXEL_RGBA8_EQ(RGBA8(0, 0, 0, 0), renderPass.color, x, y);
+                }
+            }
+        }
+    }
+
+    utils::BasicRenderPass renderPass;
+};
+
+// Test compilation and usage of the fixture :)
+TEST_P(VertexInputTest, Basic) {
+    utils::ComboVertexInputDescriptor vertexInput = MakeVertexInput(
+        {{0, 4 * sizeof(float), InputStepMode::Vertex}}, {{0, 0, 0, VertexFormat::Float4}});
+    dawn::RenderPipeline pipeline =
+        MakeTestPipeline(vertexInput, 1, {{0, VertexFormat::Float4, InputStepMode::Vertex}});
+
+    dawn::Buffer buffer0 = MakeVertexBuffer<float>({
+        0, 1, 2, 3,
+        1, 2, 3, 4,
+        2, 3, 4, 5
+    });
+    DoTestDraw(pipeline, 1, 1, {DrawVertexBuffer{0, &buffer0}});
+}
+
+// Test a stride of 0 works
+TEST_P(VertexInputTest, ZeroStride) {
+    // This test was failing only on AMD but the OpenGL backend doesn't gather PCI info yet.
+    DAWN_SKIP_TEST_IF(IsLinux() && IsOpenGL());
+
+    utils::ComboVertexInputDescriptor vertexInput =
+        MakeVertexInput({{0, 0, InputStepMode::Vertex}}, {{0, 0, 0, VertexFormat::Float4}});
+    dawn::RenderPipeline pipeline =
+        MakeTestPipeline(vertexInput, 0, {{0, VertexFormat::Float4, InputStepMode::Vertex}});
+
+    dawn::Buffer buffer0 = MakeVertexBuffer<float>({
+        0, 1, 2, 3,
+    });
+    DoTestDraw(pipeline, 1, 1, {DrawVertexBuffer{0, &buffer0}});
+}
+
+// Test attributes defaults to (0, 0, 0, 1) if the input state doesn't have all components
+TEST_P(VertexInputTest, AttributeExpanding) {
+    // This test was failing only on AMD but the OpenGL backend doesn't gather PCI info yet.
+    DAWN_SKIP_TEST_IF(IsLinux() && IsOpenGL());
+
+    // R32F case
+    {
+        utils::ComboVertexInputDescriptor vertexInput =
+            MakeVertexInput({{0, 0, InputStepMode::Vertex}}, {{0, 0, 0, VertexFormat::Float}});
+        dawn::RenderPipeline pipeline =
+            MakeTestPipeline(vertexInput, 0, {{0, VertexFormat::Float, InputStepMode::Vertex}});
+
+        dawn::Buffer buffer0 = MakeVertexBuffer<float>({
+            0, 1, 2, 3
+        });
+        DoTestDraw(pipeline, 1, 1, {DrawVertexBuffer{0, &buffer0}});
+    }
+    // RG32F case
+    {
+        utils::ComboVertexInputDescriptor vertexInput =
+            MakeVertexInput({{0, 0, InputStepMode::Vertex}}, {{0, 0, 0, VertexFormat::Float2}});
+        dawn::RenderPipeline pipeline =
+            MakeTestPipeline(vertexInput, 0, {{0, VertexFormat::Float2, InputStepMode::Vertex}});
+
+        dawn::Buffer buffer0 = MakeVertexBuffer<float>({
+            0, 1, 2, 3
+        });
+        DoTestDraw(pipeline, 1, 1, {DrawVertexBuffer{0, &buffer0}});
+    }
+    // RGB32F case
+    {
+        utils::ComboVertexInputDescriptor vertexInput =
+            MakeVertexInput({{0, 0, InputStepMode::Vertex}}, {{0, 0, 0, VertexFormat::Float3}});
+        dawn::RenderPipeline pipeline =
+            MakeTestPipeline(vertexInput, 0, {{0, VertexFormat::Float3, InputStepMode::Vertex}});
+
+        dawn::Buffer buffer0 = MakeVertexBuffer<float>({
+            0, 1, 2, 3
+        });
+        DoTestDraw(pipeline, 1, 1, {DrawVertexBuffer{0, &buffer0}});
+    }
+}
+
+// Test a stride larger than the attributes
+TEST_P(VertexInputTest, StrideLargerThanAttributes) {
+    // This test was failing only on AMD but the OpenGL backend doesn't gather PCI info yet.
+    DAWN_SKIP_TEST_IF(IsLinux() && IsOpenGL());
+
+    utils::ComboVertexInputDescriptor vertexInput = MakeVertexInput(
+        {{0, 8 * sizeof(float), InputStepMode::Vertex}}, {{0, 0, 0, VertexFormat::Float4}});
+    dawn::RenderPipeline pipeline =
+        MakeTestPipeline(vertexInput, 1, {{0, VertexFormat::Float4, InputStepMode::Vertex}});
+
+    dawn::Buffer buffer0 = MakeVertexBuffer<float>({
+        0, 1, 2, 3, 0, 0, 0, 0,
+        1, 2, 3, 4, 0, 0, 0, 0,
+        2, 3, 4, 5, 0, 0, 0, 0,
+    });
+    DoTestDraw(pipeline, 1, 1, {DrawVertexBuffer{0, &buffer0}});
+}
+
+// Test two attributes at an offset, vertex version
+TEST_P(VertexInputTest, TwoAttributesAtAnOffsetVertex) {
+    utils::ComboVertexInputDescriptor vertexInput = MakeVertexInput(
+        {{0, 8 * sizeof(float), InputStepMode::Vertex}},
+        {{0, 0, 0, VertexFormat::Float4}, {1, 0, 4 * sizeof(float), VertexFormat::Float4}});
+    dawn::RenderPipeline pipeline =
+        MakeTestPipeline(vertexInput, 1, {{0, VertexFormat::Float4, InputStepMode::Vertex}});
+
+    dawn::Buffer buffer0 = MakeVertexBuffer<float>({
+        0, 1, 2, 3, 0, 1, 2, 3,
+        1, 2, 3, 4, 1, 2, 3, 4,
+        2, 3, 4, 5, 2, 3, 4, 5,
+    });
+    DoTestDraw(pipeline, 1, 1, {DrawVertexBuffer{0, &buffer0}});
+}
+
+// Test two attributes at an offset, instance version
+TEST_P(VertexInputTest, TwoAttributesAtAnOffsetInstance) {
+    utils::ComboVertexInputDescriptor vertexInput = MakeVertexInput(
+        {{0, 8 * sizeof(float), InputStepMode::Instance}},
+        {{0, 0, 0, VertexFormat::Float4}, {1, 0, 4 * sizeof(float), VertexFormat::Float4}});
+    dawn::RenderPipeline pipeline =
+        MakeTestPipeline(vertexInput, 1, {{0, VertexFormat::Float4, InputStepMode::Instance}});
+
+    dawn::Buffer buffer0 = MakeVertexBuffer<float>({
+        0, 1, 2, 3, 0, 1, 2, 3,
+        1, 2, 3, 4, 1, 2, 3, 4,
+        2, 3, 4, 5, 2, 3, 4, 5,
+    });
+    DoTestDraw(pipeline, 1, 1, {DrawVertexBuffer{0, &buffer0}});
+}
+
+// Test a pure-instance input state
+TEST_P(VertexInputTest, PureInstance) {
+    utils::ComboVertexInputDescriptor vertexInput = MakeVertexInput(
+        {{0, 4 * sizeof(float), InputStepMode::Instance}}, {{0, 0, 0, VertexFormat::Float4}});
+    dawn::RenderPipeline pipeline =
+        MakeTestPipeline(vertexInput, 1, {{0, VertexFormat::Float4, InputStepMode::Instance}});
+
+    dawn::Buffer buffer0 = MakeVertexBuffer<float>({
+        0, 1, 2, 3,
+        1, 2, 3, 4,
+        2, 3, 4, 5,
+        3, 4, 5, 6,
+    });
+    DoTestDraw(pipeline, 1, 4, {DrawVertexBuffer{0, &buffer0}});
+}
+
+// Test with mixed everything, vertex vs. instance, different stride and offsets
+// different attribute types
+TEST_P(VertexInputTest, MixedEverything) {
+    utils::ComboVertexInputDescriptor vertexInput = MakeVertexInput(
+        {
+            {0, 12 * sizeof(float), InputStepMode::Vertex},
+            {1, 10 * sizeof(float), InputStepMode::Instance},
+        },
+        {{0, 0, 0, VertexFormat::Float},
+         {1, 0, 6 * sizeof(float), VertexFormat::Float2},
+         {2, 1, 0, VertexFormat::Float3},
+         {3, 1, 5 * sizeof(float), VertexFormat::Float4}});
+    dawn::RenderPipeline pipeline =
+        MakeTestPipeline(vertexInput, 1,
+                         {{0, VertexFormat::Float, InputStepMode::Vertex},
+                          {1, VertexFormat::Float2, InputStepMode::Vertex},
+                          {2, VertexFormat::Float3, InputStepMode::Instance},
+                          {3, VertexFormat::Float4, InputStepMode::Instance}});
+
+    dawn::Buffer buffer0 = MakeVertexBuffer<float>({
+        0, 1, 2, 3, 0, 0, 0, 1, 2, 3, 0, 0,
+        1, 2, 3, 4, 0, 0, 1, 2, 3, 4, 0, 0,
+        2, 3, 4, 5, 0, 0, 2, 3, 4, 5, 0, 0,
+        3, 4, 5, 6, 0, 0, 3, 4, 5, 6, 0, 0,
+    });
+    dawn::Buffer buffer1 = MakeVertexBuffer<float>({
+        0, 1, 2, 3, 0, 0, 1, 2, 3, 0,
+        1, 2, 3, 4, 0, 1, 2, 3, 4, 0,
+        2, 3, 4, 5, 0, 2, 3, 4, 5, 0,
+        3, 4, 5, 6, 0, 3, 4, 5, 6, 0,
+    });
+    DoTestDraw(pipeline, 1, 1, {{0, &buffer0}, {1, &buffer1}});
+}
+
+// Test input state is unaffected by unused vertex slot
+TEST_P(VertexInputTest, UnusedVertexSlot) {
+    // Instance input state, using slot 1
+    utils::ComboVertexInputDescriptor instanceVertexInput = MakeVertexInput(
+        {{1, 4 * sizeof(float), InputStepMode::Instance}}, {{0, 1, 0, VertexFormat::Float4}});
+    dawn::RenderPipeline instancePipeline = MakeTestPipeline(
+        instanceVertexInput, 1, {{0, VertexFormat::Float4, InputStepMode::Instance}});
+
+    dawn::Buffer buffer = MakeVertexBuffer<float>({
+        0, 1, 2, 3,
+        1, 2, 3, 4,
+        2, 3, 4, 5,
+        3, 4, 5, 6,
+    });
+
+    dawn::CommandEncoder encoder = device.CreateCommandEncoder();
+
+    dawn::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass.renderPassInfo);
+
+    uint64_t zeroOffset = 0;
+    pass.SetVertexBuffers(0, 1, &buffer, &zeroOffset);
+    pass.SetVertexBuffers(1, 1, &buffer, &zeroOffset);
+
+    pass.SetPipeline(instancePipeline);
+    pass.Draw(1 * 3, 4, 0, 0);
+
+    pass.EndPass();
+
+    dawn::CommandBuffer commands = encoder.Finish();
+    queue.Submit(1, &commands);
+
+    CheckResult(1, 4);
+}
+
+// Test setting a different pipeline with a different input state.
+// This was a problem with the D3D12 backend where SetVertexBuffers
+// was getting the input from the last set pipeline, not the current.
+// SetVertexBuffers should be reapplied when the input state changes.
+TEST_P(VertexInputTest, MultiplePipelinesMixedVertexInput) {
+    // Basic input state, using slot 0
+    utils::ComboVertexInputDescriptor vertexVertexInput = MakeVertexInput(
+        {{0, 4 * sizeof(float), InputStepMode::Vertex}}, {{0, 0, 0, VertexFormat::Float4}});
+    dawn::RenderPipeline vertexPipeline =
+        MakeTestPipeline(vertexVertexInput, 1, {{0, VertexFormat::Float4, InputStepMode::Vertex}});
+
+    // Instance input state, using slot 1
+    utils::ComboVertexInputDescriptor instanceVertexInput = MakeVertexInput(
+        {{1, 4 * sizeof(float), InputStepMode::Instance}}, {{0, 1, 0, VertexFormat::Float4}});
+    dawn::RenderPipeline instancePipeline = MakeTestPipeline(
+        instanceVertexInput, 1, {{0, VertexFormat::Float4, InputStepMode::Instance}});
+
+    dawn::Buffer buffer = MakeVertexBuffer<float>({
+        0, 1, 2, 3,
+        1, 2, 3, 4,
+        2, 3, 4, 5,
+        3, 4, 5, 6,
+    });
+
+    dawn::CommandEncoder encoder = device.CreateCommandEncoder();
+
+    dawn::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass.renderPassInfo);
+
+    uint64_t zeroOffset = 0;
+    pass.SetVertexBuffers(0, 1, &buffer, &zeroOffset);
+    pass.SetVertexBuffers(1, 1, &buffer, &zeroOffset);
+
+    pass.SetPipeline(vertexPipeline);
+    pass.Draw(1 * 3, 1, 0, 0);
+
+    pass.SetPipeline(instancePipeline);
+    pass.Draw(1 * 3, 4, 0, 0);
+
+    pass.EndPass();
+
+    dawn::CommandBuffer commands = encoder.Finish();
+    queue.Submit(1, &commands);
+
+    CheckResult(1, 4);
+}
+
+DAWN_INSTANTIATE_TEST(VertexInputTest, D3D12Backend, MetalBackend, OpenGLBackend, VulkanBackend);
+
+// TODO for the input state:
+//  - Add more vertex formats
+//  - Add checks that the stride is enough to contain all attributes
+//  - Add checks stride less than some limit
+//  - Add checks for alignement of vertex buffers and attributes if needed
+//  - Check for attribute narrowing
+//  - Check that the input state and the pipeline vertex input types match
diff --git a/src/tests/unittests/validation/VertexBufferValidationTests.cpp b/src/tests/unittests/validation/VertexBufferValidationTests.cpp
index 36cbd4d..60561ae 100644
--- a/src/tests/unittests/validation/VertexBufferValidationTests.cpp
+++ b/src/tests/unittests/validation/VertexBufferValidationTests.cpp
@@ -45,18 +45,18 @@
             return buffers;
         }
 
-        dawn::ShaderModule MakeVertexShader(unsigned int numInputs) {
+        dawn::ShaderModule MakeVertexShader(unsigned int numBuffers) {
             std::ostringstream vs;
             vs << "#version 450\n";
-            for (unsigned int i = 0; i < numInputs; ++i) {
+            for (unsigned int i = 0; i < numBuffers; ++i) {
                 vs << "layout(location = " << i << ") in vec3 a_position" << i << ";\n";
             }
             vs << "void main() {\n";
 
             vs << "gl_Position = vec4(";
-            for (unsigned int i = 0; i < numInputs; ++i) {
+            for (unsigned int i = 0; i < numBuffers; ++i) {
                 vs << "a_position" << i;
-                if (i != numInputs - 1) {
+                if (i != numBuffers - 1) {
                     vs << " + ";
                 }
             }
@@ -68,19 +68,19 @@
         }
 
         dawn::RenderPipeline MakeRenderPipeline(const dawn::ShaderModule& vsModule,
-                                                unsigned int numInputs) {
+                                                unsigned int numBuffers) {
             utils::ComboRenderPipelineDescriptor descriptor(device);
             descriptor.cVertexStage.module = vsModule;
             descriptor.cFragmentStage.module = fsModule;
 
-            for (unsigned int i = 0; i < numInputs; ++i) {
-                descriptor.cInputState.cAttributes[i].shaderLocation = i;
-                descriptor.cInputState.cAttributes[i].inputSlot = i;
-                descriptor.cInputState.cAttributes[i].format = dawn::VertexFormat::Float3;
-                descriptor.cInputState.cInputs[i].inputSlot = i;
+            for (unsigned int i = 0; i < numBuffers; ++i) {
+                descriptor.cVertexInput.cAttributes[i].shaderLocation = i;
+                descriptor.cVertexInput.cAttributes[i].inputSlot = i;
+                descriptor.cVertexInput.cAttributes[i].format = dawn::VertexFormat::Float3;
+                descriptor.cVertexInput.cBuffers[i].inputSlot = i;
             }
-            descriptor.cInputState.numInputs = numInputs;
-            descriptor.cInputState.numAttributes = numInputs;
+            descriptor.cVertexInput.numBuffers = numBuffers;
+            descriptor.cVertexInput.numAttributes = numBuffers;
 
             return device.CreateRenderPipeline(&descriptor);
         }
@@ -88,7 +88,7 @@
         dawn::ShaderModule fsModule;
 };
 
-TEST_F(VertexBufferValidationTest, VertexInputsInheritedBetweenPipelines) {
+TEST_F(VertexBufferValidationTest, VertexBuffersInheritedBetweenPipelines) {
     DummyRenderPass renderPass(device);
     auto vsModule2 = MakeVertexShader(2);
     auto vsModule1 = MakeVertexShader(1);
@@ -123,7 +123,7 @@
     encoder.Finish();
 }
 
-TEST_F(VertexBufferValidationTest, VertexInputsNotInheritedBetweenRendePasses) {
+TEST_F(VertexBufferValidationTest, VertexBuffersNotInheritedBetweenRendePasses) {
     DummyRenderPass renderPass(device);
     auto vsModule2 = MakeVertexShader(2);
     auto vsModule1 = MakeVertexShader(1);
diff --git a/src/tests/unittests/validation/InputStateValidationTests.cpp b/src/tests/unittests/validation/VertexInputValidationTests.cpp
similarity index 70%
rename from src/tests/unittests/validation/InputStateValidationTests.cpp
rename to src/tests/unittests/validation/VertexInputValidationTests.cpp
index 4799817..d208fc3 100644
--- a/src/tests/unittests/validation/InputStateValidationTests.cpp
+++ b/src/tests/unittests/validation/VertexInputValidationTests.cpp
@@ -17,15 +17,15 @@
 #include "utils/ComboRenderPipelineDescriptor.h"
 #include "utils/DawnHelpers.h"
 
-class InputStateTest : public ValidationTest {
-    protected:
-      void CreatePipeline(bool success,
-                          const utils::ComboInputStateDescriptor& state,
-                          std::string vertexSource) {
-          dawn::ShaderModule vsModule =
-              utils::CreateShaderModule(device, dawn::ShaderStage::Vertex, vertexSource.c_str());
-          dawn::ShaderModule fsModule =
-              utils::CreateShaderModule(device, dawn::ShaderStage::Fragment, R"(
+class VertexInputTest : public ValidationTest {
+  protected:
+    void CreatePipeline(bool success,
+                        const utils::ComboVertexInputDescriptor& state,
+                        std::string vertexSource) {
+        dawn::ShaderModule vsModule =
+            utils::CreateShaderModule(device, dawn::ShaderStage::Vertex, vertexSource.c_str());
+        dawn::ShaderModule fsModule =
+            utils::CreateShaderModule(device, dawn::ShaderStage::Fragment, R"(
                 #version 450
                 layout(location = 0) out vec4 fragColor;
                 void main() {
@@ -33,23 +33,23 @@
                 }
             )");
 
-          utils::ComboRenderPipelineDescriptor descriptor(device);
-          descriptor.cVertexStage.module = vsModule;
-          descriptor.cFragmentStage.module = fsModule;
-          descriptor.inputState = &state;
-          descriptor.cColorStates[0]->format = dawn::TextureFormat::R8G8B8A8Unorm;
+        utils::ComboRenderPipelineDescriptor descriptor(device);
+        descriptor.cVertexStage.module = vsModule;
+        descriptor.cFragmentStage.module = fsModule;
+        descriptor.vertexInput = &state;
+        descriptor.cColorStates[0]->format = dawn::TextureFormat::R8G8B8A8Unorm;
 
-          if (!success) {
-              ASSERT_DEVICE_ERROR(device.CreateRenderPipeline(&descriptor));
-          } else {
-              device.CreateRenderPipeline(&descriptor);
-          }
-      }
+        if (!success) {
+            ASSERT_DEVICE_ERROR(device.CreateRenderPipeline(&descriptor));
+        } else {
+            device.CreateRenderPipeline(&descriptor);
+        }
+    }
 };
 
 // Check an empty input state is valid
-TEST_F(InputStateTest, EmptyIsOk) {
-    utils::ComboInputStateDescriptor state;
+TEST_F(VertexInputTest, EmptyIsOk) {
+    utils::ComboVertexInputDescriptor state;
     CreatePipeline(true, state, R"(
         #version 450
         void main() {
@@ -58,11 +58,11 @@
     )");
 }
 
-// Check validation that pipeline vertex inputs are backed by attributes in the input state
-TEST_F(InputStateTest, PipelineCompatibility) {
-    utils::ComboInputStateDescriptor state;
-    state.numInputs = 1;
-    state.cInputs[0].stride = 2 * sizeof(float);
+// Check validation that pipeline vertex buffers are backed by attributes in the vertex input
+TEST_F(VertexInputTest, PipelineCompatibility) {
+    utils::ComboVertexInputDescriptor state;
+    state.numBuffers = 1;
+    state.cBuffers[0].stride = 2 * sizeof(float);
     state.numAttributes = 2;
     state.cAttributes[1].shaderLocation = 1;
     state.cAttributes[1].offset = sizeof(float);
@@ -77,7 +77,7 @@
         }
     )");
 
-    // Check it is valid for the pipeline to use a subset of the InputState
+    // Check it is valid for the pipeline to use a subset of the VertexInput
     CreatePipeline(true, state, R"(
         #version 450
         layout(location = 0) in vec4 a;
@@ -97,10 +97,10 @@
 }
 
 // Test that a stride of 0 is valid
-TEST_F(InputStateTest, StrideZero) {
+TEST_F(VertexInputTest, StrideZero) {
     // Works ok without attributes
-    utils::ComboInputStateDescriptor state;
-    state.numInputs = 1;
+    utils::ComboVertexInputDescriptor state;
+    state.numBuffers = 1;
     CreatePipeline(true, state, R"(
         #version 450
         void main() {
@@ -120,10 +120,10 @@
 }
 
 // Test that we cannot set an already set input
-TEST_F(InputStateTest, AlreadySetInput) {
+TEST_F(VertexInputTest, AlreadySetInput) {
     // Control case
-    utils::ComboInputStateDescriptor state;
-    state.numInputs = 1;
+    utils::ComboVertexInputDescriptor state;
+    state.numBuffers = 1;
     CreatePipeline(true, state, R"(
         #version 450
         void main() {
@@ -132,7 +132,7 @@
     )");
 
     // Oh no, input 0 is set twice
-    state.numInputs = 2;
+    state.numBuffers = 2;
     CreatePipeline(false, state, R"(
         #version 450
         void main() {
@@ -142,11 +142,11 @@
 }
 
 // Check out of bounds condition on input slot
-TEST_F(InputStateTest, SetInputSlotOutOfBounds) {
+TEST_F(VertexInputTest, SetInputSlotOutOfBounds) {
     // Control case, setting last input slot
-    utils::ComboInputStateDescriptor state;
-    state.numInputs = 1;
-    state.cInputs[0].inputSlot = kMaxVertexInputs - 1;
+    utils::ComboVertexInputDescriptor state;
+    state.numBuffers = 1;
+    state.cBuffers[0].inputSlot = kMaxVertexBuffers - 1;
     CreatePipeline(true, state, R"(
         #version 450
         void main() {
@@ -155,7 +155,7 @@
     )");
 
     // Test input slot OOB
-    state.cInputs[0].inputSlot = kMaxVertexInputs;
+    state.cBuffers[0].inputSlot = kMaxVertexBuffers;
     CreatePipeline(false, state, R"(
         #version 450
         void main() {
@@ -165,11 +165,11 @@
 }
 
 // Check out of bounds condition on input stride
-TEST_F(InputStateTest, SetInputStrideOutOfBounds) {
+TEST_F(VertexInputTest, SetInputStrideOutOfBounds) {
     // Control case, setting max input stride
-    utils::ComboInputStateDescriptor state;
-    state.numInputs = 1;
-    state.cInputs[0].stride = kMaxVertexInputStride;
+    utils::ComboVertexInputDescriptor state;
+    state.numBuffers = 1;
+    state.cBuffers[0].stride = kMaxVertexBufferStride;
     CreatePipeline(true, state, R"(
         #version 450
         void main() {
@@ -178,7 +178,7 @@
     )");
 
     // Test input stride OOB
-    state.cInputs[0].stride = kMaxVertexInputStride + 1;
+    state.cBuffers[0].stride = kMaxVertexBufferStride + 1;
     CreatePipeline(false, state, R"(
         #version 450
         void main() {
@@ -188,10 +188,10 @@
 }
 
 // Test that we cannot set an already set attribute
-TEST_F(InputStateTest, AlreadySetAttribute) {
+TEST_F(VertexInputTest, AlreadySetAttribute) {
     // Control case, setting last attribute
-    utils::ComboInputStateDescriptor state;
-    state.numInputs = 1;
+    utils::ComboVertexInputDescriptor state;
+    state.numBuffers = 1;
     state.numAttributes = 1;
     CreatePipeline(true, state, R"(
         #version 450
@@ -211,10 +211,10 @@
 }
 
 // Check out of bounds condition on attribute shader location
-TEST_F(InputStateTest, SetAttributeLocationOutOfBounds) {
+TEST_F(VertexInputTest, SetAttributeLocationOutOfBounds) {
     // Control case, setting last attribute shader location
-    utils::ComboInputStateDescriptor state;
-    state.numInputs = 1;
+    utils::ComboVertexInputDescriptor state;
+    state.numBuffers = 1;
     state.numAttributes = 1;
     state.cAttributes[0].shaderLocation = kMaxVertexAttributes - 1;
     CreatePipeline(true, state, R"(
@@ -235,10 +235,10 @@
 }
 
 // Check attribute offset out of bounds
-TEST_F(InputStateTest, SetAttributeOffsetOutOfBounds) {
+TEST_F(VertexInputTest, SetAttributeOffsetOutOfBounds) {
     // Control case, setting max attribute offset for FloatR32 vertex format
-    utils::ComboInputStateDescriptor state;
-    state.numInputs = 1;
+    utils::ComboVertexInputDescriptor state;
+    state.numBuffers = 1;
     state.numAttributes = 1;
     state.cAttributes[0].offset = kMaxVertexAttributeEnd - sizeof(dawn::VertexFormat::Float);
     CreatePipeline(true, state, R"(
@@ -259,9 +259,9 @@
 }
 
 // Check attribute offset overflow
-TEST_F(InputStateTest, SetAttributeOffsetOverflow) {
-    utils::ComboInputStateDescriptor state;
-    state.numInputs = 1;
+TEST_F(VertexInputTest, SetAttributeOffsetOverflow) {
+    utils::ComboVertexInputDescriptor state;
+    state.numBuffers = 1;
     state.numAttributes = 1;
     state.cAttributes[0].offset = std::numeric_limits<uint32_t>::max();
     CreatePipeline(false, state, R"(
@@ -273,10 +273,10 @@
 }
 
 // Check that all attributes must be backed by an input
-TEST_F(InputStateTest, RequireInputForAttribute) {
+TEST_F(VertexInputTest, RequireInputForAttribute) {
     // Control case
-    utils::ComboInputStateDescriptor state;
-    state.numInputs = 1;
+    utils::ComboVertexInputDescriptor state;
+    state.numBuffers = 1;
     state.numAttributes = 1;
     CreatePipeline(true, state, R"(
         #version 450
@@ -296,10 +296,10 @@
 }
 
 // Check OOB checks for an attribute's input
-TEST_F(InputStateTest, SetAttributeOOBCheckForInputs) {
+TEST_F(VertexInputTest, SetAttributeOOBCheckForInputs) {
     // Control case
-    utils::ComboInputStateDescriptor state;
-    state.numInputs = 1;
+    utils::ComboVertexInputDescriptor state;
+    state.numBuffers = 1;
     state.numAttributes = 1;
     CreatePipeline(true, state, R"(
         #version 450
diff --git a/src/tests/unittests/wire/WireArgumentTests.cpp b/src/tests/unittests/wire/WireArgumentTests.cpp
index 965ab2c..c63435a 100644
--- a/src/tests/unittests/wire/WireArgumentTests.cpp
+++ b/src/tests/unittests/wire/WireArgumentTests.cpp
@@ -97,13 +97,13 @@
     colorStateDescriptor.writeMask = DAWN_COLOR_WRITE_MASK_ALL;
 
     // Create the input state
-    DawnInputStateDescriptor inputState;
-    inputState.nextInChain = nullptr;
-    inputState.indexFormat = DAWN_INDEX_FORMAT_UINT32;
-    inputState.numInputs = 0;
-    inputState.inputs = nullptr;
-    inputState.numAttributes = 0;
-    inputState.attributes = nullptr;
+    DawnVertexInputDescriptor vertexInput;
+    vertexInput.nextInChain = nullptr;
+    vertexInput.indexFormat = DAWN_INDEX_FORMAT_UINT32;
+    vertexInput.numBuffers = 0;
+    vertexInput.buffers = nullptr;
+    vertexInput.numAttributes = 0;
+    vertexInput.attributes = nullptr;
 
     // Create the rasterization state
     DawnRasterizationStateDescriptor rasterizationState;
@@ -162,7 +162,7 @@
 
     pipelineDescriptor.sampleCount = 1;
     pipelineDescriptor.layout = layout;
-    pipelineDescriptor.inputState = &inputState;
+    pipelineDescriptor.vertexInput = &vertexInput;
     pipelineDescriptor.primitiveTopology = DAWN_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
     pipelineDescriptor.rasterizationState = &rasterizationState;
     pipelineDescriptor.depthStencilState = &depthStencilState;
diff --git a/src/tests/unittests/wire/WireOptionalTests.cpp b/src/tests/unittests/wire/WireOptionalTests.cpp
index 02a3251..5a94a29 100644
--- a/src/tests/unittests/wire/WireOptionalTests.cpp
+++ b/src/tests/unittests/wire/WireOptionalTests.cpp
@@ -87,13 +87,13 @@
     colorStateDescriptor.writeMask = DAWN_COLOR_WRITE_MASK_ALL;
 
     // Create the input state
-    DawnInputStateDescriptor inputState;
-    inputState.nextInChain = nullptr;
-    inputState.indexFormat = DAWN_INDEX_FORMAT_UINT32;
-    inputState.numInputs = 0;
-    inputState.inputs = nullptr;
-    inputState.numAttributes = 0;
-    inputState.attributes = nullptr;
+    DawnVertexInputDescriptor vertexInput;
+    vertexInput.nextInChain = nullptr;
+    vertexInput.indexFormat = DAWN_INDEX_FORMAT_UINT32;
+    vertexInput.numBuffers = 0;
+    vertexInput.buffers = nullptr;
+    vertexInput.numAttributes = 0;
+    vertexInput.attributes = nullptr;
 
     // Create the rasterization state
     DawnRasterizationStateDescriptor rasterizationState;
@@ -152,7 +152,7 @@
 
     pipelineDescriptor.sampleCount = 1;
     pipelineDescriptor.layout = layout;
-    pipelineDescriptor.inputState = &inputState;
+    pipelineDescriptor.vertexInput = &vertexInput;
     pipelineDescriptor.primitiveTopology = DAWN_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
     pipelineDescriptor.rasterizationState = &rasterizationState;
 
diff --git a/src/utils/ComboRenderPipelineDescriptor.cpp b/src/utils/ComboRenderPipelineDescriptor.cpp
index e0a1a1a..ee0a3d5 100644
--- a/src/utils/ComboRenderPipelineDescriptor.cpp
+++ b/src/utils/ComboRenderPipelineDescriptor.cpp
@@ -18,21 +18,21 @@
 
 namespace utils {
 
-    ComboInputStateDescriptor::ComboInputStateDescriptor() {
-        dawn::InputStateDescriptor* descriptor = this;
+    ComboVertexInputDescriptor::ComboVertexInputDescriptor() {
+        dawn::VertexInputDescriptor* descriptor = this;
 
         descriptor->indexFormat = dawn::IndexFormat::Uint32;
 
-        // Fill the default values for vertexInput.
-        descriptor->numInputs = 0;
-        dawn::VertexInputDescriptor vertexInput;
-        vertexInput.inputSlot = 0;
-        vertexInput.stride = 0;
-        vertexInput.stepMode = dawn::InputStepMode::Vertex;
-        for (uint32_t i = 0; i < kMaxVertexInputs; ++i) {
-            cInputs[i] = vertexInput;
+        // Fill the default values for vertexBuffer.
+        descriptor->numBuffers = 0;
+        dawn::VertexBufferDescriptor vertexBuffer;
+        vertexBuffer.inputSlot = 0;
+        vertexBuffer.stride = 0;
+        vertexBuffer.stepMode = dawn::InputStepMode::Vertex;
+        for (uint32_t i = 0; i < kMaxVertexBuffers; ++i) {
+            cBuffers[i] = vertexBuffer;
         }
-        descriptor->inputs = &cInputs[0];
+        descriptor->buffers = &cBuffers[0];
 
         // Fill the default values for vertexAttribute.
         descriptor->numAttributes = 0;
@@ -66,7 +66,7 @@
         }
 
         // Set defaults for the input state descriptors.
-        descriptor->inputState = &cInputState;
+        descriptor->vertexInput = &cVertexInput;
 
         // Set defaults for the rasterization state descriptor.
         {
diff --git a/src/utils/ComboRenderPipelineDescriptor.h b/src/utils/ComboRenderPipelineDescriptor.h
index 69ab688..8be63d2 100644
--- a/src/utils/ComboRenderPipelineDescriptor.h
+++ b/src/utils/ComboRenderPipelineDescriptor.h
@@ -23,11 +23,11 @@
 

 namespace utils {

 

-    class ComboInputStateDescriptor : public dawn::InputStateDescriptor {

+    class ComboVertexInputDescriptor : public dawn::VertexInputDescriptor {

       public:

-        ComboInputStateDescriptor();

+        ComboVertexInputDescriptor();

 

-        std::array<dawn::VertexInputDescriptor, kMaxVertexInputs> cInputs;

+        std::array<dawn::VertexBufferDescriptor, kMaxVertexBuffers> cBuffers;

         std::array<dawn::VertexAttributeDescriptor, kMaxVertexAttributes> cAttributes;

     };

 

@@ -38,7 +38,7 @@
         dawn::PipelineStageDescriptor cVertexStage;

         dawn::PipelineStageDescriptor cFragmentStage;

 

-        ComboInputStateDescriptor cInputState;

+        ComboVertexInputDescriptor cVertexInput;

         dawn::RasterizationStateDescriptor cRasterizationState;

         std::array<dawn::ColorStateDescriptor*, kMaxColorAttachments> cColorStates;

         dawn::DepthStencilStateDescriptor cDepthStencilState;