D3D12/Vulkan: Insert storage buffer barriers between compute pass dipatches

This patch extends the BindGroupTracker in the D3D12 and Vulkan backends to
track bound storage buffers. We insert barriers between dispatches to properly
synchronize writes to storage buffers.

Bug: dawn:236
Change-Id: Iab3f964c345b64755557ab206e05a2ff7b0a3a1f
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/12301
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Commit-Queue: Austin Eng <enga@chromium.org>
This commit is contained in:
Austin Eng
2019-10-22 17:28:20 +00:00
committed by Commit Bot service account
parent 2c8b5c6370
commit 7b3cc35cb6
13 changed files with 611 additions and 68 deletions

View File

@@ -0,0 +1,147 @@
// 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 "tests/unittests/validation/ValidationTest.h"
#include "utils/DawnHelpers.h"
class ComputePassValidationTest : public ValidationTest {};
// Test that it is invalid to use a buffer with both read and write usages in a compute pass.
TEST_F(ComputePassValidationTest, ReadWriteUsage) {
dawn::BufferDescriptor bufferDesc = {};
bufferDesc.usage = dawn::BufferUsage::Storage | dawn::BufferUsage::Uniform;
bufferDesc.size = 4;
dawn::Buffer buffer = device.CreateBuffer(&bufferDesc);
dawn::ShaderModule module =
utils::CreateShaderModule(device, utils::SingleShaderStage::Compute, R"(
#version 450
layout(std430, set = 0, binding = 0) buffer BufA { uint bufA; };
layout(std140, set = 0, binding = 1) uniform BufB { uint bufB; };
void main() {}
)");
dawn::BindGroupLayout bgl = utils::MakeBindGroupLayout(
device, {{0, dawn::ShaderStage::Compute, dawn::BindingType::StorageBuffer},
{1, dawn::ShaderStage::Compute, dawn::BindingType::UniformBuffer}});
dawn::BindGroup bindGroup = utils::MakeBindGroup(device, bgl,
{
{0, buffer, 0, 4},
{1, buffer, 0, 4},
});
dawn::PipelineLayout layout = utils::MakeBasicPipelineLayout(device, &bgl);
dawn::ComputePipelineDescriptor pipelineDesc = {};
pipelineDesc.layout = layout;
pipelineDesc.computeStage.module = module;
pipelineDesc.computeStage.entryPoint = "main";
dawn::ComputePipeline pipeline = device.CreateComputePipeline(&pipelineDesc);
dawn::CommandEncoder encoder = device.CreateCommandEncoder();
dawn::ComputePassEncoder pass = encoder.BeginComputePass();
pass.SetPipeline(pipeline);
pass.SetBindGroup(0, bindGroup);
pass.Dispatch(1, 1, 1);
pass.Dispatch(1, 1, 1);
pass.EndPass();
ASSERT_DEVICE_ERROR(encoder.Finish());
}
// Test that it is valid to use a buffer with a single write usage multiple times in a compute pass.
TEST_F(ComputePassValidationTest, MultipleWrites) {
dawn::BufferDescriptor bufferDesc = {};
bufferDesc.usage = dawn::BufferUsage::Storage;
bufferDesc.size = 4;
dawn::Buffer buffer = device.CreateBuffer(&bufferDesc);
dawn::ShaderModule module =
utils::CreateShaderModule(device, utils::SingleShaderStage::Compute, R"(
#version 450
layout(std430, set = 0, binding = 0) buffer Buf { uint buf; };
void main() {}
)");
dawn::BindGroupLayout bgl = utils::MakeBindGroupLayout(
device, {{0, dawn::ShaderStage::Compute, dawn::BindingType::StorageBuffer}});
dawn::BindGroup bindGroup = utils::MakeBindGroup(device, bgl, {{0, buffer, 0, 4}});
dawn::PipelineLayout layout = utils::MakeBasicPipelineLayout(device, &bgl);
dawn::ComputePipelineDescriptor pipelineDesc = {};
pipelineDesc.layout = layout;
pipelineDesc.computeStage.module = module;
pipelineDesc.computeStage.entryPoint = "main";
dawn::ComputePipeline pipeline = device.CreateComputePipeline(&pipelineDesc);
dawn::CommandEncoder encoder = device.CreateCommandEncoder();
dawn::ComputePassEncoder pass = encoder.BeginComputePass();
pass.SetPipeline(pipeline);
pass.SetBindGroup(0, bindGroup);
pass.Dispatch(1, 1, 1);
pass.Dispatch(1, 1, 1);
pass.EndPass();
encoder.Finish();
}
// Test that it is valid to use a buffer with a single write usage multiple times in a compute pass,
// even if the buffer is referenced in separate bind groups.
TEST_F(ComputePassValidationTest, MultipleWritesSeparateBindGroups) {
dawn::BufferDescriptor bufferDesc = {};
bufferDesc.usage = dawn::BufferUsage::Storage;
bufferDesc.size = 4;
dawn::Buffer buffer = device.CreateBuffer(&bufferDesc);
dawn::ShaderModule module =
utils::CreateShaderModule(device, utils::SingleShaderStage::Compute, R"(
#version 450
#define kNumValues 100
layout(std430, set = 0, binding = 0) buffer Buf { uint buf; };
void main() {}
)");
dawn::BindGroupLayout bgl = utils::MakeBindGroupLayout(
device, {{0, dawn::ShaderStage::Compute, dawn::BindingType::StorageBuffer}});
dawn::BindGroup bindGroupA = utils::MakeBindGroup(device, bgl, {{0, buffer, 0, 4}});
dawn::BindGroup bindGroupB = utils::MakeBindGroup(device, bgl, {{0, buffer, 0, 4}});
dawn::PipelineLayout layout = utils::MakeBasicPipelineLayout(device, &bgl);
dawn::ComputePipelineDescriptor pipelineDesc = {};
pipelineDesc.layout = layout;
pipelineDesc.computeStage.module = module;
pipelineDesc.computeStage.entryPoint = "main";
dawn::ComputePipeline pipeline = device.CreateComputePipeline(&pipelineDesc);
dawn::CommandEncoder encoder = device.CreateCommandEncoder();
dawn::ComputePassEncoder pass = encoder.BeginComputePass();
pass.SetPipeline(pipeline);
pass.SetBindGroup(0, bindGroupA);
pass.Dispatch(1, 1, 1);
pass.SetBindGroup(0, bindGroupB);
pass.Dispatch(1, 1, 1);
pass.EndPass();
encoder.Finish();
}