Port VertexStateValidationTests to WGSL

Bug: dawn:572
Change-Id: I904f032125797de53d4e85f8670ea36887749ac8
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/33933
Reviewed-by: Austin Eng <enga@chromium.org>
Reviewed-by: Ben Clayton <bclayton@google.com>
Commit-Queue: Corentin Wallez <cwallez@chromium.org>
This commit is contained in:
Corentin Wallez 2020-11-26 12:30:37 +00:00 committed by Commit Bot service account
parent 7e8c35df46
commit 435da1c2dc
1 changed files with 58 additions and 204 deletions

View File

@ -21,15 +21,12 @@ class VertexStateTest : public ValidationTest {
protected: protected:
void CreatePipeline(bool success, void CreatePipeline(bool success,
const utils::ComboVertexStateDescriptor& state, const utils::ComboVertexStateDescriptor& state,
std::string vertexSource) { const char* vertexSource) {
wgpu::ShaderModule vsModule = utils::CreateShaderModule( wgpu::ShaderModule vsModule = utils::CreateShaderModuleFromWGSL(device, vertexSource);
device, utils::SingleShaderStage::Vertex, vertexSource.c_str()); wgpu::ShaderModule fsModule = utils::CreateShaderModuleFromWGSL(device, R"(
wgpu::ShaderModule fsModule = [[location(0)]] var<out> fragColor : vec4<f32>;
utils::CreateShaderModule(device, utils::SingleShaderStage::Fragment, R"( [[stage(fragment)]] fn main() -> void {
#version 450 fragColor = vec4<f32>(1.0, 0.0, 0.0, 1.0);
layout(location = 0) out vec4 fragColor;
void main() {
fragColor = vec4(1.0, 0.0, 0.0, 1.0);
} }
)"); )");
@ -45,17 +42,19 @@ class VertexStateTest : public ValidationTest {
device.CreateRenderPipeline(&descriptor); device.CreateRenderPipeline(&descriptor);
} }
} }
const char* kDummyVertexShader = R"(
[[builtin(position)]] var<out> Position : vec4<f32>;
[[stage(vertex)]] fn main() -> void {
Position = vec4<f32>(0.0, 0.0, 0.0, 0.0);
}
)";
}; };
// Check an empty vertex input is valid // Check an empty vertex input is valid
TEST_F(VertexStateTest, EmptyIsOk) { TEST_F(VertexStateTest, EmptyIsOk) {
utils::ComboVertexStateDescriptor state; utils::ComboVertexStateDescriptor state;
CreatePipeline(true, state, R"( CreatePipeline(true, state, kDummyVertexShader);
#version 450
void main() {
gl_Position = vec4(0.0);
}
)");
} }
// Check null buffer is valid // Check null buffer is valid
@ -66,12 +65,7 @@ TEST_F(VertexStateTest, NullBufferIsOk) {
state.cVertexBuffers[0].arrayStride = 0; state.cVertexBuffers[0].arrayStride = 0;
state.cVertexBuffers[0].attributeCount = 0; state.cVertexBuffers[0].attributeCount = 0;
state.cVertexBuffers[0].attributes = nullptr; state.cVertexBuffers[0].attributes = nullptr;
CreatePipeline(true, state, R"( CreatePipeline(true, state, kDummyVertexShader);
#version 450
void main() {
gl_Position = vec4(0.0);
}
)");
// One null buffer (buffer[0]) followed by a buffer (buffer[1]) is OK // One null buffer (buffer[0]) followed by a buffer (buffer[1]) is OK
state.vertexBufferCount = 2; state.vertexBufferCount = 2;
@ -79,12 +73,7 @@ TEST_F(VertexStateTest, NullBufferIsOk) {
state.cVertexBuffers[1].attributeCount = 1; state.cVertexBuffers[1].attributeCount = 1;
state.cVertexBuffers[1].attributes = &state.cAttributes[0]; state.cVertexBuffers[1].attributes = &state.cAttributes[0];
state.cAttributes[0].shaderLocation = 0; state.cAttributes[0].shaderLocation = 0;
CreatePipeline(true, state, R"( CreatePipeline(true, state, kDummyVertexShader);
#version 450
void main() {
gl_Position = vec4(0.0);
}
)");
// Null buffer (buffer[2]) sitting between buffers (buffer[1] and buffer[3]) is OK // Null buffer (buffer[2]) sitting between buffers (buffer[1] and buffer[3]) is OK
state.vertexBufferCount = 4; state.vertexBufferCount = 4;
@ -93,12 +82,7 @@ TEST_F(VertexStateTest, NullBufferIsOk) {
state.cVertexBuffers[3].attributeCount = 1; state.cVertexBuffers[3].attributeCount = 1;
state.cVertexBuffers[3].attributes = &state.cAttributes[1]; state.cVertexBuffers[3].attributes = &state.cAttributes[1];
state.cAttributes[1].shaderLocation = 1; state.cAttributes[1].shaderLocation = 1;
CreatePipeline(true, state, R"( CreatePipeline(true, state, kDummyVertexShader);
#version 450
void main() {
gl_Position = vec4(0.0);
}
)");
} }
// Check validation that pipeline vertex buffers are backed by attributes in the vertex input // Check validation that pipeline vertex buffers are backed by attributes in the vertex input
@ -114,29 +98,29 @@ TEST_F(VertexStateTest, PipelineCompatibility) {
// Control case: pipeline with one input per attribute // Control case: pipeline with one input per attribute
CreatePipeline(true, state, R"( CreatePipeline(true, state, R"(
#version 450 [[location(0)]] var<in> a : vec4<f32>;
layout(location = 0) in vec4 a; [[location(1)]] var<in> b : vec4<f32>;
layout(location = 1) in vec4 b; [[builtin(position)]] var<out> Position : vec4<f32>;
void main() { [[stage(vertex)]] fn main() -> void {
gl_Position = vec4(0.0); Position = vec4<f32>(0.0, 0.0, 0.0, 0.0);
} }
)"); )");
// Check it is valid for the pipeline to use a subset of the VertexState // Check it is valid for the pipeline to use a subset of the VertexState
CreatePipeline(true, state, R"( CreatePipeline(true, state, R"(
#version 450 [[location(0)]] var<in> a : vec4<f32>;
layout(location = 0) in vec4 a; [[builtin(position)]] var<out> Position : vec4<f32>;
void main() { [[stage(vertex)]] fn main() -> void {
gl_Position = vec4(0.0); Position = vec4<f32>(0.0, 0.0, 0.0, 0.0);
} }
)"); )");
// Check for an error when the pipeline uses an attribute not in the vertex input // Check for an error when the pipeline uses an attribute not in the vertex input
CreatePipeline(false, state, R"( CreatePipeline(false, state, R"(
#version 450 [[location(2)]] var<in> a : vec4<f32>;
layout(location = 2) in vec4 a; [[builtin(position)]] var<out> Position : vec4<f32>;
void main() { [[stage(vertex)]] fn main() -> void {
gl_Position = vec4(0.0); Position = vec4<f32>(0.0, 0.0, 0.0, 0.0);
} }
)"); )");
} }
@ -148,21 +132,11 @@ TEST_F(VertexStateTest, StrideZero) {
state.vertexBufferCount = 1; state.vertexBufferCount = 1;
state.cVertexBuffers[0].arrayStride = 0; state.cVertexBuffers[0].arrayStride = 0;
state.cVertexBuffers[0].attributeCount = 1; state.cVertexBuffers[0].attributeCount = 1;
CreatePipeline(true, state, R"( CreatePipeline(true, state, kDummyVertexShader);
#version 450
void main() {
gl_Position = vec4(0.0);
}
)");
// Works ok with attributes at a large-ish offset // Works ok with attributes at a large-ish offset
state.cAttributes[0].offset = 128; state.cAttributes[0].offset = 128;
CreatePipeline(true, state, R"( CreatePipeline(true, state, kDummyVertexShader);
#version 450
void main() {
gl_Position = vec4(0.0);
}
)");
} }
// Check validation that vertex attribute offset should be within vertex buffer arrayStride, // Check validation that vertex attribute offset should be within vertex buffer arrayStride,
@ -176,30 +150,15 @@ TEST_F(VertexStateTest, SetOffsetOutOfBounds) {
state.cAttributes[0].shaderLocation = 0; state.cAttributes[0].shaderLocation = 0;
state.cAttributes[1].shaderLocation = 1; state.cAttributes[1].shaderLocation = 1;
state.cAttributes[1].offset = sizeof(float); state.cAttributes[1].offset = sizeof(float);
CreatePipeline(true, state, R"( CreatePipeline(true, state, kDummyVertexShader);
#version 450
void main() {
gl_Position = vec4(0.0);
}
)");
// Test vertex attribute offset exceed vertex buffer arrayStride range // Test vertex attribute offset exceed vertex buffer arrayStride range
state.cVertexBuffers[0].arrayStride = sizeof(float); state.cVertexBuffers[0].arrayStride = sizeof(float);
CreatePipeline(false, state, R"( CreatePipeline(false, state, kDummyVertexShader);
#version 450
void main() {
gl_Position = vec4(0.0);
}
)");
// It's OK if arrayStride is zero // It's OK if arrayStride is zero
state.cVertexBuffers[0].arrayStride = 0; state.cVertexBuffers[0].arrayStride = 0;
CreatePipeline(true, state, R"( CreatePipeline(true, state, kDummyVertexShader);
#version 450
void main() {
gl_Position = vec4(0.0);
}
)");
} }
// Check out of bounds condition on total number of vertex buffers // Check out of bounds condition on total number of vertex buffers
@ -212,21 +171,11 @@ TEST_F(VertexStateTest, SetVertexBuffersNumLimit) {
state.cVertexBuffers[i].attributes = &state.cAttributes[i]; state.cVertexBuffers[i].attributes = &state.cAttributes[i];
state.cAttributes[i].shaderLocation = i; state.cAttributes[i].shaderLocation = i;
} }
CreatePipeline(true, state, R"( CreatePipeline(true, state, kDummyVertexShader);
#version 450
void main() {
gl_Position = vec4(0.0);
}
)");
// Test vertex buffer number exceed the limit // Test vertex buffer number exceed the limit
state.vertexBufferCount = kMaxVertexBuffers + 1; state.vertexBufferCount = kMaxVertexBuffers + 1;
CreatePipeline(false, state, R"( CreatePipeline(false, state, kDummyVertexShader);
#version 450
void main() {
gl_Position = vec4(0.0);
}
)");
} }
// Check out of bounds condition on total number of vertex attributes // Check out of bounds condition on total number of vertex attributes
@ -238,22 +187,12 @@ TEST_F(VertexStateTest, SetVertexAttributesNumLimit) {
for (uint32_t i = 0; i < kMaxVertexAttributes; ++i) { for (uint32_t i = 0; i < kMaxVertexAttributes; ++i) {
state.cAttributes[i].shaderLocation = i; state.cAttributes[i].shaderLocation = i;
} }
CreatePipeline(true, state, R"( CreatePipeline(true, state, kDummyVertexShader);
#version 450
void main() {
gl_Position = vec4(0.0);
}
)");
// Test vertex attribute number exceed the limit // Test vertex attribute number exceed the limit
state.cVertexBuffers[1].attributeCount = 1; state.cVertexBuffers[1].attributeCount = 1;
state.cVertexBuffers[1].attributes = &state.cAttributes[kMaxVertexAttributes - 1]; state.cVertexBuffers[1].attributes = &state.cAttributes[kMaxVertexAttributes - 1];
CreatePipeline(false, state, R"( CreatePipeline(false, state, kDummyVertexShader);
#version 450
void main() {
gl_Position = vec4(0.0);
}
)");
} }
// Check out of bounds condition on input arrayStride // Check out of bounds condition on input arrayStride
@ -263,21 +202,11 @@ TEST_F(VertexStateTest, SetInputStrideOutOfBounds) {
state.vertexBufferCount = 1; state.vertexBufferCount = 1;
state.cVertexBuffers[0].arrayStride = kMaxVertexBufferStride; state.cVertexBuffers[0].arrayStride = kMaxVertexBufferStride;
state.cVertexBuffers[0].attributeCount = 1; state.cVertexBuffers[0].attributeCount = 1;
CreatePipeline(true, state, R"( CreatePipeline(true, state, kDummyVertexShader);
#version 450
void main() {
gl_Position = vec4(0.0);
}
)");
// Test input arrayStride OOB // Test input arrayStride OOB
state.cVertexBuffers[0].arrayStride = kMaxVertexBufferStride + 1; state.cVertexBuffers[0].arrayStride = kMaxVertexBufferStride + 1;
CreatePipeline(false, state, R"( CreatePipeline(false, state, kDummyVertexShader);
#version 450
void main() {
gl_Position = vec4(0.0);
}
)");
} }
// Check multiple of 4 bytes constraint on input arrayStride // Check multiple of 4 bytes constraint on input arrayStride
@ -287,21 +216,11 @@ TEST_F(VertexStateTest, SetInputStrideNotAligned) {
state.vertexBufferCount = 1; state.vertexBufferCount = 1;
state.cVertexBuffers[0].arrayStride = 4; state.cVertexBuffers[0].arrayStride = 4;
state.cVertexBuffers[0].attributeCount = 1; state.cVertexBuffers[0].attributeCount = 1;
CreatePipeline(true, state, R"( CreatePipeline(true, state, kDummyVertexShader);
#version 450
void main() {
gl_Position = vec4(0.0);
}
)");
// Test input arrayStride not multiple of 4 bytes // Test input arrayStride not multiple of 4 bytes
state.cVertexBuffers[0].arrayStride = 2; state.cVertexBuffers[0].arrayStride = 2;
CreatePipeline(false, state, R"( CreatePipeline(false, state, kDummyVertexShader);
#version 450
void main() {
gl_Position = vec4(0.0);
}
)");
} }
// Test that we cannot set an already set attribute // Test that we cannot set an already set attribute
@ -311,23 +230,13 @@ TEST_F(VertexStateTest, AlreadySetAttribute) {
state.vertexBufferCount = 1; state.vertexBufferCount = 1;
state.cVertexBuffers[0].attributeCount = 1; state.cVertexBuffers[0].attributeCount = 1;
state.cAttributes[0].shaderLocation = 0; state.cAttributes[0].shaderLocation = 0;
CreatePipeline(true, state, R"( CreatePipeline(true, state, kDummyVertexShader);
#version 450
void main() {
gl_Position = vec4(0.0);
}
)");
// Oh no, attribute 0 is set twice // Oh no, attribute 0 is set twice
state.cVertexBuffers[0].attributeCount = 2; state.cVertexBuffers[0].attributeCount = 2;
state.cAttributes[0].shaderLocation = 0; state.cAttributes[0].shaderLocation = 0;
state.cAttributes[1].shaderLocation = 0; state.cAttributes[1].shaderLocation = 0;
CreatePipeline(false, state, R"( CreatePipeline(false, state, kDummyVertexShader);
#version 450
void main() {
gl_Position = vec4(0.0);
}
)");
} }
// Test that a arrayStride of 0 is valid // Test that a arrayStride of 0 is valid
@ -339,21 +248,11 @@ TEST_F(VertexStateTest, SetSameShaderLocation) {
state.cAttributes[0].shaderLocation = 0; state.cAttributes[0].shaderLocation = 0;
state.cAttributes[1].shaderLocation = 1; state.cAttributes[1].shaderLocation = 1;
state.cAttributes[1].offset = sizeof(float); state.cAttributes[1].offset = sizeof(float);
CreatePipeline(true, state, R"( CreatePipeline(true, state, kDummyVertexShader);
#version 450
void main() {
gl_Position = vec4(0.0);
}
)");
// Test same shader location in two attributes in the same buffer // Test same shader location in two attributes in the same buffer
state.cAttributes[1].shaderLocation = 0; state.cAttributes[1].shaderLocation = 0;
CreatePipeline(false, state, R"( CreatePipeline(false, state, kDummyVertexShader);
#version 450
void main() {
gl_Position = vec4(0.0);
}
)");
// Test same shader location in two attributes in different buffers // Test same shader location in two attributes in different buffers
state.vertexBufferCount = 2; state.vertexBufferCount = 2;
@ -362,12 +261,7 @@ TEST_F(VertexStateTest, SetSameShaderLocation) {
state.cVertexBuffers[1].attributeCount = 1; state.cVertexBuffers[1].attributeCount = 1;
state.cVertexBuffers[1].attributes = &state.cAttributes[1]; state.cVertexBuffers[1].attributes = &state.cAttributes[1];
state.cAttributes[1].shaderLocation = 0; state.cAttributes[1].shaderLocation = 0;
CreatePipeline(false, state, R"( CreatePipeline(false, state, kDummyVertexShader);
#version 450
void main() {
gl_Position = vec4(0.0);
}
)");
} }
// Check out of bounds condition on attribute shader location // Check out of bounds condition on attribute shader location
@ -377,21 +271,11 @@ TEST_F(VertexStateTest, SetAttributeLocationOutOfBounds) {
state.vertexBufferCount = 1; state.vertexBufferCount = 1;
state.cVertexBuffers[0].attributeCount = 1; state.cVertexBuffers[0].attributeCount = 1;
state.cAttributes[0].shaderLocation = kMaxVertexAttributes - 1; state.cAttributes[0].shaderLocation = kMaxVertexAttributes - 1;
CreatePipeline(true, state, R"( CreatePipeline(true, state, kDummyVertexShader);
#version 450
void main() {
gl_Position = vec4(0.0);
}
)");
// Test attribute location OOB // Test attribute location OOB
state.cAttributes[0].shaderLocation = kMaxVertexAttributes; state.cAttributes[0].shaderLocation = kMaxVertexAttributes;
CreatePipeline(false, state, R"( CreatePipeline(false, state, kDummyVertexShader);
#version 450
void main() {
gl_Position = vec4(0.0);
}
)");
} }
// Check attribute offset out of bounds // Check attribute offset out of bounds
@ -401,21 +285,11 @@ TEST_F(VertexStateTest, SetAttributeOffsetOutOfBounds) {
state.vertexBufferCount = 1; state.vertexBufferCount = 1;
state.cVertexBuffers[0].attributeCount = 1; state.cVertexBuffers[0].attributeCount = 1;
state.cAttributes[0].offset = kMaxVertexAttributeEnd - sizeof(wgpu::VertexFormat::Float); state.cAttributes[0].offset = kMaxVertexAttributeEnd - sizeof(wgpu::VertexFormat::Float);
CreatePipeline(true, state, R"( CreatePipeline(true, state, kDummyVertexShader);
#version 450
void main() {
gl_Position = vec4(0.0);
}
)");
// Test attribute offset out of bounds // Test attribute offset out of bounds
state.cAttributes[0].offset = kMaxVertexAttributeEnd - 1; state.cAttributes[0].offset = kMaxVertexAttributeEnd - 1;
CreatePipeline(false, state, R"( CreatePipeline(false, state, kDummyVertexShader);
#version 450
void main() {
gl_Position = vec4(0.0);
}
)");
} }
// Check multiple of 4 bytes constraint on offset // Check multiple of 4 bytes constraint on offset
@ -425,21 +299,11 @@ TEST_F(VertexStateTest, SetOffsetNotAligned) {
state.vertexBufferCount = 1; state.vertexBufferCount = 1;
state.cVertexBuffers[0].attributeCount = 1; state.cVertexBuffers[0].attributeCount = 1;
state.cAttributes[0].offset = 4; state.cAttributes[0].offset = 4;
CreatePipeline(true, state, R"( CreatePipeline(true, state, kDummyVertexShader);
#version 450
void main() {
gl_Position = vec4(0.0);
}
)");
// Test offset not multiple of 4 bytes // Test offset not multiple of 4 bytes
state.cAttributes[0].offset = 2; state.cAttributes[0].offset = 2;
CreatePipeline(false, state, R"( CreatePipeline(false, state, kDummyVertexShader);
#version 450
void main() {
gl_Position = vec4(0.0);
}
)");
} }
// Check attribute offset overflow // Check attribute offset overflow
@ -448,12 +312,7 @@ TEST_F(VertexStateTest, SetAttributeOffsetOverflow) {
state.vertexBufferCount = 1; state.vertexBufferCount = 1;
state.cVertexBuffers[0].attributeCount = 1; state.cVertexBuffers[0].attributeCount = 1;
state.cAttributes[0].offset = std::numeric_limits<uint32_t>::max(); state.cAttributes[0].offset = std::numeric_limits<uint32_t>::max();
CreatePipeline(false, state, R"( CreatePipeline(false, state, kDummyVertexShader);
#version 450
void main() {
gl_Position = vec4(0.0);
}
)");
} }
// Check for some potential underflow in the vertex input validation // Check for some potential underflow in the vertex input validation
@ -463,10 +322,5 @@ TEST_F(VertexStateTest, VertexFormatLargerThanNonZeroStride) {
state.cVertexBuffers[0].arrayStride = 4; state.cVertexBuffers[0].arrayStride = 4;
state.cVertexBuffers[0].attributeCount = 1; state.cVertexBuffers[0].attributeCount = 1;
state.cAttributes[0].format = wgpu::VertexFormat::Float4; state.cAttributes[0].format = wgpu::VertexFormat::Float4;
CreatePipeline(false, state, R"( CreatePipeline(false, state, kDummyVertexShader);
#version 450
void main() {
gl_Position = vec4(0.0);
}
)");
} }