mirror of
https://github.com/encounter/dawn-cmake.git
synced 2025-12-16 08:27:05 +00:00
dawn_native: Indirect draw/dispatch
Adds indirect draw and dispatch for all backends (without validation). Tests for opengl negative offset are skipped since there is no easy way to add the index buffer offset. Current idea is to use a compute shader to modify the indirect draw buffer. Change-Id: I1d3eec7c699b211423f4b911769cca17bfbcd045 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/7481 Commit-Queue: Idan Raiter <idanr@google.com> Reviewed-by: Kai Ninomiya <kainino@chromium.org>
This commit is contained in:
committed by
Commit Bot service account
parent
de1ac9fd7b
commit
7eb6be186b
@@ -0,0 +1,90 @@
|
||||
// Copyright 2019 The Dawn Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <initializer_list>
|
||||
#include <limits>
|
||||
#include "tests/unittests/validation/ValidationTest.h"
|
||||
#include "utils/DawnHelpers.h"
|
||||
|
||||
class ComputeIndirectValidationTest : public ValidationTest {
|
||||
protected:
|
||||
void SetUp() override {
|
||||
ValidationTest::SetUp();
|
||||
|
||||
dawn::ShaderModule computeModule =
|
||||
utils::CreateShaderModule(device, dawn::ShaderStage::Compute, R"(
|
||||
#version 450
|
||||
layout(local_size_x = 1) in;
|
||||
void main() {
|
||||
})");
|
||||
|
||||
// Set up compute pipeline
|
||||
dawn::PipelineLayout pl = utils::MakeBasicPipelineLayout(device, nullptr);
|
||||
|
||||
dawn::ComputePipelineDescriptor csDesc;
|
||||
csDesc.layout = pl;
|
||||
|
||||
dawn::PipelineStageDescriptor computeStage;
|
||||
computeStage.module = computeModule;
|
||||
computeStage.entryPoint = "main";
|
||||
csDesc.computeStage = &computeStage;
|
||||
|
||||
pipeline = device.CreateComputePipeline(&csDesc);
|
||||
}
|
||||
|
||||
void ValidateExpectation(dawn::CommandEncoder encoder, utils::Expectation expectation) {
|
||||
if (expectation == utils::Expectation::Success) {
|
||||
encoder.Finish();
|
||||
} else {
|
||||
ASSERT_DEVICE_ERROR(encoder.Finish());
|
||||
}
|
||||
}
|
||||
|
||||
void TestIndirectOffset(utils::Expectation expectation,
|
||||
std::initializer_list<uint32_t> bufferList,
|
||||
uint64_t indirectOffset) {
|
||||
dawn::Buffer indirectBuffer = utils::CreateBufferFromData<uint32_t>(
|
||||
device, dawn::BufferUsageBit::Indirect, bufferList);
|
||||
|
||||
dawn::CommandEncoder encoder = device.CreateCommandEncoder();
|
||||
dawn::ComputePassEncoder pass = encoder.BeginComputePass();
|
||||
pass.SetPipeline(pipeline);
|
||||
pass.DispatchIndirect(indirectBuffer, indirectOffset);
|
||||
pass.EndPass();
|
||||
|
||||
ValidateExpectation(encoder, expectation);
|
||||
}
|
||||
|
||||
dawn::ComputePipeline pipeline;
|
||||
};
|
||||
|
||||
// Verify out of bounds indirect dispatch calls are caught early
|
||||
TEST_F(ComputeIndirectValidationTest, IndirectOffsetBounds) {
|
||||
// In bounds
|
||||
TestIndirectOffset(utils::Expectation::Success, {1, 2, 3}, 0);
|
||||
// In bounds, bigger buffer
|
||||
TestIndirectOffset(utils::Expectation::Success, {1, 2, 3, 4, 5, 6}, 0);
|
||||
// In bounds, bigger buffer, positive offset
|
||||
TestIndirectOffset(utils::Expectation::Success, {1, 2, 3, 4, 5, 6}, 3 * sizeof(uint32_t));
|
||||
|
||||
// Out of bounds, buffer too small
|
||||
TestIndirectOffset(utils::Expectation::Failure, {1, 2}, 0);
|
||||
// Out of bounds, index too big
|
||||
TestIndirectOffset(utils::Expectation::Failure, {1, 2, 3}, 1 * sizeof(uint32_t));
|
||||
// Out of bounds, index past buffer
|
||||
TestIndirectOffset(utils::Expectation::Failure, {1, 2, 3}, 4 * sizeof(uint32_t));
|
||||
// Out of bounds, index + size of command overflows
|
||||
uint64_t offset = std::numeric_limits<uint64_t>::max();
|
||||
TestIndirectOffset(utils::Expectation::Failure, {1, 2, 3, 4, 5, 6}, offset);
|
||||
}
|
||||
143
src/tests/unittests/validation/DrawIndirectValidationTests.cpp
Normal file
143
src/tests/unittests/validation/DrawIndirectValidationTests.cpp
Normal file
@@ -0,0 +1,143 @@
|
||||
// Copyright 2019 The Dawn Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <initializer_list>
|
||||
#include <limits>
|
||||
#include "tests/unittests/validation/ValidationTest.h"
|
||||
#include "utils/ComboRenderPipelineDescriptor.h"
|
||||
#include "utils/DawnHelpers.h"
|
||||
|
||||
class DrawIndirectValidationTest : public ValidationTest {
|
||||
protected:
|
||||
void SetUp() override {
|
||||
ValidationTest::SetUp();
|
||||
|
||||
dawn::ShaderModule vsModule =
|
||||
utils::CreateShaderModule(device, dawn::ShaderStage::Vertex, R"(
|
||||
#version 450
|
||||
void main() {
|
||||
gl_Position = vec4(0.0);
|
||||
})");
|
||||
|
||||
dawn::ShaderModule fsModule =
|
||||
utils::CreateShaderModule(device, dawn::ShaderStage::Fragment, R"(
|
||||
#version 450
|
||||
layout(location = 0) out vec4 fragColor;
|
||||
void main() {
|
||||
fragColor = vec4(0.0);
|
||||
})");
|
||||
|
||||
// Set up render pipeline
|
||||
dawn::PipelineLayout pipelineLayout = utils::MakeBasicPipelineLayout(device, nullptr);
|
||||
|
||||
utils::ComboRenderPipelineDescriptor descriptor(device);
|
||||
descriptor.layout = pipelineLayout;
|
||||
descriptor.cVertexStage.module = vsModule;
|
||||
descriptor.cFragmentStage.module = fsModule;
|
||||
|
||||
pipeline = device.CreateRenderPipeline(&descriptor);
|
||||
}
|
||||
|
||||
void ValidateExpectation(dawn::CommandEncoder encoder, utils::Expectation expectation) {
|
||||
if (expectation == utils::Expectation::Success) {
|
||||
encoder.Finish();
|
||||
} else {
|
||||
ASSERT_DEVICE_ERROR(encoder.Finish());
|
||||
}
|
||||
}
|
||||
|
||||
void TestIndirectOffsetDrawIndexed(utils::Expectation expectation,
|
||||
std::initializer_list<uint32_t> bufferList,
|
||||
uint64_t indirectOffset) {
|
||||
TestIndirectOffset(expectation, bufferList, indirectOffset, true);
|
||||
}
|
||||
|
||||
void TestIndirectOffsetDraw(utils::Expectation expectation,
|
||||
std::initializer_list<uint32_t> bufferList,
|
||||
uint64_t indirectOffset) {
|
||||
TestIndirectOffset(expectation, bufferList, indirectOffset, false);
|
||||
}
|
||||
|
||||
void TestIndirectOffset(utils::Expectation expectation,
|
||||
std::initializer_list<uint32_t> bufferList,
|
||||
uint64_t indirectOffset,
|
||||
bool indexed) {
|
||||
dawn::Buffer indirectBuffer = utils::CreateBufferFromData<uint32_t>(
|
||||
device, dawn::BufferUsageBit::Indirect, bufferList);
|
||||
|
||||
DummyRenderPass renderPass(device);
|
||||
dawn::CommandEncoder encoder = device.CreateCommandEncoder();
|
||||
dawn::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass);
|
||||
pass.SetPipeline(pipeline);
|
||||
if (indexed) {
|
||||
uint32_t zeros[100] = {};
|
||||
dawn::Buffer indexBuffer = utils::CreateBufferFromData(device, zeros, sizeof(zeros),
|
||||
dawn::BufferUsageBit::Index);
|
||||
pass.SetIndexBuffer(indexBuffer, 0);
|
||||
pass.DrawIndexedIndirect(indirectBuffer, indirectOffset);
|
||||
} else {
|
||||
pass.DrawIndirect(indirectBuffer, indirectOffset);
|
||||
}
|
||||
pass.EndPass();
|
||||
|
||||
ValidateExpectation(encoder, expectation);
|
||||
}
|
||||
|
||||
dawn::RenderPipeline pipeline;
|
||||
};
|
||||
|
||||
// Verify out of bounds indirect draw calls are caught early
|
||||
TEST_F(DrawIndirectValidationTest, DrawIndirectOffsetBounds) {
|
||||
// In bounds
|
||||
TestIndirectOffsetDraw(utils::Expectation::Success, {1, 2, 3, 4}, 0);
|
||||
// In bounds, bigger buffer
|
||||
TestIndirectOffsetDraw(utils::Expectation::Success, {1, 2, 3, 4, 5, 6, 7}, 0);
|
||||
// In bounds, bigger buffer, positive offset
|
||||
TestIndirectOffsetDraw(utils::Expectation::Success, {1, 2, 3, 4, 5, 6, 7, 8},
|
||||
4 * sizeof(uint32_t));
|
||||
|
||||
// Out of bounds, buffer too small
|
||||
TestIndirectOffsetDraw(utils::Expectation::Failure, {1, 2, 3}, 0);
|
||||
// Out of bounds, index too big
|
||||
TestIndirectOffsetDraw(utils::Expectation::Failure, {1, 2, 3, 4}, 1 * sizeof(uint32_t));
|
||||
// Out of bounds, index past buffer
|
||||
TestIndirectOffsetDraw(utils::Expectation::Failure, {1, 2, 3, 4}, 5 * sizeof(uint32_t));
|
||||
// Out of bounds, index + size of command overflows
|
||||
uint64_t offset = std::numeric_limits<uint64_t>::max();
|
||||
TestIndirectOffsetDraw(utils::Expectation::Failure, {1, 2, 3, 4, 5, 6, 7}, offset);
|
||||
}
|
||||
|
||||
// Verify out of bounds indirect draw indexed calls are caught early
|
||||
TEST_F(DrawIndirectValidationTest, DrawIndexedIndirectOffsetBounds) {
|
||||
// In bounds
|
||||
TestIndirectOffsetDrawIndexed(utils::Expectation::Success, {1, 2, 3, 4, 5}, 0);
|
||||
// In bounds, bigger buffer
|
||||
TestIndirectOffsetDrawIndexed(utils::Expectation::Success, {1, 2, 3, 4, 5, 6, 7, 8, 9}, 0);
|
||||
// In bounds, bigger buffer, positive offset
|
||||
TestIndirectOffsetDrawIndexed(utils::Expectation::Success, {1, 2, 3, 4, 5, 6, 7, 8, 9, 10},
|
||||
5 * sizeof(uint32_t));
|
||||
|
||||
// Out of bounds, buffer too small
|
||||
TestIndirectOffsetDrawIndexed(utils::Expectation::Failure, {1, 2, 3, 4}, 0);
|
||||
// Out of bounds, index too big
|
||||
TestIndirectOffsetDrawIndexed(utils::Expectation::Failure, {1, 2, 3, 4, 5},
|
||||
1 * sizeof(uint32_t));
|
||||
// Out of bounds, index past buffer
|
||||
TestIndirectOffsetDrawIndexed(utils::Expectation::Failure, {1, 2, 3, 4, 5},
|
||||
5 * sizeof(uint32_t));
|
||||
// Out of bounds, index + size of command overflows
|
||||
uint64_t offset = std::numeric_limits<uint64_t>::max();
|
||||
TestIndirectOffsetDrawIndexed(utils::Expectation::Failure, {1, 2, 3, 4, 5, 6, 7, 8, 9, 10},
|
||||
offset);
|
||||
}
|
||||
Reference in New Issue
Block a user