Enforce per-dimension dispatch size limits

Note that this is for direct dispatch calls only. Indirect dispatch
calls are still not validated.

Bug: dawn:1006
Change-Id: I061c15208a01dfb803923823ba4afd38667cad22
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/59122
Reviewed-by: Ryan Harrison <rharrison@chromium.org>
Reviewed-by: Austin Eng <enga@chromium.org>
Commit-Queue: Ken Rockot <rockot@google.com>
This commit is contained in:
Ken Rockot 2021-07-21 20:44:09 +00:00 committed by Dawn LUCI CQ
parent 59668e95c7
commit 2d41f8c1df
2 changed files with 80 additions and 2 deletions

View File

@ -25,6 +25,18 @@
namespace dawn_native {
namespace {
MaybeError ValidatePerDimensionDispatchSizeLimit(uint32_t size) {
if (size > kMaxComputePerDimensionDispatchSize) {
return DAWN_VALIDATION_ERROR("Dispatch size exceeds defined limits");
}
return {};
}
} // namespace
ComputePassEncoder::ComputePassEncoder(DeviceBase* device,
CommandEncoder* commandEncoder,
EncodingContext* encodingContext)
@ -63,6 +75,9 @@ namespace dawn_native {
mEncodingContext->TryEncode(this, [&](CommandAllocator* allocator) -> MaybeError {
if (IsValidationEnabled()) {
DAWN_TRY(mCommandBufferState.ValidateCanDispatch());
DAWN_TRY(ValidatePerDimensionDispatchSizeLimit(x));
DAWN_TRY(ValidatePerDimensionDispatchSizeLimit(y));
DAWN_TRY(ValidatePerDimensionDispatchSizeLimit(z));
}
// Record the synchronization scope for Dispatch, which is just the current bindgroups.

View File

@ -12,9 +12,72 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#include "common/Constants.h"
#include "tests/unittests/validation/ValidationTest.h"
class ComputeValidationTest : public ValidationTest {};
#include "utils/WGPUHelpers.h"
// TODO(cwallez@chromium.org): Add a regression test for Disptach validation trying to acces the
// input state.
class ComputeValidationTest : public ValidationTest {
protected:
void SetUp() override {
ValidationTest::SetUp();
wgpu::ShaderModule computeModule = utils::CreateShaderModule(device, R"(
[[stage(compute), workgroup_size(1)]] fn main() {
})");
// Set up compute pipeline
wgpu::PipelineLayout pl = utils::MakeBasicPipelineLayout(device, nullptr);
wgpu::ComputePipelineDescriptor csDesc;
csDesc.layout = pl;
csDesc.compute.module = computeModule;
csDesc.compute.entryPoint = "main";
pipeline = device.CreateComputePipeline(&csDesc);
}
void TestDispatch(uint32_t x, uint32_t y, uint32_t z) {
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
wgpu::ComputePassEncoder pass = encoder.BeginComputePass();
pass.SetPipeline(pipeline);
pass.Dispatch(x, y, z);
pass.EndPass();
encoder.Finish();
}
wgpu::ComputePipeline pipeline;
};
// Check that 1x1x1 dispatch is OK.
TEST_F(ComputeValidationTest, PerDimensionDispatchSizeLimits_SmallestValid) {
TestDispatch(1, 1, 1);
}
// Check that the largest allowed dispatch is OK.
TEST_F(ComputeValidationTest, PerDimensionDispatchSizeLimits_LargestValid) {
constexpr uint32_t kMax = kMaxComputePerDimensionDispatchSize;
TestDispatch(kMax, kMax, kMax);
}
// Check that exceeding the maximum on the X dimension results in validation failure.
TEST_F(ComputeValidationTest, PerDimensionDispatchSizeLimits_InvalidX) {
ASSERT_DEVICE_ERROR(TestDispatch(kMaxComputePerDimensionDispatchSize + 1, 1, 1));
}
// Check that exceeding the maximum on the Y dimension results in validation failure.
TEST_F(ComputeValidationTest, PerDimensionDispatchSizeLimits_InvalidY) {
ASSERT_DEVICE_ERROR(TestDispatch(1, kMaxComputePerDimensionDispatchSize + 1, 1));
}
// Check that exceeding the maximum on the Z dimension results in validation failure.
TEST_F(ComputeValidationTest, PerDimensionDispatchSizeLimits_InvalidZ) {
ASSERT_DEVICE_ERROR(TestDispatch(1, 1, kMaxComputePerDimensionDispatchSize + 1));
}
// Check that exceeding the maximum on all dimensions results in validation failure.
TEST_F(ComputeValidationTest, PerDimensionDispatchSizeLimits_InvalidAll) {
constexpr uint32_t kMax = kMaxComputePerDimensionDispatchSize;
ASSERT_DEVICE_ERROR(TestDispatch(kMax + 1, kMax + 1, kMax + 1));
}