1 // Copyright 2019 The Dawn Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include <initializer_list>
16 #include <limits>
17 #include "tests/unittests/validation/ValidationTest.h"
18 #include "utils/WGPUHelpers.h"
19
20 class ComputeIndirectValidationTest : public ValidationTest {
21 protected:
SetUp()22 void SetUp() override {
23 ValidationTest::SetUp();
24
25 wgpu::ShaderModule computeModule = utils::CreateShaderModule(device, R"(
26 [[stage(compute), workgroup_size(1)]] fn main() {
27 })");
28
29 // Set up compute pipeline
30 wgpu::PipelineLayout pl = utils::MakeBasicPipelineLayout(device, nullptr);
31
32 wgpu::ComputePipelineDescriptor csDesc;
33 csDesc.layout = pl;
34 csDesc.compute.module = computeModule;
35 csDesc.compute.entryPoint = "main";
36 pipeline = device.CreateComputePipeline(&csDesc);
37 }
38
ValidateExpectation(wgpu::CommandEncoder encoder,utils::Expectation expectation)39 void ValidateExpectation(wgpu::CommandEncoder encoder, utils::Expectation expectation) {
40 if (expectation == utils::Expectation::Success) {
41 encoder.Finish();
42 } else {
43 ASSERT_DEVICE_ERROR(encoder.Finish());
44 }
45 }
46
TestIndirectOffset(utils::Expectation expectation,std::initializer_list<uint32_t> bufferList,uint64_t indirectOffset,wgpu::BufferUsage usage=wgpu::BufferUsage::Indirect)47 void TestIndirectOffset(utils::Expectation expectation,
48 std::initializer_list<uint32_t> bufferList,
49 uint64_t indirectOffset,
50 wgpu::BufferUsage usage = wgpu::BufferUsage::Indirect) {
51 wgpu::Buffer indirectBuffer =
52 utils::CreateBufferFromData<uint32_t>(device, usage, bufferList);
53
54 wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
55 wgpu::ComputePassEncoder pass = encoder.BeginComputePass();
56 pass.SetPipeline(pipeline);
57 pass.DispatchIndirect(indirectBuffer, indirectOffset);
58 pass.EndPass();
59
60 ValidateExpectation(encoder, expectation);
61 }
62
63 wgpu::ComputePipeline pipeline;
64 };
65
66 // Verify out of bounds indirect dispatch calls are caught early
TEST_F(ComputeIndirectValidationTest,IndirectOffsetBounds)67 TEST_F(ComputeIndirectValidationTest, IndirectOffsetBounds) {
68 // In bounds
69 TestIndirectOffset(utils::Expectation::Success, {1, 2, 3}, 0);
70 // In bounds, bigger buffer
71 TestIndirectOffset(utils::Expectation::Success, {1, 2, 3, 4, 5, 6}, 0);
72 // In bounds, bigger buffer, positive offset
73 TestIndirectOffset(utils::Expectation::Success, {1, 2, 3, 4, 5, 6}, 3 * sizeof(uint32_t));
74
75 // In bounds, non-multiple of 4 offsets
76 TestIndirectOffset(utils::Expectation::Failure, {1, 2, 3, 4}, 1);
77 TestIndirectOffset(utils::Expectation::Failure, {1, 2, 3, 4}, 2);
78
79 // Out of bounds, buffer too small
80 TestIndirectOffset(utils::Expectation::Failure, {1, 2}, 0);
81 // Out of bounds, index too big
82 TestIndirectOffset(utils::Expectation::Failure, {1, 2, 3}, 1 * sizeof(uint32_t));
83 // Out of bounds, index past buffer
84 TestIndirectOffset(utils::Expectation::Failure, {1, 2, 3}, 4 * sizeof(uint32_t));
85 // Out of bounds, index + size of command overflows
86 uint64_t offset = std::numeric_limits<uint64_t>::max();
87 TestIndirectOffset(utils::Expectation::Failure, {1, 2, 3, 4, 5, 6}, offset);
88 }
89
90 // Check that the buffer must have the indirect usage
TEST_F(ComputeIndirectValidationTest,IndirectUsage)91 TEST_F(ComputeIndirectValidationTest, IndirectUsage) {
92 // Control case: using a buffer with the indirect usage is valid.
93 TestIndirectOffset(utils::Expectation::Success, {1, 2, 3}, 0, wgpu::BufferUsage::Indirect);
94
95 // Error case: using a buffer with the vertex usage is an error.
96 TestIndirectOffset(utils::Expectation::Failure, {1, 2, 3}, 0, wgpu::BufferUsage::Vertex);
97 }
98