Support larger maxVertexAttributes (30)

This patch adds the support of larger maxVertexAttributes (30) in Dawn.
The main reason to choose 30 as the Tier1 value of maxVertexAttributes
is that on D3D12 D3D12_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT is 32, while
both SV_VertexID and SV_InstanceID will consume one vertex input slot.
Otherwise when creating such render pipeline DXC will crash and FXC will
generate below error message:
error X4506: vs_5_1 input limit (32) exceeded, shader uses 33 inputs.

This patch also fixes a bug on the assignment of maxVertexAttributes on
the OpenGL backend. According to OpenGL ES SPEC, attribindex must be
less than the value of GL_MAX_VERTEX_ATTRIBS, so GL_MAX_VERTEX_ATTRIBS
should exactly mean maxVertexAttributes in WebGPU.

Fixed: dawn:2223
Test: dawn_end2end_tests
Change-Id: I1916b2d676296e98f74bf6d17684000ccd7a03bc
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/170140
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: Austin Eng <enga@chromium.org>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Commit-Queue: Jiawei Shao <jiawei.shao@intel.com>
diff --git a/src/dawn/common/Constants.h b/src/dawn/common/Constants.h
index 79dc0f3..4ae4ea8 100644
--- a/src/dawn/common/Constants.h
+++ b/src/dawn/common/Constants.h
@@ -35,7 +35,7 @@
 
 static constexpr uint32_t kMaxBindGroups = 4u;
 static constexpr uint32_t kMaxBindingsPerBindGroup = 1000u;
-static constexpr uint8_t kMaxVertexAttributes = 16u;
+static constexpr uint8_t kMaxVertexAttributes = 30u;
 static constexpr uint8_t kMaxVertexBuffers = 8u;
 static constexpr uint32_t kMaxVertexBufferArrayStride = 2048u;
 static constexpr uint32_t kMaxBindGroupsPlusVertexBuffers = 24u;
diff --git a/src/dawn/native/Limits.cpp b/src/dawn/native/Limits.cpp
index 6457744..808179e 100644
--- a/src/dawn/native/Limits.cpp
+++ b/src/dawn/native/Limits.cpp
@@ -118,7 +118,7 @@
     X(Alignment,           minUniformBufferOffsetAlignment,       256,       256,        256) \
     X(Alignment,           minStorageBufferOffsetAlignment,       256,       256,        256) \
     X(Maximum,                            maxVertexBuffers,         8,         8,          8) \
-    X(Maximum,                         maxVertexAttributes,        16,        16,         16) \
+    X(Maximum,                         maxVertexAttributes,        16,        16,         30) \
     X(Maximum,                  maxVertexBufferArrayStride,      2048,      2048,       2048) \
     X(Maximum,                         maxColorAttachments,         4,         8,          8)
 
diff --git a/src/dawn/native/RenderPipeline.cpp b/src/dawn/native/RenderPipeline.cpp
index 1ae53c0..1ea00b0 100644
--- a/src/dawn/native/RenderPipeline.cpp
+++ b/src/dawn/native/RenderPipeline.cpp
@@ -101,11 +101,12 @@
     DAWN_TRY(ValidateVertexFormat(attribute->format));
     const VertexFormatInfo& formatInfo = GetVertexFormatInfo(attribute->format);
 
+    uint32_t maxVertexAttributes = device->GetLimits().v1.maxVertexAttributes;
     DAWN_INVALID_IF(
-        attribute->shaderLocation >= kMaxVertexAttributes,
+        attribute->shaderLocation >= maxVertexAttributes,
         "Attribute shader location (%u) exceeds the maximum number of vertex attributes "
         "(%u).",
-        attribute->shaderLocation, kMaxVertexAttributes);
+        attribute->shaderLocation, maxVertexAttributes);
 
     VertexAttributeLocation location(static_cast<uint8_t>(attribute->shaderLocation));
 
diff --git a/src/dawn/native/d3d11/PhysicalDeviceD3D11.cpp b/src/dawn/native/d3d11/PhysicalDeviceD3D11.cpp
index 86c7738..59e887c 100644
--- a/src/dawn/native/d3d11/PhysicalDeviceD3D11.cpp
+++ b/src/dawn/native/d3d11/PhysicalDeviceD3D11.cpp
@@ -225,7 +225,8 @@
     // Slot values can be 0-15, inclusive:
     // https://docs.microsoft.com/en-ca/windows/win32/api/d3d11/ns-d3d11-d3d11_input_element_desc
     limits->v1.maxVertexBuffers = 16;
-    limits->v1.maxVertexAttributes = D3D11_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT;
+    // Both SV_VertexID and SV_InstanceID will consume vertex input slots.
+    limits->v1.maxVertexAttributes = D3D11_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT - 2;
 
     uint32_t maxUAVsAllStages = mFeatureLevel == D3D_FEATURE_LEVEL_11_1
                                     ? D3D11_1_UAV_SLOT_COUNT
diff --git a/src/dawn/native/d3d12/PhysicalDeviceD3D12.cpp b/src/dawn/native/d3d12/PhysicalDeviceD3D12.cpp
index 9b87467..34fa781 100644
--- a/src/dawn/native/d3d12/PhysicalDeviceD3D12.cpp
+++ b/src/dawn/native/d3d12/PhysicalDeviceD3D12.cpp
@@ -217,7 +217,8 @@
     // Slot values can be 0-15, inclusive:
     // https://docs.microsoft.com/en-ca/windows/win32/api/d3d12/ns-d3d12-d3d12_input_element_desc
     limits->v1.maxVertexBuffers = 16;
-    limits->v1.maxVertexAttributes = D3D12_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT;
+    // Both SV_VertexID and SV_InstanceID will consume vertex input slots.
+    limits->v1.maxVertexAttributes = D3D12_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT - 2;
 
     // Note: WebGPU requires FL11.1+
     // https://docs.microsoft.com/en-us/windows/win32/direct3d12/hardware-support
diff --git a/src/dawn/native/opengl/PhysicalDeviceGL.cpp b/src/dawn/native/opengl/PhysicalDeviceGL.cpp
index 7f85eb5..21fbb2b 100644
--- a/src/dawn/native/opengl/PhysicalDeviceGL.cpp
+++ b/src/dawn/native/opengl/PhysicalDeviceGL.cpp
@@ -283,8 +283,7 @@
     limits->v1.minStorageBufferOffsetAlignment = Get(gl, GL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT);
     limits->v1.maxVertexBuffers = Get(gl, GL_MAX_VERTEX_ATTRIB_BINDINGS);
     limits->v1.maxBufferSize = kAssumedMaxBufferSize;
-    GLint maxVertexAttribs = Get(gl, GL_MAX_VERTEX_ATTRIBS);
-    limits->v1.maxVertexAttributes = limits->v1.maxVertexBuffers * maxVertexAttribs;
+    limits->v1.maxVertexAttributes = Get(gl, GL_MAX_VERTEX_ATTRIBS);
     limits->v1.maxVertexBufferArrayStride = Get(gl, GL_MAX_VERTEX_ATTRIB_STRIDE);
     limits->v1.maxInterStageShaderComponents = Get(gl, GL_MAX_VARYING_COMPONENTS);
     limits->v1.maxInterStageShaderVariables = Get(gl, GL_MAX_VARYING_VECTORS);
diff --git a/src/dawn/tests/unittests/validation/VertexStateValidationTests.cpp b/src/dawn/tests/unittests/validation/VertexStateValidationTests.cpp
index c21e0bf..c889162 100644
--- a/src/dawn/tests/unittests/validation/VertexStateValidationTests.cpp
+++ b/src/dawn/tests/unittests/validation/VertexStateValidationTests.cpp
@@ -203,18 +203,22 @@
 
 // Check out of bounds condition on total number of vertex attributes
 TEST_F(VertexStateTest, SetVertexAttributesNumLimit) {
+    wgpu::SupportedLimits limits;
+    device.GetLimits(&limits);
+    uint32_t maxVertexAttributes = limits.limits.maxVertexAttributes;
+
     // Control case, setting max vertex attribute number
     utils::ComboVertexState state;
     state.vertexBufferCount = 2;
-    state.cVertexBuffers[0].attributeCount = kMaxVertexAttributes;
-    for (uint32_t i = 0; i < kMaxVertexAttributes; ++i) {
+    state.cVertexBuffers[0].attributeCount = maxVertexAttributes;
+    for (uint32_t i = 0; i < maxVertexAttributes; ++i) {
         state.cAttributes[i].shaderLocation = i;
     }
     CreatePipeline(true, state, kPlaceholderVertexShader);
 
     // Test vertex attribute number exceed the limit
     state.cVertexBuffers[1].attributeCount = 1;
-    state.cVertexBuffers[1].attributes = &state.cAttributes[kMaxVertexAttributes - 1];
+    state.cVertexBuffers[1].attributes = &state.cAttributes[maxVertexAttributes - 1];
     CreatePipeline(false, state, kPlaceholderVertexShader);
 }
 
@@ -289,15 +293,19 @@
 
 // Check out of bounds condition on attribute shader location
 TEST_F(VertexStateTest, SetAttributeLocationOutOfBounds) {
+    wgpu::SupportedLimits limits;
+    device.GetLimits(&limits);
+    uint32_t maxVertexAttributes = limits.limits.maxVertexAttributes;
+
     // Control case, setting last attribute shader location
     utils::ComboVertexState state;
     state.vertexBufferCount = 1;
     state.cVertexBuffers[0].attributeCount = 1;
-    state.cAttributes[0].shaderLocation = kMaxVertexAttributes - 1;
+    state.cAttributes[0].shaderLocation = maxVertexAttributes - 1;
     CreatePipeline(true, state, kPlaceholderVertexShader);
 
     // Test attribute location OOB
-    state.cAttributes[0].shaderLocation = kMaxVertexAttributes;
+    state.cAttributes[0].shaderLocation = maxVertexAttributes;
     CreatePipeline(false, state, kPlaceholderVertexShader);
 }