Add SetIndex/VertexBuffer offset argument alignment constraints

The vertex buffer alignment in particular is helps make the
implementation of programmable pulling much easier on Metal since the
vertex data will be able to be represented as array<u32>.

Bug: dawn:805
Change-Id: I2bf2742db3b8fa478be620c892925b8b75dc514c
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/54659
Reviewed-by: Stephen White <senorblanco@chromium.org>
Reviewed-by: Kai Ninomiya <kainino@chromium.org>
Commit-Queue: Kai Ninomiya <kainino@chromium.org>
diff --git a/src/tests/unittests/validation/IndexBufferValidationTests.cpp b/src/tests/unittests/validation/IndexBufferValidationTests.cpp
index 27f7b21..f2da91d 100644
--- a/src/tests/unittests/validation/IndexBufferValidationTests.cpp
+++ b/src/tests/unittests/validation/IndexBufferValidationTests.cpp
@@ -224,3 +224,39 @@
         ASSERT_DEVICE_ERROR(encoder.Finish());
     }
 }
+
+// Check the alignment constraint on the index buffer offset.
+TEST_F(IndexBufferValidationTest, OffsetAlignment) {
+    wgpu::Buffer indexBuffer =
+        utils::CreateBufferFromData<uint32_t>(device, wgpu::BufferUsage::Index, {0, 1, 2});
+
+    DummyRenderPass renderPass(device);
+    // Control cases: index buffer offset is a multiple of the index format size
+    {
+        wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
+        wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass);
+        pass.SetIndexBuffer(indexBuffer, wgpu::IndexFormat::Uint32, 0);
+        pass.SetIndexBuffer(indexBuffer, wgpu::IndexFormat::Uint32, 4);
+        pass.SetIndexBuffer(indexBuffer, wgpu::IndexFormat::Uint16, 0);
+        pass.SetIndexBuffer(indexBuffer, wgpu::IndexFormat::Uint16, 2);
+        pass.EndPass();
+        encoder.Finish();
+    }
+
+    // Error case: index buffer offset isn't a multiple of 4 for IndexFormat::Uint32
+    {
+        wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
+        wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass);
+        pass.SetIndexBuffer(indexBuffer, wgpu::IndexFormat::Uint32, 2);
+        pass.EndPass();
+        ASSERT_DEVICE_ERROR(encoder.Finish());
+    }
+    // Error case: index buffer offset isn't a multiple of 2 for IndexFormat::Uint16
+    {
+        wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
+        wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass);
+        pass.SetIndexBuffer(indexBuffer, wgpu::IndexFormat::Uint16, 1);
+        pass.EndPass();
+        ASSERT_DEVICE_ERROR(encoder.Finish());
+    }
+}