Implement internal storage for buffer usage and buffer binding type

In the timestamp internal pipeline, the ResolveQuery buffer cannnot be
binded as Storage buffer in binding group layout due to it has not
Storage usage.
Add InternalStorageBuffer for buffer usage and
InternalStorageBufferBinding for buffer binding type, make the
QueryResolve buffer implicitly get InternalStorageBuffer and only
compatible with InternalStorageBufferBinding in BGL, not Storage buffer
binding type.

Bug: dawn:797
Change-Id: I286339e703e26d3786c706ded03f850ca17355fb
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/54400
Reviewed-by: Jiawei Shao <jiawei.shao@intel.com>
Commit-Queue: Hao Li <hao.x.li@intel.com>
This commit is contained in:
Li Hao 2021-06-16 14:33:27 +00:00 committed by Dawn LUCI CQ
parent 46ed96336a
commit b936d23364
21 changed files with 79 additions and 21 deletions

View File

@ -54,6 +54,10 @@ namespace dawn_native {
requiredUsage = wgpu::BufferUsage::Storage; requiredUsage = wgpu::BufferUsage::Storage;
maxBindingSize = std::numeric_limits<uint64_t>::max(); maxBindingSize = std::numeric_limits<uint64_t>::max();
break; break;
case kInternalStorageBufferBinding:
requiredUsage = kInternalStorageBuffer;
maxBindingSize = std::numeric_limits<uint64_t>::max();
break;
case wgpu::BufferBindingType::Undefined: case wgpu::BufferBindingType::Undefined:
UNREACHABLE(); UNREACHABLE();
} }

View File

@ -85,9 +85,15 @@ namespace dawn_native {
if (entry.buffer.type != wgpu::BufferBindingType::Undefined) { if (entry.buffer.type != wgpu::BufferBindingType::Undefined) {
bindingMemberCount++; bindingMemberCount++;
const BufferBindingLayout& buffer = entry.buffer; const BufferBindingLayout& buffer = entry.buffer;
DAWN_TRY(ValidateBufferBindingType(buffer.type));
if (buffer.type == wgpu::BufferBindingType::Storage) { // The kInternalStorageBufferBinding is used internally and not a value
// in wgpu::BufferBindingType.
if (buffer.type != kInternalStorageBufferBinding) {
DAWN_TRY(ValidateBufferBindingType(buffer.type));
}
if (buffer.type == wgpu::BufferBindingType::Storage ||
buffer.type == kInternalStorageBufferBinding) {
allowedStages &= ~wgpu::ShaderStage::Vertex; allowedStages &= ~wgpu::ShaderStage::Vertex;
} }
@ -96,6 +102,7 @@ namespace dawn_native {
if (device->IsToggleEnabled(Toggle::DisallowUnsafeAPIs) && if (device->IsToggleEnabled(Toggle::DisallowUnsafeAPIs) &&
buffer.hasDynamicOffset && buffer.hasDynamicOffset &&
(buffer.type == wgpu::BufferBindingType::Storage || (buffer.type == wgpu::BufferBindingType::Storage ||
buffer.type == kInternalStorageBufferBinding ||
buffer.type == wgpu::BufferBindingType::ReadOnlyStorage)) { buffer.type == wgpu::BufferBindingType::ReadOnlyStorage)) {
return DAWN_VALIDATION_ERROR( return DAWN_VALIDATION_ERROR(
"Dynamic storage buffers are disallowed because they aren't secure yet. " "Dynamic storage buffers are disallowed because they aren't secure yet. "

View File

@ -40,6 +40,7 @@ namespace dawn_native {
break; break;
case wgpu::BufferBindingType::Storage: case wgpu::BufferBindingType::Storage:
case kInternalStorageBufferBinding:
case wgpu::BufferBindingType::ReadOnlyStorage: case wgpu::BufferBindingType::ReadOnlyStorage:
if (buffer.hasDynamicOffset) { if (buffer.hasDynamicOffset) {
++bindingCounts->dynamicStorageBufferCount; ++bindingCounts->dynamicStorageBufferCount;

View File

@ -138,12 +138,11 @@ namespace dawn_native {
mUsage |= kReadOnlyStorageBuffer; mUsage |= kReadOnlyStorageBuffer;
} }
// TODO(crbug.com/dawn/434): This is just a workaround to make QueryResolve buffer pass the // The buffer made with QueryResolve usage implicitly get InternalStorage usage which is
// binding group validation when used as an internal resource. Instead the buffer made with // only compatible with InternalStorageBuffer binding type in BGL, not StorageBuffer binding
// QueryResolve usage would implicitly get StorageInternal usage which is only compatible // type.
// with StorageBufferInternal binding type in BGL, not StorageBuffer binding type.
if (mUsage & wgpu::BufferUsage::QueryResolve) { if (mUsage & wgpu::BufferUsage::QueryResolve) {
mUsage |= wgpu::BufferUsage::Storage; mUsage |= kInternalStorageBuffer;
} }
} }

View File

@ -80,6 +80,9 @@ namespace dawn_native {
case wgpu::BufferBindingType::Storage: case wgpu::BufferBindingType::Storage:
BufferUsedAs(buffer, wgpu::BufferUsage::Storage); BufferUsedAs(buffer, wgpu::BufferUsage::Storage);
break; break;
case kInternalStorageBufferBinding:
BufferUsedAs(buffer, kInternalStorageBuffer);
break;
case wgpu::BufferBindingType::ReadOnlyStorage: case wgpu::BufferBindingType::ReadOnlyStorage:
BufferUsedAs(buffer, kReadOnlyStorageBuffer); BufferUsedAs(buffer, kReadOnlyStorageBuffer);
break; break;

View File

@ -121,10 +121,33 @@ namespace dawn_native {
DAWN_TRY_ASSIGN(store->timestampCS, device->CreateShaderModule(&descriptor)); DAWN_TRY_ASSIGN(store->timestampCS, device->CreateShaderModule(&descriptor));
} }
// Create binding group layout
std::array<BindGroupLayoutEntry, 3> entries = {};
for (uint32_t i = 0; i < entries.size(); i++) {
entries[i].binding = i;
entries[i].visibility = wgpu::ShaderStage::Compute;
}
entries[0].buffer.type = kInternalStorageBufferBinding;
entries[1].buffer.type = wgpu::BufferBindingType::ReadOnlyStorage;
entries[2].buffer.type = wgpu::BufferBindingType::Uniform;
BindGroupLayoutDescriptor bglDesc;
bglDesc.entryCount = static_cast<uint32_t>(entries.size());
bglDesc.entries = entries.data();
Ref<BindGroupLayoutBase> bgl;
DAWN_TRY_ASSIGN(bgl, device->CreateBindGroupLayout(&bglDesc));
// Create pipeline layout
PipelineLayoutDescriptor plDesc;
plDesc.bindGroupLayoutCount = 1;
plDesc.bindGroupLayouts = &bgl.Get();
Ref<PipelineLayoutBase> layout;
DAWN_TRY_ASSIGN(layout, device->CreatePipelineLayout(&plDesc));
// Create ComputePipeline. // Create ComputePipeline.
ComputePipelineDescriptor computePipelineDesc = {}; ComputePipelineDescriptor computePipelineDesc = {};
// Generate the layout based on shader module. // Generate the layout based on shader module.
computePipelineDesc.layout = nullptr; computePipelineDesc.layout = layout.Get();
computePipelineDesc.compute.module = store->timestampCS.Get(); computePipelineDesc.compute.module = store->timestampCS.Get();
computePipelineDesc.compute.entryPoint = "main"; computePipelineDesc.compute.entryPoint = "main";

View File

@ -594,10 +594,14 @@ namespace dawn_native {
// Binding mismatch between shader and bind group is invalid. For example, a // Binding mismatch between shader and bind group is invalid. For example, a
// writable binding in the shader with a readonly storage buffer in the bind // writable binding in the shader with a readonly storage buffer in the bind
// group layout is invalid. However, a readonly binding in the shader with a // group layout is invalid. However, a readonly binding in the shader with a
// writable storage buffer in the bind group layout is valid. // writable storage buffer in the bind group layout is valid, a storage
// binding in the shader with an internal storage buffer in the bind group
// layout is also valid.
bool validBindingConversion = bool validBindingConversion =
layoutInfo.buffer.type == wgpu::BufferBindingType::Storage && (layoutInfo.buffer.type == wgpu::BufferBindingType::Storage &&
shaderInfo.buffer.type == wgpu::BufferBindingType::ReadOnlyStorage; shaderInfo.buffer.type == wgpu::BufferBindingType::ReadOnlyStorage) ||
(layoutInfo.buffer.type == kInternalStorageBufferBinding &&
shaderInfo.buffer.type == wgpu::BufferBindingType::Storage);
if (layoutInfo.buffer.type != shaderInfo.buffer.type && if (layoutInfo.buffer.type != shaderInfo.buffer.type &&
!validBindingConversion) { !validBindingConversion) {

View File

@ -78,7 +78,8 @@ namespace dawn_native { namespace d3d12 {
bindingOffsets[bindingIndex])); bindingOffsets[bindingIndex]));
break; break;
} }
case wgpu::BufferBindingType::Storage: { case wgpu::BufferBindingType::Storage:
case kInternalStorageBufferBinding: {
// Since SPIRV-Cross outputs HLSL shaders with RWByteAddressBuffer, // Since SPIRV-Cross outputs HLSL shaders with RWByteAddressBuffer,
// we must use D3D12_BUFFER_UAV_FLAG_RAW when making the // we must use D3D12_BUFFER_UAV_FLAG_RAW when making the
// UNORDERED_ACCESS_VIEW_DESC. Using D3D12_BUFFER_UAV_FLAG_RAW requires // UNORDERED_ACCESS_VIEW_DESC. Using D3D12_BUFFER_UAV_FLAG_RAW requires

View File

@ -30,6 +30,7 @@ namespace dawn_native { namespace d3d12 {
case wgpu::BufferBindingType::Uniform: case wgpu::BufferBindingType::Uniform:
return BindGroupLayout::DescriptorType::CBV; return BindGroupLayout::DescriptorType::CBV;
case wgpu::BufferBindingType::Storage: case wgpu::BufferBindingType::Storage:
case kInternalStorageBufferBinding:
return BindGroupLayout::DescriptorType::UAV; return BindGroupLayout::DescriptorType::UAV;
case wgpu::BufferBindingType::ReadOnlyStorage: case wgpu::BufferBindingType::ReadOnlyStorage:
return BindGroupLayout::DescriptorType::SRV; return BindGroupLayout::DescriptorType::SRV;

View File

@ -31,7 +31,7 @@ namespace dawn_native { namespace d3d12 {
D3D12_RESOURCE_FLAGS D3D12ResourceFlags(wgpu::BufferUsage usage) { D3D12_RESOURCE_FLAGS D3D12ResourceFlags(wgpu::BufferUsage usage) {
D3D12_RESOURCE_FLAGS flags = D3D12_RESOURCE_FLAG_NONE; D3D12_RESOURCE_FLAGS flags = D3D12_RESOURCE_FLAG_NONE;
if (usage & wgpu::BufferUsage::Storage) { if (usage & (wgpu::BufferUsage::Storage | kInternalStorageBuffer)) {
flags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS; flags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
} }

View File

@ -392,6 +392,7 @@ namespace dawn_native { namespace d3d12 {
} }
break; break;
case wgpu::BufferBindingType::Storage: case wgpu::BufferBindingType::Storage:
case kInternalStorageBufferBinding:
if (mInCompute) { if (mInCompute) {
commandList->SetComputeRootUnorderedAccessView(parameterIndex, commandList->SetComputeRootUnorderedAccessView(parameterIndex,
bufferLocation); bufferLocation);

View File

@ -45,6 +45,7 @@ namespace dawn_native { namespace d3d12 {
case wgpu::BufferBindingType::Uniform: case wgpu::BufferBindingType::Uniform:
return D3D12_ROOT_PARAMETER_TYPE_CBV; return D3D12_ROOT_PARAMETER_TYPE_CBV;
case wgpu::BufferBindingType::Storage: case wgpu::BufferBindingType::Storage:
case kInternalStorageBufferBinding:
return D3D12_ROOT_PARAMETER_TYPE_UAV; return D3D12_ROOT_PARAMETER_TYPE_UAV;
case wgpu::BufferBindingType::ReadOnlyStorage: case wgpu::BufferBindingType::ReadOnlyStorage:
return D3D12_ROOT_PARAMETER_TYPE_SRV; return D3D12_ROOT_PARAMETER_TYPE_SRV;

View File

@ -229,10 +229,13 @@ namespace dawn_native { namespace d3d12 {
// storage buffer in the BGL produces the wrong output. // storage buffer in the BGL produces the wrong output.
// Force read-only storage buffer bindings to be treated as UAV // Force read-only storage buffer bindings to be treated as UAV
// instead of SRV. // instead of SRV.
// Internal storage buffer is a storage buffer used in the internal pipeline.
const bool forceStorageBufferAsUAV = const bool forceStorageBufferAsUAV =
(bindingInfo.buffer.type == wgpu::BufferBindingType::ReadOnlyStorage && (bindingInfo.buffer.type == wgpu::BufferBindingType::ReadOnlyStorage &&
(bgl->GetBindingInfo(bindingIndex).buffer.type ==
wgpu::BufferBindingType::Storage ||
bgl->GetBindingInfo(bindingIndex).buffer.type == bgl->GetBindingInfo(bindingIndex).buffer.type ==
wgpu::BufferBindingType::Storage); kInternalStorageBufferBinding));
if (forceStorageBufferAsUAV) { if (forceStorageBufferAsUAV) {
accessControls.emplace(srcBindingPoint, tint::ast::Access::kReadWrite); accessControls.emplace(srcBindingPoint, tint::ast::Access::kReadWrite);
} }

View File

@ -35,6 +35,13 @@ namespace dawn_native {
// This currently aliases wgpu::TextureUsage::Present, we would assign it // This currently aliases wgpu::TextureUsage::Present, we would assign it
// some bit when wgpu::TextureUsage::Present is removed. // some bit when wgpu::TextureUsage::Present is removed.
static constexpr wgpu::TextureUsage kPresentTextureUsage = wgpu::TextureUsage::Present; static constexpr wgpu::TextureUsage kPresentTextureUsage = wgpu::TextureUsage::Present;
// Add an extra buffer usage and an extra binding type for binding the buffers with QueryResolve
// usage as storage buffer in the internal pipeline.
static constexpr wgpu::BufferUsage kInternalStorageBuffer =
static_cast<wgpu::BufferUsage>(0x40000000);
static constexpr wgpu::BufferBindingType kInternalStorageBufferBinding =
static_cast<wgpu::BufferBindingType>(0xFFFFFFFF);
} // namespace dawn_native } // namespace dawn_native
#endif // DAWNNATIVE_DAWNPLATFORM_H_ #endif // DAWNNATIVE_DAWNPLATFORM_H_

View File

@ -53,7 +53,8 @@ namespace dawn_native { namespace metal {
// Metal validation layer requires the size of uniform buffer and storage buffer to be no // Metal validation layer requires the size of uniform buffer and storage buffer to be no
// less than the size of the buffer block defined in shader, and the overall size of the // less than the size of the buffer block defined in shader, and the overall size of the
// buffer must be aligned to the largest alignment of its members. // buffer must be aligned to the largest alignment of its members.
if (GetUsage() & (wgpu::BufferUsage::Uniform | wgpu::BufferUsage::Storage)) { if (GetUsage() &
(wgpu::BufferUsage::Uniform | wgpu::BufferUsage::Storage | kInternalStorageBuffer)) {
if (currentSize > if (currentSize >
std::numeric_limits<NSUInteger>::max() - kMinUniformOrStorageBufferAlignment) { std::numeric_limits<NSUInteger>::max() - kMinUniformOrStorageBufferAlignment) {
// Alignment would overlow. // Alignment would overlow.

View File

@ -265,6 +265,7 @@ namespace dawn_native { namespace opengl {
target = GL_UNIFORM_BUFFER; target = GL_UNIFORM_BUFFER;
break; break;
case wgpu::BufferBindingType::Storage: case wgpu::BufferBindingType::Storage:
case kInternalStorageBufferBinding:
case wgpu::BufferBindingType::ReadOnlyStorage: case wgpu::BufferBindingType::ReadOnlyStorage:
target = GL_SHADER_STORAGE_BUFFER; target = GL_SHADER_STORAGE_BUFFER;
break; break;

View File

@ -43,6 +43,7 @@ namespace dawn_native { namespace opengl {
uboIndex++; uboIndex++;
break; break;
case wgpu::BufferBindingType::Storage: case wgpu::BufferBindingType::Storage:
case kInternalStorageBufferBinding:
case wgpu::BufferBindingType::ReadOnlyStorage: case wgpu::BufferBindingType::ReadOnlyStorage:
mIndexInfo[group][bindingIndex] = ssboIndex; mIndexInfo[group][bindingIndex] = ssboIndex;
ssboIndex++; ssboIndex++;

View File

@ -56,6 +56,7 @@ namespace dawn_native { namespace vulkan {
} }
return VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; return VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
case wgpu::BufferBindingType::Storage: case wgpu::BufferBindingType::Storage:
case kInternalStorageBufferBinding:
case wgpu::BufferBindingType::ReadOnlyStorage: case wgpu::BufferBindingType::ReadOnlyStorage:
if (bindingInfo.buffer.hasDynamicOffset) { if (bindingInfo.buffer.hasDynamicOffset) {
return VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC; return VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC;

View File

@ -74,7 +74,7 @@ namespace dawn_native { namespace vulkan {
flags |= VK_PIPELINE_STAGE_VERTEX_INPUT_BIT; flags |= VK_PIPELINE_STAGE_VERTEX_INPUT_BIT;
} }
if (usage & (wgpu::BufferUsage::Uniform | wgpu::BufferUsage::Storage | if (usage & (wgpu::BufferUsage::Uniform | wgpu::BufferUsage::Storage |
kReadOnlyStorageBuffer)) { kInternalStorageBuffer | kReadOnlyStorageBuffer)) {
flags |= VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | flags |= VK_PIPELINE_STAGE_VERTEX_SHADER_BIT |
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT; VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
@ -113,7 +113,7 @@ namespace dawn_native { namespace vulkan {
if (usage & wgpu::BufferUsage::Uniform) { if (usage & wgpu::BufferUsage::Uniform) {
flags |= VK_ACCESS_UNIFORM_READ_BIT; flags |= VK_ACCESS_UNIFORM_READ_BIT;
} }
if (usage & wgpu::BufferUsage::Storage) { if (usage & (wgpu::BufferUsage::Storage | kInternalStorageBuffer)) {
flags |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT; flags |= VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
} }
if (usage & kReadOnlyStorageBuffer) { if (usage & kReadOnlyStorageBuffer) {

View File

@ -544,8 +544,7 @@ TEST_F(BindGroupValidationTest, BufferUsageReadonlySSBO) {
} }
// Check that a resolve buffer with internal storge usage cannot be used as SSBO // Check that a resolve buffer with internal storge usage cannot be used as SSBO
// TODO(hao.x.li@intel.com): Disable until internal storage usage is implemented TEST_F(BindGroupValidationTest, BufferUsageQueryResolve) {
TEST_F(BindGroupValidationTest, DISABLED_BufferUsageQueryResolve) {
wgpu::BindGroupLayout layout = utils::MakeBindGroupLayout( wgpu::BindGroupLayout layout = utils::MakeBindGroupLayout(
device, {{0, wgpu::ShaderStage::Fragment, wgpu::BufferBindingType::Storage}}); device, {{0, wgpu::ShaderStage::Fragment, wgpu::BufferBindingType::Storage}});

View File

@ -122,7 +122,7 @@ TEST_P(QueryInternalShaderTests, TimestampComputeShader) {
wgpu::BufferDescriptor timestampsDesc; wgpu::BufferDescriptor timestampsDesc;
timestampsDesc.size = kTimestampCount * sizeof(uint64_t); timestampsDesc.size = kTimestampCount * sizeof(uint64_t);
timestampsDesc.usage = timestampsDesc.usage =
wgpu::BufferUsage::Storage | wgpu::BufferUsage::CopySrc | wgpu::BufferUsage::CopyDst; wgpu::BufferUsage::QueryResolve | wgpu::BufferUsage::CopySrc | wgpu::BufferUsage::CopyDst;
wgpu::Buffer timestampsBuffer = device.CreateBuffer(&timestampsDesc); wgpu::Buffer timestampsBuffer = device.CreateBuffer(&timestampsDesc);
auto PrepareExpectedResults = [&](uint32_t first, uint32_t count, auto PrepareExpectedResults = [&](uint32_t first, uint32_t count,