• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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