Update BindingInfo to reflect new BindGroupLayoutEntry structure

Changes the internal BindingInfo structure and any references to it. The
BindGroupLayoutEntry information is normalized when converting it into
the internal representation, but still accepted as either the old or
new layout. A "bindingType" member is added to the BindingInfo that's
not present in the BindGroupLayoutEntry itself to indicate which of
buffer, sampler, texture, or storageTexture is populated. This proves
useful for a myriad of switch statements in the various backends.

Bug: dawn:527
Change-Id: I6ae65adae61d0005fc50ed6d1bc2ec9b2a1295ad
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/35862
Commit-Queue: Austin Eng <enga@chromium.org>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Reviewed-by: Austin Eng <enga@chromium.org>
Auto-Submit: Brandon Jones <bajones@chromium.org>
This commit is contained in:
Brandon Jones 2020-12-21 20:14:26 +00:00 committed by Commit Bot service account
parent ec56b90cea
commit 3af532b8a8
29 changed files with 812 additions and 778 deletions

View File

@ -31,15 +31,31 @@ namespace dawn_native {
MaybeError ValidateBufferBinding(const DeviceBase* device, MaybeError ValidateBufferBinding(const DeviceBase* device,
const BindGroupEntry& entry, const BindGroupEntry& entry,
wgpu::BufferUsage requiredUsage, const BindingInfo& bindingInfo) {
const BindingInfo& bindingInfo,
const uint64_t maxBindingSize) {
if (entry.buffer == nullptr || entry.sampler != nullptr || if (entry.buffer == nullptr || entry.sampler != nullptr ||
entry.textureView != nullptr) { entry.textureView != nullptr) {
return DAWN_VALIDATION_ERROR("Expected buffer binding"); return DAWN_VALIDATION_ERROR("Expected buffer binding");
} }
DAWN_TRY(device->ValidateObject(entry.buffer)); DAWN_TRY(device->ValidateObject(entry.buffer));
ASSERT(bindingInfo.bindingType == BindingInfoType::Buffer);
wgpu::BufferUsage requiredUsage;
uint64_t maxBindingSize;
switch (bindingInfo.buffer.type) {
case wgpu::BufferBindingType::Uniform:
requiredUsage = wgpu::BufferUsage::Uniform;
maxBindingSize = kMaxUniformBufferBindingSize;
break;
case wgpu::BufferBindingType::Storage:
case wgpu::BufferBindingType::ReadOnlyStorage:
requiredUsage = wgpu::BufferUsage::Storage;
maxBindingSize = std::numeric_limits<uint64_t>::max();
break;
case wgpu::BufferBindingType::Undefined:
UNREACHABLE();
}
uint64_t bufferSize = entry.buffer->GetSize(); uint64_t bufferSize = entry.buffer->GetSize();
// Handle wgpu::WholeSize, avoiding overflows. // Handle wgpu::WholeSize, avoiding overflows.
@ -72,11 +88,11 @@ namespace dawn_native {
return DAWN_VALIDATION_ERROR("buffer binding usage mismatch"); return DAWN_VALIDATION_ERROR("buffer binding usage mismatch");
} }
if (bindingSize < bindingInfo.minBufferBindingSize) { if (bindingSize < bindingInfo.buffer.minBindingSize) {
return DAWN_VALIDATION_ERROR( return DAWN_VALIDATION_ERROR(
"Binding size smaller than minimum buffer size: binding " + "Binding size smaller than minimum buffer size: binding " +
std::to_string(entry.binding) + " given " + std::to_string(bindingSize) + std::to_string(entry.binding) + " given " + std::to_string(bindingSize) +
" bytes, required " + std::to_string(bindingInfo.minBufferBindingSize) + " bytes, required " + std::to_string(bindingInfo.buffer.minBindingSize) +
" bytes"); " bytes");
} }
@ -93,8 +109,6 @@ namespace dawn_native {
MaybeError ValidateTextureBinding(const DeviceBase* device, MaybeError ValidateTextureBinding(const DeviceBase* device,
const BindGroupEntry& entry, const BindGroupEntry& entry,
wgpu::TextureUsage requiredUsage,
bool multisampled,
const BindingInfo& bindingInfo) { const BindingInfo& bindingInfo) {
if (entry.textureView == nullptr || entry.sampler != nullptr || if (entry.textureView == nullptr || entry.sampler != nullptr ||
entry.buffer != nullptr) { entry.buffer != nullptr) {
@ -110,30 +124,44 @@ namespace dawn_native {
} }
TextureBase* texture = view->GetTexture(); TextureBase* texture = view->GetTexture();
if (!(texture->GetUsage() & requiredUsage)) { switch (bindingInfo.bindingType) {
return DAWN_VALIDATION_ERROR("Texture binding usage mismatch"); case BindingInfoType::Texture: {
}
if (texture->IsMultisampledTexture() != multisampled) {
return DAWN_VALIDATION_ERROR("Texture multisampling mismatch");
}
switch (requiredUsage) {
case wgpu::TextureUsage::Sampled: {
ComponentTypeBit supportedTypes = ComponentTypeBit supportedTypes =
texture->GetFormat().GetAspectInfo(aspect).supportedComponentTypes; texture->GetFormat().GetAspectInfo(aspect).supportedComponentTypes;
ComponentTypeBit requiredType = ComponentTypeBit requiredType =
ToComponentTypeBit(bindingInfo.textureComponentType); SampleTypeToComponentTypeBit(bindingInfo.texture.sampleType);
if (!(texture->GetUsage() & wgpu::TextureUsage::Sampled)) {
return DAWN_VALIDATION_ERROR("Texture binding usage mismatch");
}
if (texture->IsMultisampledTexture() != bindingInfo.texture.multisampled) {
return DAWN_VALIDATION_ERROR("Texture multisampling mismatch");
}
if ((supportedTypes & requiredType) == 0) { if ((supportedTypes & requiredType) == 0) {
return DAWN_VALIDATION_ERROR("Texture component type usage mismatch"); return DAWN_VALIDATION_ERROR("Texture component type usage mismatch");
} }
if (entry.textureView->GetDimension() != bindingInfo.texture.viewDimension) {
return DAWN_VALIDATION_ERROR("Texture view dimension mismatch");
}
break; break;
} }
case wgpu::TextureUsage::Storage: { case BindingInfoType::StorageTexture: {
if (texture->GetFormat().format != bindingInfo.storageTextureFormat) { ASSERT(!texture->IsMultisampledTexture());
if (!(texture->GetUsage() & wgpu::TextureUsage::Storage)) {
return DAWN_VALIDATION_ERROR("Storage Texture binding usage mismatch");
}
if (texture->GetFormat().format != bindingInfo.storageTexture.format) {
return DAWN_VALIDATION_ERROR("Storage texture format mismatch"); return DAWN_VALIDATION_ERROR("Storage texture format mismatch");
} }
if (entry.textureView->GetDimension() !=
bindingInfo.storageTexture.viewDimension) {
return DAWN_VALIDATION_ERROR("Storage texture view dimension mismatch");
}
break; break;
} }
default: default:
@ -141,29 +169,28 @@ namespace dawn_native {
break; break;
} }
if (entry.textureView->GetDimension() != bindingInfo.viewDimension) {
return DAWN_VALIDATION_ERROR("Texture view dimension mismatch");
}
return {}; return {};
} }
MaybeError ValidateSamplerBinding(const DeviceBase* device, MaybeError ValidateSamplerBinding(const DeviceBase* device,
const BindGroupEntry& entry, const BindGroupEntry& entry,
wgpu::BindingType bindingType) { const BindingInfo& bindingInfo) {
if (entry.sampler == nullptr || entry.textureView != nullptr || if (entry.sampler == nullptr || entry.textureView != nullptr ||
entry.buffer != nullptr) { entry.buffer != nullptr) {
return DAWN_VALIDATION_ERROR("Expected sampler binding"); return DAWN_VALIDATION_ERROR("Expected sampler binding");
} }
DAWN_TRY(device->ValidateObject(entry.sampler)); DAWN_TRY(device->ValidateObject(entry.sampler));
switch (bindingType) { ASSERT(bindingInfo.bindingType == BindingInfoType::Sampler);
case wgpu::BindingType::Sampler:
switch (bindingInfo.sampler.type) {
case wgpu::SamplerBindingType::Filtering:
case wgpu::SamplerBindingType::NonFiltering:
if (entry.sampler->HasCompareFunction()) { if (entry.sampler->HasCompareFunction()) {
return DAWN_VALIDATION_ERROR("Did not expect comparison sampler"); return DAWN_VALIDATION_ERROR("Did not expect comparison sampler");
} }
break; break;
case wgpu::BindingType::ComparisonSampler: case wgpu::SamplerBindingType::Comparison:
if (!entry.sampler->HasCompareFunction()) { if (!entry.sampler->HasCompareFunction()) {
return DAWN_VALIDATION_ERROR("Expected comparison sampler"); return DAWN_VALIDATION_ERROR("Expected comparison sampler");
} }
@ -212,36 +239,16 @@ namespace dawn_native {
const BindingInfo& bindingInfo = descriptor->layout->GetBindingInfo(bindingIndex); const BindingInfo& bindingInfo = descriptor->layout->GetBindingInfo(bindingIndex);
// Perform binding-type specific validation. // Perform binding-type specific validation.
switch (bindingInfo.type) { switch (bindingInfo.bindingType) {
case wgpu::BindingType::UniformBuffer: case BindingInfoType::Buffer:
DAWN_TRY(ValidateBufferBinding(device, entry, wgpu::BufferUsage::Uniform, DAWN_TRY(ValidateBufferBinding(device, entry, bindingInfo));
bindingInfo, kMaxUniformBufferBindingSize));
break; break;
case wgpu::BindingType::StorageBuffer: case BindingInfoType::Texture:
case wgpu::BindingType::ReadonlyStorageBuffer: case BindingInfoType::StorageTexture:
DAWN_TRY(ValidateBufferBinding(device, entry, wgpu::BufferUsage::Storage, DAWN_TRY(ValidateTextureBinding(device, entry, bindingInfo));
bindingInfo,
std::numeric_limits<uint64_t>::max()));
break; break;
case wgpu::BindingType::SampledTexture: case BindingInfoType::Sampler:
DAWN_TRY(ValidateTextureBinding(device, entry, wgpu::TextureUsage::Sampled, DAWN_TRY(ValidateSamplerBinding(device, entry, bindingInfo));
false, bindingInfo));
break;
case wgpu::BindingType::MultisampledTexture:
DAWN_TRY(ValidateTextureBinding(device, entry, wgpu::TextureUsage::Sampled,
true, bindingInfo));
break;
case wgpu::BindingType::Sampler:
case wgpu::BindingType::ComparisonSampler:
DAWN_TRY(ValidateSamplerBinding(device, entry, bindingInfo.type));
break;
case wgpu::BindingType::ReadonlyStorageTexture:
case wgpu::BindingType::WriteonlyStorageTexture:
DAWN_TRY(ValidateTextureBinding(device, entry, wgpu::TextureUsage::Storage,
false, bindingInfo));
break;
case wgpu::BindingType::Undefined:
UNREACHABLE();
break; break;
} }
} }
@ -307,7 +314,7 @@ namespace dawn_native {
uint32_t packedIdx = 0; uint32_t packedIdx = 0;
for (BindingIndex bindingIndex{0}; bindingIndex < descriptor->layout->GetBufferCount(); for (BindingIndex bindingIndex{0}; bindingIndex < descriptor->layout->GetBufferCount();
++bindingIndex) { ++bindingIndex) {
if (descriptor->layout->GetBindingInfo(bindingIndex).minBufferBindingSize == 0) { if (descriptor->layout->GetBindingInfo(bindingIndex).buffer.minBindingSize == 0) {
mBindingData.unverifiedBufferSizes[packedIdx] = mBindingData.unverifiedBufferSizes[packedIdx] =
mBindingData.bufferData[bindingIndex].size; mBindingData.bufferData[bindingIndex].size;
++packedIdx; ++packedIdx;
@ -359,10 +366,7 @@ namespace dawn_native {
BufferBinding BindGroupBase::GetBindingAsBufferBinding(BindingIndex bindingIndex) { BufferBinding BindGroupBase::GetBindingAsBufferBinding(BindingIndex bindingIndex) {
ASSERT(!IsError()); ASSERT(!IsError());
ASSERT(bindingIndex < mLayout->GetBindingCount()); ASSERT(bindingIndex < mLayout->GetBindingCount());
ASSERT(mLayout->GetBindingInfo(bindingIndex).type == wgpu::BindingType::UniformBuffer || ASSERT(mLayout->GetBindingInfo(bindingIndex).bindingType == BindingInfoType::Buffer);
mLayout->GetBindingInfo(bindingIndex).type == wgpu::BindingType::StorageBuffer ||
mLayout->GetBindingInfo(bindingIndex).type ==
wgpu::BindingType::ReadonlyStorageBuffer);
BufferBase* buffer = static_cast<BufferBase*>(mBindingData.bindings[bindingIndex].Get()); BufferBase* buffer = static_cast<BufferBase*>(mBindingData.bindings[bindingIndex].Get());
return {buffer, mBindingData.bufferData[bindingIndex].offset, return {buffer, mBindingData.bufferData[bindingIndex].offset,
mBindingData.bufferData[bindingIndex].size}; mBindingData.bufferData[bindingIndex].size};
@ -371,21 +375,16 @@ namespace dawn_native {
SamplerBase* BindGroupBase::GetBindingAsSampler(BindingIndex bindingIndex) const { SamplerBase* BindGroupBase::GetBindingAsSampler(BindingIndex bindingIndex) const {
ASSERT(!IsError()); ASSERT(!IsError());
ASSERT(bindingIndex < mLayout->GetBindingCount()); ASSERT(bindingIndex < mLayout->GetBindingCount());
ASSERT(mLayout->GetBindingInfo(bindingIndex).type == wgpu::BindingType::Sampler || ASSERT(mLayout->GetBindingInfo(bindingIndex).bindingType == BindingInfoType::Sampler);
mLayout->GetBindingInfo(bindingIndex).type == wgpu::BindingType::ComparisonSampler);
return static_cast<SamplerBase*>(mBindingData.bindings[bindingIndex].Get()); return static_cast<SamplerBase*>(mBindingData.bindings[bindingIndex].Get());
} }
TextureViewBase* BindGroupBase::GetBindingAsTextureView(BindingIndex bindingIndex) { TextureViewBase* BindGroupBase::GetBindingAsTextureView(BindingIndex bindingIndex) {
ASSERT(!IsError()); ASSERT(!IsError());
ASSERT(bindingIndex < mLayout->GetBindingCount()); ASSERT(bindingIndex < mLayout->GetBindingCount());
ASSERT(mLayout->GetBindingInfo(bindingIndex).type == wgpu::BindingType::SampledTexture || ASSERT(mLayout->GetBindingInfo(bindingIndex).bindingType == BindingInfoType::Texture ||
mLayout->GetBindingInfo(bindingIndex).type == mLayout->GetBindingInfo(bindingIndex).bindingType ==
wgpu::BindingType::MultisampledTexture || BindingInfoType::StorageTexture);
mLayout->GetBindingInfo(bindingIndex).type ==
wgpu::BindingType::ReadonlyStorageTexture ||
mLayout->GetBindingInfo(bindingIndex).type ==
wgpu::BindingType::WriteonlyStorageTexture);
return static_cast<TextureViewBase*>(mBindingData.bindings[bindingIndex].Get()); return static_cast<TextureViewBase*>(mBindingData.bindings[bindingIndex].Get());
} }

View File

@ -248,17 +248,43 @@ namespace dawn_native {
bool operator!=(const BindingInfo& a, const BindingInfo& b) { bool operator!=(const BindingInfo& a, const BindingInfo& b) {
return a.hasDynamicOffset != b.hasDynamicOffset || // if (a.visibility != b.visibility || a.bindingType != b.bindingType) {
a.visibility != b.visibility || // return true;
a.type != b.type || //
a.textureComponentType != b.textureComponentType || //
a.viewDimension != b.viewDimension || //
a.storageTextureFormat != b.storageTextureFormat || //
a.minBufferBindingSize != b.minBufferBindingSize;
} }
bool IsBufferBindingType(wgpu::BindingType type) { switch (a.bindingType) {
switch (type) { case BindingInfoType::Buffer:
return a.buffer.type != b.buffer.type ||
a.buffer.hasDynamicOffset != b.buffer.hasDynamicOffset ||
a.buffer.minBindingSize != b.buffer.minBindingSize;
case BindingInfoType::Sampler:
return a.sampler.type != b.sampler.type;
case BindingInfoType::Texture:
return a.texture.sampleType != b.texture.sampleType ||
a.texture.viewDimension != b.texture.viewDimension ||
a.texture.multisampled != b.texture.multisampled;
case BindingInfoType::StorageTexture:
return a.storageTexture.access != b.storageTexture.access ||
a.storageTexture.viewDimension != b.storageTexture.viewDimension ||
a.storageTexture.format != b.storageTexture.format;
}
}
// TODO(dawn:527): Once the deprecated BindGroupLayoutEntry path has been removed, this can
// turn into a simple `binding.buffer.type != wgpu::BufferBindingType::Undefined` check.
bool IsBufferBinding(const BindGroupLayoutEntry& binding) {
if (binding.buffer.type != wgpu::BufferBindingType::Undefined) {
return true;
} else if (binding.sampler.type != wgpu::SamplerBindingType::Undefined) {
return false;
} else if (binding.texture.sampleType != wgpu::TextureSampleType::Undefined) {
return false;
} else if (binding.storageTexture.access != wgpu::StorageTextureAccess::Undefined) {
return false;
}
// Deprecated path
switch (binding.type) {
case wgpu::BindingType::UniformBuffer: case wgpu::BindingType::UniformBuffer:
case wgpu::BindingType::StorageBuffer: case wgpu::BindingType::StorageBuffer:
case wgpu::BindingType::ReadonlyStorageBuffer: case wgpu::BindingType::ReadonlyStorageBuffer:
@ -274,20 +300,6 @@ namespace dawn_native {
} }
} }
bool IsBufferBinding(const BindGroupLayoutEntry& binding) {
if (binding.buffer.type != wgpu::BufferBindingType::Undefined) {
return true;
} else if (binding.sampler.type != wgpu::SamplerBindingType::Undefined) {
return false;
} else if (binding.texture.sampleType != wgpu::TextureSampleType::Undefined) {
return false;
} else if (binding.storageTexture.access != wgpu::StorageTextureAccess::Undefined) {
return false;
}
return IsBufferBindingType(binding.type);
}
bool BindingHasDynamicOffset(const BindGroupLayoutEntry& binding) { bool BindingHasDynamicOffset(const BindGroupLayoutEntry& binding) {
if (binding.buffer.type != wgpu::BufferBindingType::Undefined) { if (binding.buffer.type != wgpu::BufferBindingType::Undefined) {
return binding.buffer.hasDynamicOffset; return binding.buffer.hasDynamicOffset;
@ -357,7 +369,7 @@ namespace dawn_native {
BindingIndex lastBufferIndex{0}; BindingIndex lastBufferIndex{0};
BindingIndex firstNonBufferIndex = std::numeric_limits<BindingIndex>::max(); BindingIndex firstNonBufferIndex = std::numeric_limits<BindingIndex>::max();
for (BindingIndex i{0}; i < bindings.size(); ++i) { for (BindingIndex i{0}; i < bindings.size(); ++i) {
if (IsBufferBindingType(bindings[i].type)) { if (bindings[i].bindingType == BindingInfoType::Buffer) {
lastBufferIndex = std::max(i, lastBufferIndex); lastBufferIndex = std::max(i, lastBufferIndex);
} else { } else {
firstNonBufferIndex = std::min(i, firstNonBufferIndex); firstNonBufferIndex = std::min(i, firstNonBufferIndex);
@ -369,6 +381,120 @@ namespace dawn_native {
return firstNonBufferIndex >= lastBufferIndex; return firstNonBufferIndex >= lastBufferIndex;
} }
BindingInfo CreateBindGroupLayoutInfo(const BindGroupLayoutEntry& binding) {
BindingInfo bindingInfo;
bindingInfo.binding = BindingNumber(binding.binding);
bindingInfo.visibility = binding.visibility;
if (binding.buffer.type != wgpu::BufferBindingType::Undefined) {
bindingInfo.bindingType = BindingInfoType::Buffer;
bindingInfo.buffer = binding.buffer;
} else if (binding.sampler.type != wgpu::SamplerBindingType::Undefined) {
bindingInfo.bindingType = BindingInfoType::Sampler;
bindingInfo.sampler = binding.sampler;
} else if (binding.texture.sampleType != wgpu::TextureSampleType::Undefined) {
bindingInfo.bindingType = BindingInfoType::Texture;
bindingInfo.texture = binding.texture;
if (binding.texture.viewDimension == wgpu::TextureViewDimension::Undefined) {
bindingInfo.texture.viewDimension = wgpu::TextureViewDimension::e2D;
}
} else if (binding.storageTexture.access != wgpu::StorageTextureAccess::Undefined) {
bindingInfo.bindingType = BindingInfoType::StorageTexture;
bindingInfo.storageTexture = binding.storageTexture;
if (binding.storageTexture.viewDimension == wgpu::TextureViewDimension::Undefined) {
bindingInfo.storageTexture.viewDimension = wgpu::TextureViewDimension::e2D;
}
} else {
// Deprecated entry layout.
switch (binding.type) {
case wgpu::BindingType::UniformBuffer:
bindingInfo.bindingType = BindingInfoType::Buffer;
bindingInfo.buffer.type = wgpu::BufferBindingType::Uniform;
bindingInfo.buffer.hasDynamicOffset = binding.hasDynamicOffset;
bindingInfo.buffer.minBindingSize = binding.minBufferBindingSize;
break;
case wgpu::BindingType::StorageBuffer:
bindingInfo.bindingType = BindingInfoType::Buffer;
bindingInfo.buffer.type = wgpu::BufferBindingType::Storage;
bindingInfo.buffer.hasDynamicOffset = binding.hasDynamicOffset;
bindingInfo.buffer.minBindingSize = binding.minBufferBindingSize;
break;
case wgpu::BindingType::ReadonlyStorageBuffer:
bindingInfo.bindingType = BindingInfoType::Buffer;
bindingInfo.buffer.type = wgpu::BufferBindingType::ReadOnlyStorage;
bindingInfo.buffer.hasDynamicOffset = binding.hasDynamicOffset;
bindingInfo.buffer.minBindingSize = binding.minBufferBindingSize;
break;
case wgpu::BindingType::Sampler:
bindingInfo.bindingType = BindingInfoType::Sampler;
bindingInfo.sampler.type = wgpu::SamplerBindingType::Filtering;
break;
case wgpu::BindingType::ComparisonSampler:
bindingInfo.bindingType = BindingInfoType::Sampler;
bindingInfo.sampler.type = wgpu::SamplerBindingType::Comparison;
break;
case wgpu::BindingType::MultisampledTexture:
bindingInfo.texture.multisampled = true;
DAWN_FALLTHROUGH;
case wgpu::BindingType::SampledTexture:
bindingInfo.bindingType = BindingInfoType::Texture;
bindingInfo.texture.viewDimension = binding.viewDimension;
if (binding.texture.viewDimension ==
wgpu::TextureViewDimension::Undefined) {
bindingInfo.texture.viewDimension = wgpu::TextureViewDimension::e2D;
}
switch (binding.textureComponentType) {
case wgpu::TextureComponentType::Float:
bindingInfo.texture.sampleType = wgpu::TextureSampleType::Float;
break;
case wgpu::TextureComponentType::Uint:
bindingInfo.texture.sampleType = wgpu::TextureSampleType::Uint;
break;
case wgpu::TextureComponentType::Sint:
bindingInfo.texture.sampleType = wgpu::TextureSampleType::Sint;
break;
case wgpu::TextureComponentType::DepthComparison:
bindingInfo.texture.sampleType = wgpu::TextureSampleType::Depth;
break;
}
break;
case wgpu::BindingType::ReadonlyStorageTexture:
bindingInfo.bindingType = BindingInfoType::StorageTexture;
bindingInfo.storageTexture.access = wgpu::StorageTextureAccess::ReadOnly;
bindingInfo.storageTexture.format = binding.storageTextureFormat;
bindingInfo.storageTexture.viewDimension = binding.viewDimension;
if (binding.storageTexture.viewDimension ==
wgpu::TextureViewDimension::Undefined) {
bindingInfo.storageTexture.viewDimension =
wgpu::TextureViewDimension::e2D;
}
break;
case wgpu::BindingType::WriteonlyStorageTexture:
bindingInfo.bindingType = BindingInfoType::StorageTexture;
bindingInfo.storageTexture.access = wgpu::StorageTextureAccess::WriteOnly;
bindingInfo.storageTexture.format = binding.storageTextureFormat;
bindingInfo.storageTexture.viewDimension = binding.viewDimension;
if (binding.storageTexture.viewDimension ==
wgpu::TextureViewDimension::Undefined) {
bindingInfo.storageTexture.viewDimension =
wgpu::TextureViewDimension::e2D;
}
break;
case wgpu::BindingType::Undefined:
UNREACHABLE();
}
}
return bindingInfo;
}
} // namespace } // namespace
// BindGroupLayoutBase // BindGroupLayoutBase
@ -384,106 +510,7 @@ namespace dawn_native {
for (BindingIndex i{0}; i < mBindingInfo.size(); ++i) { for (BindingIndex i{0}; i < mBindingInfo.size(); ++i) {
const BindGroupLayoutEntry& binding = sortedBindings[static_cast<uint32_t>(i)]; const BindGroupLayoutEntry& binding = sortedBindings[static_cast<uint32_t>(i)];
// TODO(dawn:527): This code currently converts the new-style BindGroupLayoutEntry mBindingInfo[i] = CreateBindGroupLayoutInfo(binding);
// definitions into the older-style BindingInfo. This is to allow for a staggered
// conversion, but it means that there's some combinations that the more expressive new
// style can handle that will be lost in the translation. The solution is to update
// BindingInfo to only reflect the new-style entry layout and convert the old-style
// entry layout into it instead.
mBindingInfo[i].binding = BindingNumber(binding.binding);
mBindingInfo[i].visibility = binding.visibility;
if (binding.buffer.type != wgpu::BufferBindingType::Undefined) {
switch (binding.buffer.type) {
case wgpu::BufferBindingType::Uniform:
mBindingInfo[i].type = wgpu::BindingType::UniformBuffer;
break;
case wgpu::BufferBindingType::Storage:
mBindingInfo[i].type = wgpu::BindingType::StorageBuffer;
break;
case wgpu::BufferBindingType::ReadOnlyStorage:
mBindingInfo[i].type = wgpu::BindingType::ReadonlyStorageBuffer;
break;
case wgpu::BufferBindingType::Undefined:
UNREACHABLE();
}
mBindingInfo[i].minBufferBindingSize = binding.buffer.minBindingSize;
mBindingInfo[i].hasDynamicOffset = binding.buffer.hasDynamicOffset;
} else if (binding.sampler.type != wgpu::SamplerBindingType::Undefined) {
switch (binding.sampler.type) {
case wgpu::SamplerBindingType::Filtering:
case wgpu::SamplerBindingType::NonFiltering:
mBindingInfo[i].type = wgpu::BindingType::Sampler;
break;
case wgpu::SamplerBindingType::Comparison:
mBindingInfo[i].type = wgpu::BindingType::ComparisonSampler;
break;
case wgpu::SamplerBindingType::Undefined:
UNREACHABLE();
}
} else if (binding.texture.sampleType != wgpu::TextureSampleType::Undefined) {
mBindingInfo[i].type = binding.texture.multisampled
? wgpu::BindingType::MultisampledTexture
: wgpu::BindingType::SampledTexture;
switch (binding.texture.sampleType) {
case wgpu::TextureSampleType::Float:
case wgpu::TextureSampleType::UnfilterableFloat:
mBindingInfo[i].textureComponentType = wgpu::TextureComponentType::Float;
break;
case wgpu::TextureSampleType::Sint:
mBindingInfo[i].textureComponentType = wgpu::TextureComponentType::Sint;
break;
case wgpu::TextureSampleType::Uint:
mBindingInfo[i].textureComponentType = wgpu::TextureComponentType::Uint;
break;
case wgpu::TextureSampleType::Depth:
mBindingInfo[i].textureComponentType =
wgpu::TextureComponentType::DepthComparison;
break;
case wgpu::TextureSampleType::Undefined:
UNREACHABLE();
}
if (binding.texture.viewDimension == wgpu::TextureViewDimension::Undefined) {
mBindingInfo[i].viewDimension = wgpu::TextureViewDimension::e2D;
} else {
mBindingInfo[i].viewDimension = binding.texture.viewDimension;
}
} else if (binding.storageTexture.access != wgpu::StorageTextureAccess::Undefined) {
switch (binding.storageTexture.access) {
case wgpu::StorageTextureAccess::ReadOnly:
mBindingInfo[i].type = wgpu::BindingType::ReadonlyStorageTexture;
break;
case wgpu::StorageTextureAccess::WriteOnly:
mBindingInfo[i].type = wgpu::BindingType::WriteonlyStorageTexture;
break;
case wgpu::StorageTextureAccess::Undefined:
UNREACHABLE();
}
mBindingInfo[i].storageTextureFormat = binding.storageTexture.format;
if (binding.storageTexture.viewDimension == wgpu::TextureViewDimension::Undefined) {
mBindingInfo[i].viewDimension = wgpu::TextureViewDimension::e2D;
} else {
mBindingInfo[i].viewDimension = binding.storageTexture.viewDimension;
}
} else {
// Deprecated entry layout. As noted above, though, this is currently the only
// lossless path.
mBindingInfo[i].type = binding.type;
mBindingInfo[i].textureComponentType = binding.textureComponentType;
mBindingInfo[i].storageTextureFormat = binding.storageTextureFormat;
mBindingInfo[i].minBufferBindingSize = binding.minBufferBindingSize;
if (binding.viewDimension == wgpu::TextureViewDimension::Undefined) {
mBindingInfo[i].viewDimension = wgpu::TextureViewDimension::e2D;
} else {
mBindingInfo[i].viewDimension = binding.viewDimension;
}
mBindingInfo[i].hasDynamicOffset = binding.hasDynamicOffset;
}
if (IsBufferBinding(binding)) { if (IsBufferBinding(binding)) {
// Buffers must be contiguously packed at the start of the binding info. // Buffers must be contiguously packed at the start of the binding info.
@ -534,9 +561,12 @@ namespace dawn_native {
recorder.Record(it.first, it.second); recorder.Record(it.first, it.second);
const BindingInfo& info = mBindingInfo[it.second]; const BindingInfo& info = mBindingInfo[it.second];
recorder.Record(info.hasDynamicOffset, info.visibility, info.type,
info.textureComponentType, info.viewDimension, recorder.Record(info.buffer.hasDynamicOffset, info.visibility, info.bindingType,
info.storageTextureFormat, info.minBufferBindingSize); info.buffer.type, info.buffer.minBindingSize, info.sampler.type,
info.texture.sampleType, info.texture.viewDimension,
info.texture.multisampled, info.storageTexture.access,
info.storageTexture.format, info.storageTexture.viewDimension);
} }
return recorder.GetContentHash(); return recorder.GetContentHash();

View File

@ -48,15 +48,24 @@ namespace dawn_native {
// TODO(enga): Figure out a good number for this. // TODO(enga): Figure out a good number for this.
static constexpr uint32_t kMaxOptimalBindingsPerGroup = 32; static constexpr uint32_t kMaxOptimalBindingsPerGroup = 32;
enum class BindingInfoType {
Buffer,
Sampler,
Texture,
StorageTexture,
};
struct BindingInfo { struct BindingInfo {
BindingNumber binding; BindingNumber binding;
wgpu::ShaderStage visibility; wgpu::ShaderStage visibility;
wgpu::BindingType type;
wgpu::TextureComponentType textureComponentType = wgpu::TextureComponentType::Float; BindingInfoType bindingType;
wgpu::TextureViewDimension viewDimension = wgpu::TextureViewDimension::Undefined;
wgpu::TextureFormat storageTextureFormat = wgpu::TextureFormat::Undefined; // TODO(dawn:527): These four values could be made into a union.
bool hasDynamicOffset = false; BufferBindingLayout buffer;
uint64_t minBufferBindingSize = 0; SamplerBindingLayout sampler;
TextureBindingLayout texture;
StorageTextureBindingLayout storageTexture;
}; };
struct PerStageBindingCounts { struct PerStageBindingCounts {

View File

@ -31,6 +31,7 @@ namespace dawn_native {
// Format // Format
// TODO(dawn:527): Remove when unused.
ComponentTypeBit ToComponentTypeBit(wgpu::TextureComponentType type) { ComponentTypeBit ToComponentTypeBit(wgpu::TextureComponentType type) {
switch (type) { switch (type) {
case wgpu::TextureComponentType::Float: case wgpu::TextureComponentType::Float:
@ -64,6 +65,24 @@ namespace dawn_native {
return static_cast<ComponentTypeBit>(1 << static_cast<uint32_t>(type)); return static_cast<ComponentTypeBit>(1 << static_cast<uint32_t>(type));
} }
ComponentTypeBit SampleTypeToComponentTypeBit(wgpu::TextureSampleType sampleType) {
switch (sampleType) {
case wgpu::TextureSampleType::Float:
case wgpu::TextureSampleType::UnfilterableFloat:
return ComponentTypeBit::Float;
case wgpu::TextureSampleType::Sint:
return ComponentTypeBit::Sint;
case wgpu::TextureSampleType::Uint:
return ComponentTypeBit::Uint;
case wgpu::TextureSampleType::Depth:
return ComponentTypeBit::DepthComparison;
case wgpu::TextureSampleType::Undefined:
UNREACHABLE();
}
// TODO(dawn:527): Ideally we can get this path to use that static_cast method as well.
}
bool Format::IsColor() const { bool Format::IsColor() const {
return aspects == Aspect::Color; return aspects == Aspect::Color;
} }

View File

@ -39,6 +39,8 @@ namespace dawn_native {
// Converts an wgpu::TextureComponentType to its bitmask representation. // Converts an wgpu::TextureComponentType to its bitmask representation.
ComponentTypeBit ToComponentTypeBit(wgpu::TextureComponentType type); ComponentTypeBit ToComponentTypeBit(wgpu::TextureComponentType type);
// Converts an wgpu::TextureSampleType to its bitmask representation.
ComponentTypeBit SampleTypeToComponentTypeBit(wgpu::TextureSampleType sampleType);
struct TexelBlockInfo { struct TexelBlockInfo {
uint32_t byteSize; uint32_t byteSize;

View File

@ -83,14 +83,34 @@ namespace dawn_native {
// Merges two entries at the same location, if they are allowed to be merged. // Merges two entries at the same location, if they are allowed to be merged.
auto MergeEntries = [](BindGroupLayoutEntry* modifiedEntry, auto MergeEntries = [](BindGroupLayoutEntry* modifiedEntry,
const BindGroupLayoutEntry& mergedEntry) -> MaybeError { const BindGroupLayoutEntry& mergedEntry) -> MaybeError {
// Minimum buffer binding size excluded because we take the maximum seen across stages.
// Visibility is excluded because we take the OR across stages. // Visibility is excluded because we take the OR across stages.
bool compatible = bool compatible =
modifiedEntry->binding == mergedEntry.binding && // modifiedEntry->binding == mergedEntry.binding &&
modifiedEntry->type == mergedEntry.type && // modifiedEntry->buffer.type == mergedEntry.buffer.type &&
modifiedEntry->hasDynamicOffset == mergedEntry.hasDynamicOffset && // modifiedEntry->sampler.type == mergedEntry.sampler.type &&
modifiedEntry->viewDimension == mergedEntry.viewDimension && // modifiedEntry->texture.sampleType == mergedEntry.texture.sampleType &&
modifiedEntry->textureComponentType == mergedEntry.textureComponentType; modifiedEntry->storageTexture.access == mergedEntry.storageTexture.access;
// Minimum buffer binding size excluded because we take the maximum seen across stages.
if (modifiedEntry->buffer.type != wgpu::BufferBindingType::Undefined) {
compatible = compatible && modifiedEntry->buffer.hasDynamicOffset ==
mergedEntry.buffer.hasDynamicOffset;
}
if (modifiedEntry->texture.sampleType != wgpu::TextureSampleType::Undefined) {
compatible =
compatible &&
modifiedEntry->texture.viewDimension == mergedEntry.texture.viewDimension &&
modifiedEntry->texture.multisampled == mergedEntry.texture.multisampled;
}
if (modifiedEntry->storageTexture.access != wgpu::StorageTextureAccess::Undefined) {
compatible =
compatible &&
modifiedEntry->storageTexture.format == mergedEntry.storageTexture.format &&
modifiedEntry->storageTexture.viewDimension ==
mergedEntry.storageTexture.viewDimension;
}
// Check if any properties are incompatible with existing entry // Check if any properties are incompatible with existing entry
// If compatible, we will merge some properties // If compatible, we will merge some properties
@ -101,8 +121,8 @@ namespace dawn_native {
} }
// Use the max |minBufferBindingSize| we find. // Use the max |minBufferBindingSize| we find.
modifiedEntry->minBufferBindingSize = modifiedEntry->buffer.minBindingSize =
std::max(modifiedEntry->minBufferBindingSize, mergedEntry.minBufferBindingSize); std::max(modifiedEntry->buffer.minBindingSize, mergedEntry.buffer.minBindingSize);
// Use the OR of all the stages at which we find this binding. // Use the OR of all the stages at which we find this binding.
modifiedEntry->visibility |= mergedEntry.visibility; modifiedEntry->visibility |= mergedEntry.visibility;
@ -114,12 +134,20 @@ namespace dawn_native {
auto ConvertMetadataToEntry = auto ConvertMetadataToEntry =
[](const EntryPointMetadata::ShaderBindingInfo& shaderBinding) -> BindGroupLayoutEntry { [](const EntryPointMetadata::ShaderBindingInfo& shaderBinding) -> BindGroupLayoutEntry {
BindGroupLayoutEntry entry = {}; BindGroupLayoutEntry entry = {};
entry.type = shaderBinding.type; switch (shaderBinding.bindingType) {
entry.hasDynamicOffset = false; case BindingInfoType::Buffer:
entry.viewDimension = shaderBinding.viewDimension; entry.buffer = shaderBinding.buffer;
entry.textureComponentType = shaderBinding.textureComponentType; break;
entry.storageTextureFormat = shaderBinding.storageTextureFormat; case BindingInfoType::Sampler:
entry.minBufferBindingSize = shaderBinding.minBufferBindingSize; entry.sampler = shaderBinding.sampler;
break;
case BindingInfoType::Texture:
entry.texture = shaderBinding.texture;
break;
case BindingInfoType::StorageTexture:
entry.storageTexture = shaderBinding.storageTexture;
break;
}
return entry; return entry;
}; };

View File

@ -32,52 +32,50 @@ namespace dawn_native {
BindGroupBase* group) { BindGroupBase* group) {
for (BindingIndex bindingIndex{0}; bindingIndex < group->GetLayout()->GetBindingCount(); for (BindingIndex bindingIndex{0}; bindingIndex < group->GetLayout()->GetBindingCount();
++bindingIndex) { ++bindingIndex) {
wgpu::BindingType type = group->GetLayout()->GetBindingInfo(bindingIndex).type; const BindingInfo& bindingInfo = group->GetLayout()->GetBindingInfo(bindingIndex);
switch (type) { switch (bindingInfo.bindingType) {
case wgpu::BindingType::UniformBuffer: { case BindingInfoType::Buffer: {
BufferBase* buffer = group->GetBindingAsBufferBinding(bindingIndex).buffer; BufferBase* buffer = group->GetBindingAsBufferBinding(bindingIndex).buffer;
switch (bindingInfo.buffer.type) {
case wgpu::BufferBindingType::Uniform:
usageTracker->BufferUsedAs(buffer, wgpu::BufferUsage::Uniform); usageTracker->BufferUsedAs(buffer, wgpu::BufferUsage::Uniform);
break; break;
} case wgpu::BufferBindingType::Storage:
case wgpu::BindingType::StorageBuffer: {
BufferBase* buffer = group->GetBindingAsBufferBinding(bindingIndex).buffer;
usageTracker->BufferUsedAs(buffer, wgpu::BufferUsage::Storage); usageTracker->BufferUsedAs(buffer, wgpu::BufferUsage::Storage);
break; break;
case wgpu::BufferBindingType::ReadOnlyStorage:
usageTracker->BufferUsedAs(buffer, kReadOnlyStorageBuffer);
break;
case wgpu::BufferBindingType::Undefined:
UNREACHABLE();
}
break;
} }
case wgpu::BindingType::SampledTexture: case BindingInfoType::Texture: {
case wgpu::BindingType::MultisampledTexture: {
TextureViewBase* view = group->GetBindingAsTextureView(bindingIndex); TextureViewBase* view = group->GetBindingAsTextureView(bindingIndex);
usageTracker->TextureViewUsedAs(view, wgpu::TextureUsage::Sampled); usageTracker->TextureViewUsedAs(view, wgpu::TextureUsage::Sampled);
break; break;
} }
case wgpu::BindingType::ReadonlyStorageBuffer: { case BindingInfoType::StorageTexture: {
BufferBase* buffer = group->GetBindingAsBufferBinding(bindingIndex).buffer;
usageTracker->BufferUsedAs(buffer, kReadOnlyStorageBuffer);
break;
}
case wgpu::BindingType::Sampler:
case wgpu::BindingType::ComparisonSampler:
break;
case wgpu::BindingType::ReadonlyStorageTexture: {
TextureViewBase* view = group->GetBindingAsTextureView(bindingIndex); TextureViewBase* view = group->GetBindingAsTextureView(bindingIndex);
switch (bindingInfo.storageTexture.access) {
case wgpu::StorageTextureAccess::ReadOnly:
usageTracker->TextureViewUsedAs(view, kReadonlyStorageTexture); usageTracker->TextureViewUsedAs(view, kReadonlyStorageTexture);
break; break;
} case wgpu::StorageTextureAccess::WriteOnly:
case wgpu::BindingType::WriteonlyStorageTexture: {
TextureViewBase* view = group->GetBindingAsTextureView(bindingIndex);
usageTracker->TextureViewUsedAs(view, wgpu::TextureUsage::Storage); usageTracker->TextureViewUsedAs(view, wgpu::TextureUsage::Storage);
break; break;
case wgpu::StorageTextureAccess::Undefined:
UNREACHABLE();
}
break;
} }
case wgpu::BindingType::Undefined: case BindingInfoType::Sampler:
UNREACHABLE(); break;
} }
} }
} }
@ -158,16 +156,8 @@ namespace dawn_native {
// BGL creation sorts bindings such that the dynamic buffer bindings are first. // BGL creation sorts bindings such that the dynamic buffer bindings are first.
// ASSERT that this true. // ASSERT that this true.
ASSERT(bindingInfo.hasDynamicOffset); ASSERT(bindingInfo.bindingType == BindingInfoType::Buffer);
switch (bindingInfo.type) { ASSERT(bindingInfo.buffer.hasDynamicOffset);
case wgpu::BindingType::UniformBuffer:
case wgpu::BindingType::StorageBuffer:
case wgpu::BindingType::ReadonlyStorageBuffer:
break;
default:
UNREACHABLE();
break;
}
if (dynamicOffsets[i] % kMinDynamicBufferOffsetAlignment != 0) { if (dynamicOffsets[i] % kMinDynamicBufferOffsetAlignment != 0) {
return DAWN_VALIDATION_ERROR("Dynamic Buffer Offset need to be aligned"); return DAWN_VALIDATION_ERROR("Dynamic Buffer Offset need to be aligned");

View File

@ -261,7 +261,7 @@ namespace dawn_native {
for (BindingIndex bindingIndex{0}; bindingIndex < layout->GetBufferCount(); for (BindingIndex bindingIndex{0}; bindingIndex < layout->GetBufferCount();
++bindingIndex) { ++bindingIndex) {
const BindingInfo& bindingInfo = layout->GetBindingInfo(bindingIndex); const BindingInfo& bindingInfo = layout->GetBindingInfo(bindingIndex);
if (bindingInfo.minBufferBindingSize != 0) { if (bindingInfo.buffer.minBindingSize != 0) {
// Skip bindings that have minimum buffer size set in the layout // Skip bindings that have minimum buffer size set in the layout
continue; continue;
} }
@ -269,7 +269,7 @@ namespace dawn_native {
ASSERT(packedIdx < requiredBufferSizes.size()); ASSERT(packedIdx < requiredBufferSizes.size());
const auto& shaderInfo = shaderBindings.find(bindingInfo.binding); const auto& shaderInfo = shaderBindings.find(bindingInfo.binding);
if (shaderInfo != shaderBindings.end()) { if (shaderInfo != shaderBindings.end()) {
requiredBufferSizes[packedIdx] = shaderInfo->second.minBufferBindingSize; requiredBufferSizes[packedIdx] = shaderInfo->second.buffer.minBindingSize;
} else { } else {
// We have to include buffers if they are included in the bind group's // We have to include buffers if they are included in the bind group's
// packed vector. We don't actually need to check these at draw time, so // packed vector. We don't actually need to check these at draw time, so
@ -340,31 +340,11 @@ namespace dawn_native {
BindingIndex bindingIndex(bindingIt->second); BindingIndex bindingIndex(bindingIt->second);
const BindingInfo& layoutInfo = layout->GetBindingInfo(bindingIndex); const BindingInfo& layoutInfo = layout->GetBindingInfo(bindingIndex);
if (layoutInfo.type != shaderInfo.type) { if (layoutInfo.bindingType != shaderInfo.bindingType) {
// 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
// group layout is invalid. However, a readonly binding in the shader with a
// writable storage buffer in the bind group layout is valid.
bool validBindingConversion =
layoutInfo.type == wgpu::BindingType::StorageBuffer &&
shaderInfo.type == wgpu::BindingType::ReadonlyStorageBuffer;
// TODO(crbug.com/dawn/367): Temporarily allow using either a sampler or a
// comparison sampler until we can perform the proper shader analysis of what
// type is used in the shader module.
validBindingConversion |=
(layoutInfo.type == wgpu::BindingType::Sampler &&
shaderInfo.type == wgpu::BindingType::ComparisonSampler);
validBindingConversion |=
(layoutInfo.type == wgpu::BindingType::ComparisonSampler &&
shaderInfo.type == wgpu::BindingType::Sampler);
if (!validBindingConversion) {
return DAWN_VALIDATION_ERROR( return DAWN_VALIDATION_ERROR(
"The binding type of the bind group layout entry conflicts " + "The binding type of the bind group layout entry conflicts " +
GetShaderDeclarationString(group, bindingNumber)); GetShaderDeclarationString(group, bindingNumber));
} }
}
if ((layoutInfo.visibility & StageBit(entryPoint.stage)) == 0) { if ((layoutInfo.visibility & StageBit(entryPoint.stage)) == 0) {
return DAWN_VALIDATION_ERROR("The bind group layout entry for " + return DAWN_VALIDATION_ERROR("The bind group layout entry for " +
@ -372,49 +352,77 @@ namespace dawn_native {
" is not visible for the shader stage"); " is not visible for the shader stage");
} }
switch (layoutInfo.type) { switch (layoutInfo.bindingType) {
case wgpu::BindingType::SampledTexture: case BindingInfoType::Texture: {
case wgpu::BindingType::MultisampledTexture: { if (layoutInfo.texture.multisampled != shaderInfo.texture.multisampled) {
if (layoutInfo.textureComponentType != shaderInfo.textureComponentType) {
return DAWN_VALIDATION_ERROR( return DAWN_VALIDATION_ERROR(
"The textureComponentType of the bind group layout entry is " "The texture multisampled flag of the bind group layout entry is "
"different from " + "different from " +
GetShaderDeclarationString(group, bindingNumber)); GetShaderDeclarationString(group, bindingNumber));
} }
if (layoutInfo.viewDimension != shaderInfo.viewDimension) { if (layoutInfo.texture.sampleType != shaderInfo.texture.sampleType) {
return DAWN_VALIDATION_ERROR( return DAWN_VALIDATION_ERROR(
"The viewDimension of the bind group layout entry is different " "The texture sampleType of the bind group layout entry is "
"different from " +
GetShaderDeclarationString(group, bindingNumber));
}
if (layoutInfo.texture.viewDimension != shaderInfo.texture.viewDimension) {
return DAWN_VALIDATION_ERROR(
"The texture viewDimension of the bind group layout entry is "
"different "
"from " + "from " +
GetShaderDeclarationString(group, bindingNumber)); GetShaderDeclarationString(group, bindingNumber));
} }
break; break;
} }
case wgpu::BindingType::ReadonlyStorageTexture: case BindingInfoType::StorageTexture: {
case wgpu::BindingType::WriteonlyStorageTexture: { ASSERT(layoutInfo.storageTexture.format != wgpu::TextureFormat::Undefined);
ASSERT(layoutInfo.storageTextureFormat != wgpu::TextureFormat::Undefined); ASSERT(shaderInfo.storageTexture.format != wgpu::TextureFormat::Undefined);
ASSERT(shaderInfo.storageTextureFormat != wgpu::TextureFormat::Undefined);
if (layoutInfo.storageTextureFormat != shaderInfo.storageTextureFormat) { if (layoutInfo.storageTexture.access != shaderInfo.storageTexture.access) {
return DAWN_VALIDATION_ERROR( return DAWN_VALIDATION_ERROR(
"The storageTextureFormat of the bind group layout entry is " "The storageTexture access mode of the bind group layout entry is "
"different from " + "different from " +
GetShaderDeclarationString(group, bindingNumber)); GetShaderDeclarationString(group, bindingNumber));
} }
if (layoutInfo.viewDimension != shaderInfo.viewDimension) {
if (layoutInfo.storageTexture.format != shaderInfo.storageTexture.format) {
return DAWN_VALIDATION_ERROR( return DAWN_VALIDATION_ERROR(
"The viewDimension of the bind group layout entry is different " "The storageTexture format of the bind group layout entry is "
"from " + "different from " +
GetShaderDeclarationString(group, bindingNumber));
}
if (layoutInfo.storageTexture.viewDimension !=
shaderInfo.storageTexture.viewDimension) {
return DAWN_VALIDATION_ERROR(
"The storageTexture viewDimension of the bind group layout entry "
"is different from " +
GetShaderDeclarationString(group, bindingNumber)); GetShaderDeclarationString(group, bindingNumber));
} }
break; break;
} }
case wgpu::BindingType::UniformBuffer: case BindingInfoType::Buffer: {
case wgpu::BindingType::ReadonlyStorageBuffer: // Binding mismatch between shader and bind group is invalid. For example, a
case wgpu::BindingType::StorageBuffer: { // writable binding in the shader with a readonly storage buffer in the bind
if (layoutInfo.minBufferBindingSize != 0 && // group layout is invalid. However, a readonly binding in the shader with a
shaderInfo.minBufferBindingSize > layoutInfo.minBufferBindingSize) { // writable storage buffer in the bind group layout is valid.
bool validBindingConversion =
layoutInfo.buffer.type == wgpu::BufferBindingType::Storage &&
shaderInfo.buffer.type == wgpu::BufferBindingType::ReadOnlyStorage;
if (layoutInfo.buffer.type != shaderInfo.buffer.type &&
!validBindingConversion) {
return DAWN_VALIDATION_ERROR(
"The buffer type of the bind group layout entry conflicts " +
GetShaderDeclarationString(group, bindingNumber));
}
if (layoutInfo.buffer.minBindingSize != 0 &&
shaderInfo.buffer.minBindingSize > layoutInfo.buffer.minBindingSize) {
return DAWN_VALIDATION_ERROR( return DAWN_VALIDATION_ERROR(
"The minimum buffer size of the bind group layout entry is smaller " "The minimum buffer size of the bind group layout entry is smaller "
"than " + "than " +
@ -422,12 +430,12 @@ namespace dawn_native {
} }
break; break;
} }
case wgpu::BindingType::Sampler:
case wgpu::BindingType::ComparisonSampler:
break;
case wgpu::BindingType::Undefined: case BindingInfoType::Sampler:
UNREACHABLE(); // TODO(crbug.com/dawn/367): Temporarily allow using either a sampler or a
// comparison sampler until we can perform the proper shader analysis of
// what type is used in the shader module.
break;
} }
} }
@ -458,8 +466,9 @@ namespace dawn_native {
auto ExtractResourcesBinding = auto ExtractResourcesBinding =
[](const DeviceBase* device, [](const DeviceBase* device,
const spirv_cross::SmallVector<spirv_cross::Resource>& resources, const spirv_cross::SmallVector<spirv_cross::Resource>& resources,
const spirv_cross::Compiler& compiler, wgpu::BindingType bindingType, const spirv_cross::Compiler& compiler, BindingInfoType bindingType,
EntryPointMetadata::BindingInfo* metadataBindings) -> MaybeError { EntryPointMetadata::BindingInfo* metadataBindings,
bool isStorageBuffer = false) -> MaybeError {
for (const auto& resource : resources) { for (const auto& resource : resources) {
if (!compiler.get_decoration_bitset(resource.id).get(spv::DecorationBinding)) { if (!compiler.get_decoration_bitset(resource.id).get(spv::DecorationBinding)) {
return DAWN_VALIDATION_ERROR("No Binding decoration set for resource"); return DAWN_VALIDATION_ERROR("No Binding decoration set for resource");
@ -488,67 +497,64 @@ namespace dawn_native {
EntryPointMetadata::ShaderBindingInfo* info = &it.first->second; EntryPointMetadata::ShaderBindingInfo* info = &it.first->second;
info->id = resource.id; info->id = resource.id;
info->base_type_id = resource.base_type_id; info->base_type_id = resource.base_type_id;
info->bindingType = bindingType;
if (bindingType == wgpu::BindingType::UniformBuffer ||
bindingType == wgpu::BindingType::StorageBuffer ||
bindingType == wgpu::BindingType::ReadonlyStorageBuffer) {
// Determine buffer size, with a minimum of 1 element in the runtime array
spirv_cross::SPIRType type = compiler.get_type(info->base_type_id);
info->minBufferBindingSize =
compiler.get_declared_struct_size_runtime_array(type, 1);
}
switch (bindingType) { switch (bindingType) {
case wgpu::BindingType::SampledTexture: { case BindingInfoType::Texture: {
spirv_cross::SPIRType::ImageType imageType = spirv_cross::SPIRType::ImageType imageType =
compiler.get_type(info->base_type_id).image; compiler.get_type(info->base_type_id).image;
spirv_cross::SPIRType::BaseType textureComponentType = spirv_cross::SPIRType::BaseType textureComponentType =
compiler.get_type(imageType.type).basetype; compiler.get_type(imageType.type).basetype;
info->viewDimension = info->texture.viewDimension =
SpirvDimToTextureViewDimension(imageType.dim, imageType.arrayed); SpirvDimToTextureViewDimension(imageType.dim, imageType.arrayed);
info->textureComponentType = info->texture.sampleType =
SpirvBaseTypeToTextureComponentType(textureComponentType); SpirvBaseTypeToTextureSampleType(textureComponentType);
info->texture.multisampled = imageType.ms;
if (imageType.ms) {
info->type = wgpu::BindingType::MultisampledTexture;
} else {
info->type = wgpu::BindingType::SampledTexture;
}
if (imageType.depth) { if (imageType.depth) {
if (imageType.ms) { if (imageType.ms) {
return DAWN_VALIDATION_ERROR( return DAWN_VALIDATION_ERROR(
"Multisampled depth textures aren't supported"); "Multisampled depth textures aren't supported");
} }
if (info->textureComponentType != if (info->texture.sampleType != wgpu::TextureSampleType::Float) {
wgpu::TextureComponentType::Float) {
return DAWN_VALIDATION_ERROR( return DAWN_VALIDATION_ERROR(
"Depth textures must have a float type"); "Depth textures must have a float type");
} }
info->textureComponentType = info->texture.sampleType = wgpu::TextureSampleType::Depth;
wgpu::TextureComponentType::DepthComparison;
} }
break; break;
} }
case wgpu::BindingType::StorageBuffer: { case BindingInfoType::Buffer: {
// Determine buffer size, with a minimum of 1 element in the runtime
// array
spirv_cross::SPIRType type = compiler.get_type(info->base_type_id);
info->buffer.minBindingSize =
compiler.get_declared_struct_size_runtime_array(type, 1);
// Differentiate between readonly storage bindings and writable ones // Differentiate between readonly storage bindings and writable ones
// based on the NonWritable decoration // based on the NonWritable decoration.
// TODO(dawn:527): Could isStorageBuffer be determined by calling
// compiler.get_storage_class(resource.id)?
if (isStorageBuffer) {
spirv_cross::Bitset flags = spirv_cross::Bitset flags =
compiler.get_buffer_block_flags(resource.id); compiler.get_buffer_block_flags(resource.id);
if (flags.get(spv::DecorationNonWritable)) { if (flags.get(spv::DecorationNonWritable)) {
info->type = wgpu::BindingType::ReadonlyStorageBuffer; info->buffer.type = wgpu::BufferBindingType::ReadOnlyStorage;
} else { } else {
info->type = wgpu::BindingType::StorageBuffer; info->buffer.type = wgpu::BufferBindingType::Storage;
}
} else {
info->buffer.type = wgpu::BufferBindingType::Uniform;
} }
break; break;
} }
case wgpu::BindingType::ReadonlyStorageTexture: { case BindingInfoType::StorageTexture: {
spirv_cross::Bitset flags = compiler.get_decoration_bitset(resource.id); spirv_cross::Bitset flags = compiler.get_decoration_bitset(resource.id);
if (flags.get(spv::DecorationNonReadable)) { if (flags.get(spv::DecorationNonReadable)) {
info->type = wgpu::BindingType::WriteonlyStorageTexture; info->storageTexture.access = wgpu::StorageTextureAccess::WriteOnly;
} else if (flags.get(spv::DecorationNonWritable)) { } else if (flags.get(spv::DecorationNonWritable)) {
info->type = wgpu::BindingType::ReadonlyStorageTexture; info->storageTexture.access = wgpu::StorageTextureAccess::ReadOnly;
} else { } else {
return DAWN_VALIDATION_ERROR( return DAWN_VALIDATION_ERROR(
"Read-write storage textures are not supported"); "Read-write storage textures are not supported");
@ -576,33 +582,30 @@ namespace dawn_native {
return DAWN_VALIDATION_ERROR( return DAWN_VALIDATION_ERROR(
"Depth storage textures aren't supported"); "Depth storage textures aren't supported");
} }
info->storageTextureFormat = storageTextureFormat; info->storageTexture.format = storageTextureFormat;
info->viewDimension = info->storageTexture.viewDimension =
SpirvDimToTextureViewDimension(imageType.dim, imageType.arrayed); SpirvDimToTextureViewDimension(imageType.dim, imageType.arrayed);
break; break;
} }
default: case BindingInfoType::Sampler: {
info->type = bindingType; info->sampler.type = wgpu::SamplerBindingType::Filtering;
}
} }
} }
return {}; return {};
}; };
DAWN_TRY(ExtractResourcesBinding(device, resources.uniform_buffers, compiler, DAWN_TRY(ExtractResourcesBinding(device, resources.uniform_buffers, compiler,
wgpu::BindingType::UniformBuffer, BindingInfoType::Buffer, &metadata->bindings));
&metadata->bindings));
DAWN_TRY(ExtractResourcesBinding(device, resources.separate_images, compiler, DAWN_TRY(ExtractResourcesBinding(device, resources.separate_images, compiler,
wgpu::BindingType::SampledTexture, BindingInfoType::Texture, &metadata->bindings));
&metadata->bindings));
DAWN_TRY(ExtractResourcesBinding(device, resources.separate_samplers, compiler, DAWN_TRY(ExtractResourcesBinding(device, resources.separate_samplers, compiler,
wgpu::BindingType::Sampler, &metadata->bindings)); BindingInfoType::Sampler, &metadata->bindings));
DAWN_TRY(ExtractResourcesBinding(device, resources.storage_buffers, compiler, DAWN_TRY(ExtractResourcesBinding(device, resources.storage_buffers, compiler,
wgpu::BindingType::StorageBuffer, BindingInfoType::Buffer, &metadata->bindings, true));
&metadata->bindings));
// ReadonlyStorageTexture is used as a tag to do general storage texture handling. // ReadonlyStorageTexture is used as a tag to do general storage texture handling.
DAWN_TRY(ExtractResourcesBinding(device, resources.storage_images, compiler, DAWN_TRY(ExtractResourcesBinding(device, resources.storage_images, compiler,
wgpu::BindingType::ReadonlyStorageTexture, BindingInfoType::StorageTexture, &metadata->bindings));
&metadata->bindings));
// Extract the vertex attributes // Extract the vertex attributes
if (stage == SingleShaderStage::Vertex) { if (stage == SingleShaderStage::Vertex) {

View File

@ -101,7 +101,6 @@ namespace dawn_native {
private: private:
// Disallow access to unused members. // Disallow access to unused members.
using BindingInfo::hasDynamicOffset;
using BindingInfo::visibility; using BindingInfo::visibility;
}; };

View File

@ -148,4 +148,18 @@ namespace dawn_native {
} }
} }
wgpu::TextureSampleType SpirvBaseTypeToTextureSampleType(
spirv_cross::SPIRType::BaseType spirvBaseType) {
switch (spirvBaseType) {
case spirv_cross::SPIRType::Float:
return wgpu::TextureSampleType::Float;
case spirv_cross::SPIRType::Int:
return wgpu::TextureSampleType::Sint;
case spirv_cross::SPIRType::UInt:
return wgpu::TextureSampleType::Uint;
default:
UNREACHABLE();
}
}
} // namespace dawn_native } // namespace dawn_native

View File

@ -39,6 +39,8 @@ namespace dawn_native {
// Returns the format "component type" corresponding to the SPIRV base type. // Returns the format "component type" corresponding to the SPIRV base type.
wgpu::TextureComponentType SpirvBaseTypeToTextureComponentType( wgpu::TextureComponentType SpirvBaseTypeToTextureComponentType(
spirv_cross::SPIRType::BaseType spirvBaseType); spirv_cross::SPIRType::BaseType spirvBaseType);
wgpu::TextureSampleType SpirvBaseTypeToTextureSampleType(
spirv_cross::SPIRType::BaseType spirvBaseType);
} // namespace dawn_native } // namespace dawn_native

View File

@ -53,24 +53,25 @@ namespace dawn_native { namespace d3d12 {
// Increment size does not need to be stored and is only used to get a handle // Increment size does not need to be stored and is only used to get a handle
// local to the allocation with OffsetFrom(). // local to the allocation with OffsetFrom().
switch (bindingInfo.type) { switch (bindingInfo.bindingType) {
case wgpu::BindingType::UniformBuffer: { case BindingInfoType::Buffer: {
BufferBinding binding = GetBindingAsBufferBinding(bindingIndex); BufferBinding binding = GetBindingAsBufferBinding(bindingIndex);
switch (bindingInfo.buffer.type) {
case wgpu::BufferBindingType::Uniform: {
D3D12_CONSTANT_BUFFER_VIEW_DESC desc; D3D12_CONSTANT_BUFFER_VIEW_DESC desc;
// TODO(enga@google.com): investigate if this needs to be a constraint at // TODO(enga@google.com): investigate if this needs to be a constraint
// the API level // at the API level
desc.SizeInBytes = Align(binding.size, 256); desc.SizeInBytes = Align(binding.size, 256);
desc.BufferLocation = ToBackend(binding.buffer)->GetVA() + binding.offset; desc.BufferLocation =
ToBackend(binding.buffer)->GetVA() + binding.offset;
d3d12Device->CreateConstantBufferView( d3d12Device->CreateConstantBufferView(
&desc, &desc, viewAllocation.OffsetFrom(viewSizeIncrement,
viewAllocation.OffsetFrom(viewSizeIncrement, bindingOffsets[bindingIndex])); bindingOffsets[bindingIndex]));
break; break;
} }
case wgpu::BindingType::StorageBuffer: { case wgpu::BufferBindingType::Storage: {
BufferBinding binding = GetBindingAsBufferBinding(bindingIndex);
// 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
@ -89,16 +90,15 @@ namespace dawn_native { namespace d3d12 {
d3d12Device->CreateUnorderedAccessView( d3d12Device->CreateUnorderedAccessView(
ToBackend(binding.buffer)->GetD3D12Resource(), nullptr, &desc, ToBackend(binding.buffer)->GetD3D12Resource(), nullptr, &desc,
viewAllocation.OffsetFrom(viewSizeIncrement, bindingOffsets[bindingIndex])); viewAllocation.OffsetFrom(viewSizeIncrement,
bindingOffsets[bindingIndex]));
break; break;
} }
case wgpu::BindingType::ReadonlyStorageBuffer: { case wgpu::BufferBindingType::ReadOnlyStorage: {
BufferBinding binding = GetBindingAsBufferBinding(bindingIndex); // Like StorageBuffer, SPIRV-Cross outputs HLSL shaders for readonly
// storage buffer with ByteAddressBuffer. So we must use
// Like StorageBuffer, SPIRV-Cross outputs HLSL shaders for readonly storage // D3D12_BUFFER_SRV_FLAG_RAW when making the SRV descriptor. And it has
// buffer with ByteAddressBuffer. So we must use D3D12_BUFFER_SRV_FLAG_RAW // similar requirement for format, element size, etc.
// when making the SRV descriptor. And it has similar requirement for
// format, element size, etc.
D3D12_SHADER_RESOURCE_VIEW_DESC desc; D3D12_SHADER_RESOURCE_VIEW_DESC desc;
desc.Format = DXGI_FORMAT_R32_TYPELESS; desc.Format = DXGI_FORMAT_R32_TYPELESS;
desc.ViewDimension = D3D12_SRV_DIMENSION_BUFFER; desc.ViewDimension = D3D12_SRV_DIMENSION_BUFFER;
@ -109,15 +109,18 @@ namespace dawn_native { namespace d3d12 {
desc.Buffer.Flags = D3D12_BUFFER_SRV_FLAG_RAW; desc.Buffer.Flags = D3D12_BUFFER_SRV_FLAG_RAW;
d3d12Device->CreateShaderResourceView( d3d12Device->CreateShaderResourceView(
ToBackend(binding.buffer)->GetD3D12Resource(), &desc, ToBackend(binding.buffer)->GetD3D12Resource(), &desc,
viewAllocation.OffsetFrom(viewSizeIncrement, bindingOffsets[bindingIndex])); viewAllocation.OffsetFrom(viewSizeIncrement,
bindingOffsets[bindingIndex]));
break;
}
case wgpu::BufferBindingType::Undefined:
UNREACHABLE();
}
break; break;
} }
case wgpu::BindingType::SampledTexture: case BindingInfoType::Texture: {
case wgpu::BindingType::MultisampledTexture:
// Readonly storage is implemented as SRV so it can be used at the same time as a
// sampled texture.
case wgpu::BindingType::ReadonlyStorageTexture: {
auto* view = ToBackend(GetBindingAsTextureView(bindingIndex)); auto* view = ToBackend(GetBindingAsTextureView(bindingIndex));
auto& srv = view->GetSRVDescriptor(); auto& srv = view->GetSRVDescriptor();
d3d12Device->CreateShaderResourceView( d3d12Device->CreateShaderResourceView(
@ -125,24 +128,43 @@ namespace dawn_native { namespace d3d12 {
viewAllocation.OffsetFrom(viewSizeIncrement, bindingOffsets[bindingIndex])); viewAllocation.OffsetFrom(viewSizeIncrement, bindingOffsets[bindingIndex]));
break; break;
} }
case wgpu::BindingType::Sampler:
case wgpu::BindingType::ComparisonSampler: { case BindingInfoType::StorageTexture: {
// No-op as samplers will be later initialized by CreateSamplers(). TextureView* view = ToBackend(GetBindingAsTextureView(bindingIndex));
switch (bindingInfo.storageTexture.access) {
case wgpu::StorageTextureAccess::ReadOnly: {
// Readonly storage is implemented as SRV so it can be used at the same
// time as a sampled texture.
auto& srv = view->GetSRVDescriptor();
d3d12Device->CreateShaderResourceView(
ToBackend(view->GetTexture())->GetD3D12Resource(), &srv,
viewAllocation.OffsetFrom(viewSizeIncrement,
bindingOffsets[bindingIndex]));
break; break;
} }
case wgpu::BindingType::WriteonlyStorageTexture: { case wgpu::StorageTextureAccess::WriteOnly: {
TextureView* view = ToBackend(GetBindingAsTextureView(bindingIndex));
D3D12_UNORDERED_ACCESS_VIEW_DESC uav = view->GetUAVDescriptor(); D3D12_UNORDERED_ACCESS_VIEW_DESC uav = view->GetUAVDescriptor();
d3d12Device->CreateUnorderedAccessView( d3d12Device->CreateUnorderedAccessView(
ToBackend(view->GetTexture())->GetD3D12Resource(), nullptr, &uav, ToBackend(view->GetTexture())->GetD3D12Resource(), nullptr, &uav,
viewAllocation.OffsetFrom(viewSizeIncrement, bindingOffsets[bindingIndex])); viewAllocation.OffsetFrom(viewSizeIncrement,
bindingOffsets[bindingIndex]));
break; break;
} }
case wgpu::BindingType::Undefined: case wgpu::StorageTextureAccess::Undefined:
UNREACHABLE(); UNREACHABLE();
} }
break;
}
case BindingInfoType::Sampler: {
// No-op as samplers will be later initialized by CreateSamplers().
break;
}
}
} }
} }

View File

@ -22,25 +22,37 @@
namespace dawn_native { namespace d3d12 { namespace dawn_native { namespace d3d12 {
namespace { namespace {
BindGroupLayout::DescriptorType WGPUBindingTypeToDescriptorType( BindGroupLayout::DescriptorType WGPUBindingInfoToDescriptorType(
wgpu::BindingType bindingType) { const BindingInfo& bindingInfo) {
switch (bindingType) { switch (bindingInfo.bindingType) {
case wgpu::BindingType::UniformBuffer: case BindingInfoType::Buffer:
switch (bindingInfo.buffer.type) {
case wgpu::BufferBindingType::Uniform:
return BindGroupLayout::DescriptorType::CBV; return BindGroupLayout::DescriptorType::CBV;
case wgpu::BindingType::StorageBuffer: case wgpu::BufferBindingType::Storage:
case wgpu::BindingType::WriteonlyStorageTexture:
return BindGroupLayout::DescriptorType::UAV; return BindGroupLayout::DescriptorType::UAV;
case wgpu::BindingType::SampledTexture: case wgpu::BufferBindingType::ReadOnlyStorage:
case wgpu::BindingType::MultisampledTexture:
case wgpu::BindingType::ReadonlyStorageBuffer:
case wgpu::BindingType::ReadonlyStorageTexture:
return BindGroupLayout::DescriptorType::SRV; return BindGroupLayout::DescriptorType::SRV;
case wgpu::BindingType::Sampler: case wgpu::BufferBindingType::Undefined:
case wgpu::BindingType::ComparisonSampler:
return BindGroupLayout::DescriptorType::Sampler;
case wgpu::BindingType::Undefined:
UNREACHABLE(); UNREACHABLE();
} }
case BindingInfoType::Sampler:
return BindGroupLayout::DescriptorType::Sampler;
case BindingInfoType::Texture:
return BindGroupLayout::DescriptorType::SRV;
case BindingInfoType::StorageTexture:
switch (bindingInfo.storageTexture.access) {
case wgpu::StorageTextureAccess::ReadOnly:
return BindGroupLayout::DescriptorType::SRV;
case wgpu::StorageTextureAccess::WriteOnly:
return BindGroupLayout::DescriptorType::UAV;
case wgpu::StorageTextureAccess::Undefined:
UNREACHABLE();
}
}
} }
} // anonymous namespace } // anonymous namespace
@ -57,9 +69,9 @@ namespace dawn_native { namespace d3d12 {
// So there is no need to allocate the descriptor from descriptor heap. // So there is no need to allocate the descriptor from descriptor heap.
// This loop starts after the dynamic buffer indices to skip counting // This loop starts after the dynamic buffer indices to skip counting
// dynamic resources in calculating the size of the descriptor heap. // dynamic resources in calculating the size of the descriptor heap.
ASSERT(!bindingInfo.hasDynamicOffset); ASSERT(!bindingInfo.buffer.hasDynamicOffset);
DescriptorType descriptorType = WGPUBindingTypeToDescriptorType(bindingInfo.type); DescriptorType descriptorType = WGPUBindingInfoToDescriptorType(bindingInfo);
mBindingOffsets[bindingIndex] = mDescriptorCounts[descriptorType]++; mBindingOffsets[bindingIndex] = mDescriptorCounts[descriptorType]++;
} }
@ -107,31 +119,17 @@ namespace dawn_native { namespace d3d12 {
for (BindingIndex bindingIndex{0}; bindingIndex < GetBindingCount(); ++bindingIndex) { for (BindingIndex bindingIndex{0}; bindingIndex < GetBindingCount(); ++bindingIndex) {
const BindingInfo& bindingInfo = GetBindingInfo(bindingIndex); const BindingInfo& bindingInfo = GetBindingInfo(bindingIndex);
if (bindingInfo.hasDynamicOffset) { if (bindingInfo.bindingType == BindingInfoType::Buffer &&
bindingInfo.buffer.hasDynamicOffset) {
// Dawn is using values in mBindingOffsets to decide register number in HLSL. // Dawn is using values in mBindingOffsets to decide register number in HLSL.
// Root descriptor needs to set this value to set correct register number in // Root descriptor needs to set this value to set correct register number in
// generated HLSL shader. // generated HLSL shader.
switch (bindingInfo.type) {
case wgpu::BindingType::UniformBuffer:
case wgpu::BindingType::StorageBuffer:
case wgpu::BindingType::ReadonlyStorageBuffer:
mBindingOffsets[bindingIndex] = baseRegister++; mBindingOffsets[bindingIndex] = baseRegister++;
break;
case wgpu::BindingType::SampledTexture:
case wgpu::BindingType::MultisampledTexture:
case wgpu::BindingType::Sampler:
case wgpu::BindingType::ComparisonSampler:
case wgpu::BindingType::ReadonlyStorageTexture:
case wgpu::BindingType::WriteonlyStorageTexture:
case wgpu::BindingType::Undefined:
UNREACHABLE();
break;
}
continue; continue;
} }
// TODO(shaobo.yan@intel.com): Implement dynamic buffer offset. // TODO(shaobo.yan@intel.com): Implement dynamic buffer offset.
DescriptorType descriptorType = WGPUBindingTypeToDescriptorType(bindingInfo.type); DescriptorType descriptorType = WGPUBindingInfoToDescriptorType(bindingInfo);
mBindingOffsets[bindingIndex] += descriptorOffsets[descriptorType]; mBindingOffsets[bindingIndex] += descriptorOffsets[descriptorType];
} }

View File

@ -223,50 +223,56 @@ namespace dawn_native { namespace d3d12 {
for (BindGroupIndex index : IterateBitSet(mBindGroupLayoutsMask)) { for (BindGroupIndex index : IterateBitSet(mBindGroupLayoutsMask)) {
BindGroupLayoutBase* layout = mBindGroups[index]->GetLayout(); BindGroupLayoutBase* layout = mBindGroups[index]->GetLayout();
for (BindingIndex binding{0}; binding < layout->GetBindingCount(); ++binding) { for (BindingIndex binding{0}; binding < layout->GetBindingCount(); ++binding) {
switch (layout->GetBindingInfo(binding).type) { const BindingInfo& bindingInfo = layout->GetBindingInfo(binding);
case wgpu::BindingType::StorageBuffer: { switch (bindingInfo.bindingType) {
case BindingInfoType::Buffer: {
D3D12_RESOURCE_BARRIER barrier; D3D12_RESOURCE_BARRIER barrier;
wgpu::BufferUsage usage;
switch (bindingInfo.buffer.type) {
case wgpu::BufferBindingType::Uniform:
usage = wgpu::BufferUsage::Uniform;
break;
case wgpu::BufferBindingType::Storage:
usage = wgpu::BufferUsage::Storage;
break;
case wgpu::BufferBindingType::ReadOnlyStorage:
usage = kReadOnlyStorageBuffer;
break;
case wgpu::BufferBindingType::Undefined:
UNREACHABLE();
}
if (ToBackend(mBindGroups[index] if (ToBackend(mBindGroups[index]
->GetBindingAsBufferBinding(binding) ->GetBindingAsBufferBinding(binding)
.buffer) .buffer)
->TrackUsageAndGetResourceBarrier( ->TrackUsageAndGetResourceBarrier(commandContext, &barrier,
commandContext, &barrier, wgpu::BufferUsage::Storage)) { usage)) {
barriers.push_back(barrier); barriers.push_back(barrier);
} }
break; break;
} }
case wgpu::BindingType::ReadonlyStorageTexture: { case BindingInfoType::StorageTexture: {
TextureViewBase* view = TextureViewBase* view =
mBindGroups[index]->GetBindingAsTextureView(binding); mBindGroups[index]->GetBindingAsTextureView(binding);
wgpu::TextureUsage usage;
switch (bindingInfo.storageTexture.access) {
case wgpu::StorageTextureAccess::ReadOnly:
usage = kReadonlyStorageTexture;
break;
case wgpu::StorageTextureAccess::WriteOnly:
usage = wgpu::TextureUsage::Storage;
break;
case wgpu::StorageTextureAccess::Undefined:
UNREACHABLE();
}
ToBackend(view->GetTexture()) ToBackend(view->GetTexture())
->TransitionUsageAndGetResourceBarrier( ->TransitionUsageAndGetResourceBarrier(
commandContext, &barriers, kReadonlyStorageTexture, commandContext, &barriers, usage,
view->GetSubresourceRange()); view->GetSubresourceRange());
break; break;
} }
case wgpu::BindingType::WriteonlyStorageTexture: {
TextureViewBase* view = case BindingInfoType::Texture: {
mBindGroups[index]->GetBindingAsTextureView(binding);
ToBackend(view->GetTexture())
->TransitionUsageAndGetResourceBarrier(
commandContext, &barriers, wgpu::TextureUsage::Storage,
view->GetSubresourceRange());
break;
}
case wgpu::BindingType::ReadonlyStorageBuffer: {
D3D12_RESOURCE_BARRIER barrier;
if (ToBackend(mBindGroups[index]
->GetBindingAsBufferBinding(binding)
.buffer)
->TrackUsageAndGetResourceBarrier(commandContext, &barrier,
kReadOnlyStorageBuffer)) {
barriers.push_back(barrier);
}
break;
}
case wgpu::BindingType::SampledTexture:
case wgpu::BindingType::MultisampledTexture: {
TextureViewBase* view = TextureViewBase* view =
mBindGroups[index]->GetBindingAsTextureView(binding); mBindGroups[index]->GetBindingAsTextureView(binding);
ToBackend(view->GetTexture()) ToBackend(view->GetTexture())
@ -275,25 +281,10 @@ namespace dawn_native { namespace d3d12 {
view->GetSubresourceRange()); view->GetSubresourceRange());
break; break;
} }
case wgpu::BindingType::UniformBuffer: {
D3D12_RESOURCE_BARRIER barrier;
if (ToBackend(mBindGroups[index]
->GetBindingAsBufferBinding(binding)
.buffer)
->TrackUsageAndGetResourceBarrier(
commandContext, &barrier, wgpu::BufferUsage::Uniform)) {
barriers.push_back(barrier);
}
break;
}
case wgpu::BindingType::Sampler: case BindingInfoType::Sampler:
case wgpu::BindingType::ComparisonSampler:
// Don't require barriers. // Don't require barriers.
break; break;
case wgpu::BindingType::Undefined:
UNREACHABLE();
} }
} }
} }
@ -353,8 +344,9 @@ namespace dawn_native { namespace d3d12 {
D3D12_GPU_VIRTUAL_ADDRESS bufferLocation = D3D12_GPU_VIRTUAL_ADDRESS bufferLocation =
ToBackend(binding.buffer)->GetVA() + offset; ToBackend(binding.buffer)->GetVA() + offset;
switch (bindingInfo.type) { ASSERT(bindingInfo.bindingType == BindingInfoType::Buffer);
case wgpu::BindingType::UniformBuffer: switch (bindingInfo.buffer.type) {
case wgpu::BufferBindingType::Uniform:
if (mInCompute) { if (mInCompute) {
commandList->SetComputeRootConstantBufferView(parameterIndex, commandList->SetComputeRootConstantBufferView(parameterIndex,
bufferLocation); bufferLocation);
@ -363,7 +355,7 @@ namespace dawn_native { namespace d3d12 {
bufferLocation); bufferLocation);
} }
break; break;
case wgpu::BindingType::StorageBuffer: case wgpu::BufferBindingType::Storage:
if (mInCompute) { if (mInCompute) {
commandList->SetComputeRootUnorderedAccessView(parameterIndex, commandList->SetComputeRootUnorderedAccessView(parameterIndex,
bufferLocation); bufferLocation);
@ -372,7 +364,7 @@ namespace dawn_native { namespace d3d12 {
bufferLocation); bufferLocation);
} }
break; break;
case wgpu::BindingType::ReadonlyStorageBuffer: case wgpu::BufferBindingType::ReadOnlyStorage:
if (mInCompute) { if (mInCompute) {
commandList->SetComputeRootShaderResourceView(parameterIndex, commandList->SetComputeRootShaderResourceView(parameterIndex,
bufferLocation); bufferLocation);
@ -381,13 +373,7 @@ namespace dawn_native { namespace d3d12 {
bufferLocation); bufferLocation);
} }
break; break;
case wgpu::BindingType::SampledTexture: case wgpu::BufferBindingType::Undefined:
case wgpu::BindingType::MultisampledTexture:
case wgpu::BindingType::Sampler:
case wgpu::BindingType::ComparisonSampler:
case wgpu::BindingType::ReadonlyStorageTexture:
case wgpu::BindingType::WriteonlyStorageTexture:
case wgpu::BindingType::Undefined:
UNREACHABLE(); UNREACHABLE();
} }
} }

View File

@ -40,21 +40,15 @@ namespace dawn_native { namespace d3d12 {
return D3D12_SHADER_VISIBILITY_ALL; return D3D12_SHADER_VISIBILITY_ALL;
} }
D3D12_ROOT_PARAMETER_TYPE RootParameterType(wgpu::BindingType type) { D3D12_ROOT_PARAMETER_TYPE RootParameterType(wgpu::BufferBindingType type) {
switch (type) { switch (type) {
case wgpu::BindingType::UniformBuffer: case wgpu::BufferBindingType::Uniform:
return D3D12_ROOT_PARAMETER_TYPE_CBV; return D3D12_ROOT_PARAMETER_TYPE_CBV;
case wgpu::BindingType::StorageBuffer: case wgpu::BufferBindingType::Storage:
return D3D12_ROOT_PARAMETER_TYPE_UAV; return D3D12_ROOT_PARAMETER_TYPE_UAV;
case wgpu::BindingType::ReadonlyStorageBuffer: case wgpu::BufferBindingType::ReadOnlyStorage:
return D3D12_ROOT_PARAMETER_TYPE_SRV; return D3D12_ROOT_PARAMETER_TYPE_SRV;
case wgpu::BindingType::SampledTexture: case wgpu::BufferBindingType::Undefined:
case wgpu::BindingType::MultisampledTexture:
case wgpu::BindingType::Sampler:
case wgpu::BindingType::ComparisonSampler:
case wgpu::BindingType::ReadonlyStorageTexture:
case wgpu::BindingType::WriteonlyStorageTexture:
case wgpu::BindingType::Undefined:
UNREACHABLE(); UNREACHABLE();
} }
} }
@ -148,7 +142,7 @@ namespace dawn_native { namespace d3d12 {
mDynamicRootParameterIndices[group][dynamicBindingIndex] = rootParameters.size(); mDynamicRootParameterIndices[group][dynamicBindingIndex] = rootParameters.size();
// Set parameter types according to bind group layout descriptor. // Set parameter types according to bind group layout descriptor.
rootParameter.ParameterType = RootParameterType(bindingInfo.type); rootParameter.ParameterType = RootParameterType(bindingInfo.buffer.type);
// Set visibilities according to bind group layout descriptor. // Set visibilities according to bind group layout descriptor.
rootParameter.ShaderVisibility = ShaderVisibilityType(bindingInfo.visibility); rootParameter.ShaderVisibility = ShaderVisibilityType(bindingInfo.visibility);
@ -196,7 +190,7 @@ namespace dawn_native { namespace d3d12 {
BindingIndex bindingIndex) const { BindingIndex bindingIndex) const {
ASSERT(group < kMaxBindGroupsTyped); ASSERT(group < kMaxBindGroupsTyped);
ASSERT(bindingIndex < kMaxDynamicBuffersPerPipelineLayoutTyped); ASSERT(bindingIndex < kMaxDynamicBuffersPerPipelineLayoutTyped);
ASSERT(GetBindGroupLayout(group)->GetBindingInfo(bindingIndex).hasDynamicOffset); ASSERT(GetBindGroupLayout(group)->GetBindingInfo(bindingIndex).buffer.hasDynamicOffset);
ASSERT(GetBindGroupLayout(group)->GetBindingInfo(bindingIndex).visibility != ASSERT(GetBindGroupLayout(group)->GetBindingInfo(bindingIndex).visibility !=
wgpu::ShaderStage::None); wgpu::ShaderStage::None);
return mDynamicRootParameterIndices[group][bindingIndex]; return mDynamicRootParameterIndices[group][bindingIndex];

View File

@ -103,8 +103,7 @@ namespace dawn_native { namespace d3d12 {
for (BindingIndex bindingIndex = bgl->GetDynamicBufferCount(); for (BindingIndex bindingIndex = bgl->GetDynamicBufferCount();
bindingIndex < bgl->GetBindingCount(); ++bindingIndex) { bindingIndex < bgl->GetBindingCount(); ++bindingIndex) {
const BindingInfo& bindingInfo = bgl->GetBindingInfo(bindingIndex); const BindingInfo& bindingInfo = bgl->GetBindingInfo(bindingIndex);
if (bindingInfo.type == wgpu::BindingType::Sampler || if (bindingInfo.bindingType == BindingInfoType::Sampler) {
bindingInfo.type == wgpu::BindingType::ComparisonSampler) {
samplers.push_back(ToBackend(group->GetBindingAsSampler(bindingIndex))); samplers.push_back(ToBackend(group->GetBindingAsSampler(bindingIndex)));
} }
} }

View File

@ -277,8 +277,9 @@ namespace dawn_native { namespace d3d12 {
// the BGL produces the wrong output. Force read-only storage buffer bindings to // the BGL produces the wrong output. Force read-only storage buffer bindings to
// be treated as UAV instead of SRV. // be treated as UAV instead of SRV.
const bool forceStorageBufferAsUAV = const bool forceStorageBufferAsUAV =
(bindingInfo.type == wgpu::BindingType::ReadonlyStorageBuffer && (bindingInfo.buffer.type == wgpu::BufferBindingType::ReadOnlyStorage &&
bgl->GetBindingInfo(bindingIndex).type == wgpu::BindingType::StorageBuffer); bgl->GetBindingInfo(bindingIndex).buffer.type ==
wgpu::BufferBindingType::Storage);
uint32_t bindingOffset = bindingOffsets[bindingIndex]; uint32_t bindingOffset = bindingOffsets[bindingIndex];
compiler.set_decoration(bindingInfo.id, spv::DecorationBinding, bindingOffset); compiler.set_decoration(bindingInfo.id, spv::DecorationBinding, bindingOffset);

View File

@ -379,10 +379,8 @@ namespace dawn_native { namespace metal {
SingleShaderStage::Compute)[index][bindingIndex]; SingleShaderStage::Compute)[index][bindingIndex];
} }
switch (bindingInfo.type) { switch (bindingInfo.bindingType) {
case wgpu::BindingType::UniformBuffer: case BindingInfoType::Buffer: {
case wgpu::BindingType::StorageBuffer:
case wgpu::BindingType::ReadonlyStorageBuffer: {
const BufferBinding& binding = const BufferBinding& binding =
group->GetBindingAsBufferBinding(bindingIndex); group->GetBindingAsBufferBinding(bindingIndex);
const id<MTLBuffer> buffer = ToBackend(binding.buffer)->GetMTLBuffer(); const id<MTLBuffer> buffer = ToBackend(binding.buffer)->GetMTLBuffer();
@ -390,7 +388,7 @@ namespace dawn_native { namespace metal {
// TODO(shaobo.yan@intel.com): Record bound buffer status to use // TODO(shaobo.yan@intel.com): Record bound buffer status to use
// setBufferOffset to achieve better performance. // setBufferOffset to achieve better performance.
if (bindingInfo.hasDynamicOffset) { if (bindingInfo.buffer.hasDynamicOffset) {
offset += dynamicOffsets[currentDynamicBufferIndex]; offset += dynamicOffsets[currentDynamicBufferIndex];
currentDynamicBufferIndex++; currentDynamicBufferIndex++;
} }
@ -423,8 +421,7 @@ namespace dawn_native { namespace metal {
break; break;
} }
case wgpu::BindingType::Sampler: case BindingInfoType::Sampler: {
case wgpu::BindingType::ComparisonSampler: {
auto sampler = ToBackend(group->GetBindingAsSampler(bindingIndex)); auto sampler = ToBackend(group->GetBindingAsSampler(bindingIndex));
if (hasVertStage) { if (hasVertStage) {
[render setVertexSamplerState:sampler->GetMTLSamplerState() [render setVertexSamplerState:sampler->GetMTLSamplerState()
@ -441,10 +438,8 @@ namespace dawn_native { namespace metal {
break; break;
} }
case wgpu::BindingType::SampledTexture: case BindingInfoType::Texture:
case wgpu::BindingType::MultisampledTexture: case BindingInfoType::StorageTexture: {
case wgpu::BindingType::ReadonlyStorageTexture:
case wgpu::BindingType::WriteonlyStorageTexture: {
auto textureView = auto textureView =
ToBackend(group->GetBindingAsTextureView(bindingIndex)); ToBackend(group->GetBindingAsTextureView(bindingIndex));
if (hasVertStage) { if (hasVertStage) {
@ -461,9 +456,6 @@ namespace dawn_native { namespace metal {
} }
break; break;
} }
case wgpu::BindingType::Undefined:
UNREACHABLE();
} }
} }
} }

View File

@ -39,27 +39,22 @@ namespace dawn_native { namespace metal {
continue; continue;
} }
switch (bindingInfo.type) { switch (bindingInfo.bindingType) {
case wgpu::BindingType::UniformBuffer: case BindingInfoType::Buffer:
case wgpu::BindingType::StorageBuffer:
case wgpu::BindingType::ReadonlyStorageBuffer:
mIndexInfo[stage][group][bindingIndex] = bufferIndex; mIndexInfo[stage][group][bindingIndex] = bufferIndex;
bufferIndex++; bufferIndex++;
break; break;
case wgpu::BindingType::Sampler:
case wgpu::BindingType::ComparisonSampler: case BindingInfoType::Sampler:
mIndexInfo[stage][group][bindingIndex] = samplerIndex; mIndexInfo[stage][group][bindingIndex] = samplerIndex;
samplerIndex++; samplerIndex++;
break; break;
case wgpu::BindingType::SampledTexture:
case wgpu::BindingType::MultisampledTexture: case BindingInfoType::Texture:
case wgpu::BindingType::ReadonlyStorageTexture: case BindingInfoType::StorageTexture:
case wgpu::BindingType::WriteonlyStorageTexture:
mIndexInfo[stage][group][bindingIndex] = textureIndex; mIndexInfo[stage][group][bindingIndex] = textureIndex;
textureIndex++; textureIndex++;
break; break;
case wgpu::BindingType::Undefined:
UNREACHABLE();
} }
} }
} }

View File

@ -30,31 +30,15 @@ namespace dawn_native { namespace opengl {
ASSERT(bindingIndex < descriptor->layout->GetBindingCount()); ASSERT(bindingIndex < descriptor->layout->GetBindingCount());
const BindingInfo& bindingInfo = descriptor->layout->GetBindingInfo(bindingIndex); const BindingInfo& bindingInfo = descriptor->layout->GetBindingInfo(bindingIndex);
switch (bindingInfo.type) { if (bindingInfo.bindingType == BindingInfoType::StorageTexture) {
case wgpu::BindingType::ReadonlyStorageTexture:
case wgpu::BindingType::WriteonlyStorageTexture: {
ASSERT(entry.textureView != nullptr); ASSERT(entry.textureView != nullptr);
const uint32_t textureViewLayerCount = entry.textureView->GetLayerCount(); const uint32_t textureViewLayerCount = entry.textureView->GetLayerCount();
if (textureViewLayerCount != 1 && if (textureViewLayerCount != 1 &&
textureViewLayerCount != textureViewLayerCount != entry.textureView->GetTexture()->GetArrayLayers()) {
entry.textureView->GetTexture()->GetArrayLayers()) {
return DAWN_VALIDATION_ERROR( return DAWN_VALIDATION_ERROR(
"Currently the OpenGL backend only supports either binding a layer or " "Currently the OpenGL backend only supports either binding a layer or "
"the entire texture as storage texture."); "the entire texture as storage texture.");
} }
} break;
case wgpu::BindingType::UniformBuffer:
case wgpu::BindingType::StorageBuffer:
case wgpu::BindingType::ReadonlyStorageBuffer:
case wgpu::BindingType::SampledTexture:
case wgpu::BindingType::MultisampledTexture:
case wgpu::BindingType::Sampler:
case wgpu::BindingType::ComparisonSampler:
break;
case wgpu::BindingType::Undefined:
UNREACHABLE();
} }
} }

View File

@ -243,49 +243,43 @@ namespace dawn_native { namespace opengl {
const BindingInfo& bindingInfo = const BindingInfo& bindingInfo =
group->GetLayout()->GetBindingInfo(bindingIndex); group->GetLayout()->GetBindingInfo(bindingIndex);
switch (bindingInfo.type) { switch (bindingInfo.bindingType) {
case wgpu::BindingType::UniformBuffer: { case BindingInfoType::Buffer: {
BufferBinding binding = group->GetBindingAsBufferBinding(bindingIndex); BufferBinding binding = group->GetBindingAsBufferBinding(bindingIndex);
GLuint buffer = ToBackend(binding.buffer)->GetHandle(); GLuint buffer = ToBackend(binding.buffer)->GetHandle();
GLuint uboIndex = indices[bindingIndex]; GLuint index = indices[bindingIndex];
GLuint offset = binding.offset; GLuint offset = binding.offset;
if (bindingInfo.hasDynamicOffset) { if (bindingInfo.buffer.hasDynamicOffset) {
offset += dynamicOffsets[currentDynamicOffsetIndex]; offset += dynamicOffsets[currentDynamicOffsetIndex];
++currentDynamicOffsetIndex; ++currentDynamicOffsetIndex;
} }
gl.BindBufferRange(GL_UNIFORM_BUFFER, uboIndex, buffer, offset, GLenum target;
binding.size); switch (bindingInfo.buffer.type) {
case wgpu::BufferBindingType::Uniform:
target = GL_UNIFORM_BUFFER;
break;
case wgpu::BufferBindingType::Storage:
case wgpu::BufferBindingType::ReadOnlyStorage:
target = GL_SHADER_STORAGE_BUFFER;
break;
case wgpu::BufferBindingType::Undefined:
UNREACHABLE();
}
gl.BindBufferRange(target, index, buffer, offset, binding.size);
break; break;
} }
case wgpu::BindingType::StorageBuffer: case BindingInfoType::Sampler: {
case wgpu::BindingType::ReadonlyStorageBuffer: {
BufferBinding binding = group->GetBindingAsBufferBinding(bindingIndex);
GLuint buffer = ToBackend(binding.buffer)->GetHandle();
GLuint ssboIndex = indices[bindingIndex];
GLuint offset = binding.offset;
if (bindingInfo.hasDynamicOffset) {
offset += dynamicOffsets[currentDynamicOffsetIndex];
++currentDynamicOffsetIndex;
}
gl.BindBufferRange(GL_SHADER_STORAGE_BUFFER, ssboIndex, buffer, offset,
binding.size);
break;
}
case wgpu::BindingType::Sampler:
case wgpu::BindingType::ComparisonSampler: {
Sampler* sampler = ToBackend(group->GetBindingAsSampler(bindingIndex)); Sampler* sampler = ToBackend(group->GetBindingAsSampler(bindingIndex));
GLuint samplerIndex = indices[bindingIndex]; GLuint samplerIndex = indices[bindingIndex];
for (PipelineGL::SamplerUnit unit : for (PipelineGL::SamplerUnit unit :
mPipeline->GetTextureUnitsForSampler(samplerIndex)) { mPipeline->GetTextureUnitsForSampler(samplerIndex)) {
// Only use filtering for certain texture units, because int and // Only use filtering for certain texture units, because int
// uint texture are only complete without filtering // and uint texture are only complete without filtering
if (unit.shouldUseFiltering) { if (unit.shouldUseFiltering) {
gl.BindSampler(unit.unit, sampler->GetFilteringHandle()); gl.BindSampler(unit.unit, sampler->GetFilteringHandle());
} else { } else {
@ -295,8 +289,7 @@ namespace dawn_native { namespace opengl {
break; break;
} }
case wgpu::BindingType::SampledTexture: case BindingInfoType::Texture: {
case wgpu::BindingType::MultisampledTexture: {
TextureView* view = TextureView* view =
ToBackend(group->GetBindingAsTextureView(bindingIndex)); ToBackend(group->GetBindingAsTextureView(bindingIndex));
GLuint handle = view->GetHandle(); GLuint handle = view->GetHandle();
@ -328,8 +321,7 @@ namespace dawn_native { namespace opengl {
break; break;
} }
case wgpu::BindingType::ReadonlyStorageTexture: case BindingInfoType::StorageTexture: {
case wgpu::BindingType::WriteonlyStorageTexture: {
TextureView* view = TextureView* view =
ToBackend(group->GetBindingAsTextureView(bindingIndex)); ToBackend(group->GetBindingAsTextureView(bindingIndex));
Texture* texture = ToBackend(view->GetTexture()); Texture* texture = ToBackend(view->GetTexture());
@ -337,20 +329,19 @@ namespace dawn_native { namespace opengl {
GLuint imageIndex = indices[bindingIndex]; GLuint imageIndex = indices[bindingIndex];
GLenum access; GLenum access;
switch (bindingInfo.type) { switch (bindingInfo.storageTexture.access) {
case wgpu::BindingType::ReadonlyStorageTexture: case wgpu::StorageTextureAccess::ReadOnly:
access = GL_READ_ONLY; access = GL_READ_ONLY;
break; break;
case wgpu::BindingType::WriteonlyStorageTexture: case wgpu::StorageTextureAccess::WriteOnly:
access = GL_WRITE_ONLY; access = GL_WRITE_ONLY;
break; break;
case wgpu::StorageTextureAccess::Undefined:
default:
UNREACHABLE(); UNREACHABLE();
} }
// OpenGL ES only supports either binding a layer or the entire texture // OpenGL ES only supports either binding a layer or the entire
// in glBindImageTexture(). // texture in glBindImageTexture().
GLboolean isLayered; GLboolean isLayered;
if (view->GetLayerCount() == 1) { if (view->GetLayerCount() == 1) {
isLayered = GL_FALSE; isLayered = GL_FALSE;
@ -365,9 +356,6 @@ namespace dawn_native { namespace opengl {
texture->GetGLFormat().internalFormat); texture->GetGLFormat().internalFormat);
break; break;
} }
case wgpu::BindingType::Undefined:
UNREACHABLE();
} }
} }
} }

View File

@ -132,8 +132,11 @@ namespace dawn_native { namespace opengl {
BindingIndex bindingIndex = it.second; BindingIndex bindingIndex = it.second;
std::string name = GetBindingName(group, bindingNumber); std::string name = GetBindingName(group, bindingNumber);
switch (bgl->GetBindingInfo(bindingIndex).type) { const BindingInfo& bindingInfo = bgl->GetBindingInfo(bindingIndex);
case wgpu::BindingType::UniformBuffer: { switch (bindingInfo.bindingType) {
case BindingInfoType::Buffer:
switch (bindingInfo.buffer.type) {
case wgpu::BufferBindingType::Uniform: {
GLint location = gl.GetUniformBlockIndex(mProgram, name.c_str()); GLint location = gl.GetUniformBlockIndex(mProgram, name.c_str());
if (location != -1) { if (location != -1) {
gl.UniformBlockBinding(mProgram, location, gl.UniformBlockBinding(mProgram, location,
@ -141,14 +144,13 @@ namespace dawn_native { namespace opengl {
} }
break; break;
} }
case wgpu::BufferBindingType::Storage:
case wgpu::BindingType::StorageBuffer: case wgpu::BufferBindingType::ReadOnlyStorage: {
case wgpu::BindingType::ReadonlyStorageBuffer: { // Since glShaderStorageBlockBinding doesn't exist in OpenGL ES, we
// Since glShaderStorageBlockBinding doesn't exist in OpenGL ES, we skip // skip that call and handle it during shader translation by
// that call and handle it during shader translation by modifying the // modifying the location decoration. Contrary to all other binding
// location decoration. // types, OpenGL ES's SSBO binding index in the SSBO table is the
// Contrary to all other binding types, OpenGL ES's SSBO binding index in // value of the location= decoration in GLSL.
// the SSBO table is the value of the location= decoration in GLSL.
if (gl.GetVersion().IsDesktop()) { if (gl.GetVersion().IsDesktop()) {
GLuint location = gl.GetProgramResourceIndex( GLuint location = gl.GetProgramResourceIndex(
mProgram, GL_SHADER_STORAGE_BLOCK, name.c_str()); mProgram, GL_SHADER_STORAGE_BLOCK, name.c_str());
@ -159,26 +161,24 @@ namespace dawn_native { namespace opengl {
} }
break; break;
} }
case wgpu::BufferBindingType::Undefined:
UNREACHABLE();
}
break;
case wgpu::BindingType::Sampler: case BindingInfoType::Sampler:
case wgpu::BindingType::ComparisonSampler: case BindingInfoType::Texture:
case wgpu::BindingType::SampledTexture:
case wgpu::BindingType::MultisampledTexture:
// These binding types are handled in the separate sampler and texture // These binding types are handled in the separate sampler and texture
// emulation // emulation
break; break;
case wgpu::BindingType::ReadonlyStorageTexture: case BindingInfoType::StorageTexture: {
case wgpu::BindingType::WriteonlyStorageTexture: {
GLint location = gl.GetUniformLocation(mProgram, name.c_str()); GLint location = gl.GetUniformLocation(mProgram, name.c_str());
if (location != -1) { if (location != -1) {
gl.Uniform1i(location, indices[group][bindingIndex]); gl.Uniform1i(location, indices[group][bindingIndex]);
} }
break; break;
} }
case wgpu::BindingType::Undefined:
UNREACHABLE();
} }
} }
} }
@ -216,8 +216,8 @@ namespace dawn_native { namespace opengl {
GLuint textureIndex = indices[combined.textureLocation.group][bindingIndex]; GLuint textureIndex = indices[combined.textureLocation.group][bindingIndex];
mUnitsForTextures[textureIndex].push_back(textureUnit); mUnitsForTextures[textureIndex].push_back(textureUnit);
shouldUseFiltering = bgl->GetBindingInfo(bindingIndex).textureComponentType == shouldUseFiltering = bgl->GetBindingInfo(bindingIndex).texture.sampleType ==
wgpu::TextureComponentType::Float; wgpu::TextureSampleType::Float;
} }
{ {
if (combined.useDummySampler) { if (combined.useDummySampler) {

View File

@ -34,36 +34,38 @@ namespace dawn_native { namespace opengl {
for (BindingIndex bindingIndex{0}; bindingIndex < bgl->GetBindingCount(); for (BindingIndex bindingIndex{0}; bindingIndex < bgl->GetBindingCount();
++bindingIndex) { ++bindingIndex) {
switch (bgl->GetBindingInfo(bindingIndex).type) { const BindingInfo& bindingInfo = bgl->GetBindingInfo(bindingIndex);
case wgpu::BindingType::UniformBuffer: switch (bindingInfo.bindingType) {
case BindingInfoType::Buffer:
switch (bindingInfo.buffer.type) {
case wgpu::BufferBindingType::Uniform:
mIndexInfo[group][bindingIndex] = uboIndex; mIndexInfo[group][bindingIndex] = uboIndex;
uboIndex++; uboIndex++;
break; break;
case wgpu::BindingType::Sampler: case wgpu::BufferBindingType::Storage:
case wgpu::BindingType::ComparisonSampler: case wgpu::BufferBindingType::ReadOnlyStorage:
mIndexInfo[group][bindingIndex] = ssboIndex;
ssboIndex++;
break;
case wgpu::BufferBindingType::Undefined:
UNREACHABLE();
}
break;
case BindingInfoType::Sampler:
mIndexInfo[group][bindingIndex] = samplerIndex; mIndexInfo[group][bindingIndex] = samplerIndex;
samplerIndex++; samplerIndex++;
break; break;
case wgpu::BindingType::SampledTexture:
case wgpu::BindingType::MultisampledTexture: case BindingInfoType::Texture:
mIndexInfo[group][bindingIndex] = sampledTextureIndex; mIndexInfo[group][bindingIndex] = sampledTextureIndex;
sampledTextureIndex++; sampledTextureIndex++;
break; break;
case wgpu::BindingType::StorageBuffer: case BindingInfoType::StorageTexture:
case wgpu::BindingType::ReadonlyStorageBuffer:
mIndexInfo[group][bindingIndex] = ssboIndex;
ssboIndex++;
break;
case wgpu::BindingType::ReadonlyStorageTexture:
case wgpu::BindingType::WriteonlyStorageTexture:
mIndexInfo[group][bindingIndex] = storageTextureIndex; mIndexInfo[group][bindingIndex] = storageTextureIndex;
storageTextureIndex++; storageTextureIndex++;
break; break;
case wgpu::BindingType::Undefined:
UNREACHABLE();
} }
} }
} }

View File

@ -180,12 +180,10 @@ namespace dawn_native { namespace opengl {
const auto& info = it.second; const auto& info = it.second;
uint32_t resourceId; uint32_t resourceId;
switch (info.type) { switch (info.bindingType) {
// When the resource is a uniform or shader storage block, we should change the // When the resource is a uniform or shader storage block, we should change the
// block name instead of the instance name. // block name instead of the instance name.
case wgpu::BindingType::ReadonlyStorageBuffer: case BindingInfoType::Buffer:
case wgpu::BindingType::StorageBuffer:
case wgpu::BindingType::UniformBuffer:
resourceId = info.base_type_id; resourceId = info.base_type_id;
break; break;
default: default:
@ -197,8 +195,9 @@ namespace dawn_native { namespace opengl {
compiler.unset_decoration(info.id, spv::DecorationDescriptorSet); compiler.unset_decoration(info.id, spv::DecorationDescriptorSet);
// OpenGL ES has no glShaderStorageBlockBinding call, so we adjust the SSBO binding // OpenGL ES has no glShaderStorageBlockBinding call, so we adjust the SSBO binding
// decoration here instead. // decoration here instead.
if (version.IsES() && (info.type == wgpu::BindingType::StorageBuffer || if (version.IsES() && info.bindingType == BindingInfoType::Buffer &&
info.type == wgpu::BindingType::ReadonlyStorageBuffer)) { (info.buffer.type == wgpu::BufferBindingType::Storage ||
info.buffer.type == wgpu::BufferBindingType::ReadOnlyStorage)) {
const auto& indices = layout->GetBindingIndexInfo(); const auto& indices = layout->GetBindingIndexInfo();
BindingIndex bindingIndex = BindingIndex bindingIndex =
layout->GetBindGroupLayout(group)->GetBindingIndex(bindingNumber); layout->GetBindGroupLayout(group)->GetBindingIndex(bindingNumber);

View File

@ -46,31 +46,31 @@ namespace dawn_native { namespace vulkan {
} // anonymous namespace } // anonymous namespace
VkDescriptorType VulkanDescriptorType(wgpu::BindingType type, bool isDynamic) { VkDescriptorType VulkanDescriptorType(const BindingInfo& bindingInfo) {
switch (type) { switch (bindingInfo.bindingType) {
case wgpu::BindingType::UniformBuffer: case BindingInfoType::Buffer:
if (isDynamic) { switch (bindingInfo.buffer.type) {
case wgpu::BufferBindingType::Uniform:
if (bindingInfo.buffer.hasDynamicOffset) {
return VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC; return VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC;
} }
return VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; return VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
case wgpu::BindingType::Sampler: case wgpu::BufferBindingType::Storage:
case wgpu::BindingType::ComparisonSampler: case wgpu::BufferBindingType::ReadOnlyStorage:
return VK_DESCRIPTOR_TYPE_SAMPLER; if (bindingInfo.buffer.hasDynamicOffset) {
case wgpu::BindingType::SampledTexture:
case wgpu::BindingType::MultisampledTexture:
return VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
case wgpu::BindingType::StorageBuffer:
case wgpu::BindingType::ReadonlyStorageBuffer:
if (isDynamic) {
return VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC; return VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC;
} }
return VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; return VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
case wgpu::BindingType::ReadonlyStorageTexture: case wgpu::BufferBindingType::Undefined:
case wgpu::BindingType::WriteonlyStorageTexture:
return VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
case wgpu::BindingType::Undefined:
UNREACHABLE(); UNREACHABLE();
} }
case BindingInfoType::Sampler:
return VK_DESCRIPTOR_TYPE_SAMPLER;
case BindingInfoType::Texture:
return VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
case BindingInfoType::StorageTexture:
return VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
}
} }
// static // static
@ -96,8 +96,7 @@ namespace dawn_native { namespace vulkan {
VkDescriptorSetLayoutBinding vkBinding; VkDescriptorSetLayoutBinding vkBinding;
vkBinding.binding = static_cast<uint32_t>(bindingNumber); vkBinding.binding = static_cast<uint32_t>(bindingNumber);
vkBinding.descriptorType = vkBinding.descriptorType = VulkanDescriptorType(bindingInfo);
VulkanDescriptorType(bindingInfo.type, bindingInfo.hasDynamicOffset);
vkBinding.descriptorCount = 1; vkBinding.descriptorCount = 1;
vkBinding.stageFlags = VulkanShaderStageFlags(bindingInfo.visibility); vkBinding.stageFlags = VulkanShaderStageFlags(bindingInfo.visibility);
vkBinding.pImmutableSamplers = nullptr; vkBinding.pImmutableSamplers = nullptr;
@ -121,9 +120,7 @@ namespace dawn_native { namespace vulkan {
std::map<VkDescriptorType, uint32_t> descriptorCountPerType; std::map<VkDescriptorType, uint32_t> descriptorCountPerType;
for (BindingIndex bindingIndex{0}; bindingIndex < GetBindingCount(); ++bindingIndex) { for (BindingIndex bindingIndex{0}; bindingIndex < GetBindingCount(); ++bindingIndex) {
const BindingInfo& bindingInfo = GetBindingInfo(bindingIndex); VkDescriptorType vulkanType = VulkanDescriptorType(GetBindingInfo(bindingIndex));
VkDescriptorType vulkanType =
VulkanDescriptorType(bindingInfo.type, bindingInfo.hasDynamicOffset);
// map::operator[] will return 0 if the key doesn't exist. // map::operator[] will return 0 if the key doesn't exist.
descriptorCountPerType[vulkanType]++; descriptorCountPerType[vulkanType]++;

View File

@ -29,7 +29,7 @@ namespace dawn_native { namespace vulkan {
class DescriptorSetAllocator; class DescriptorSetAllocator;
class Device; class Device;
VkDescriptorType VulkanDescriptorType(wgpu::BindingType type, bool isDynamic); VkDescriptorType VulkanDescriptorType(const BindingInfo& bindingInfo);
// In Vulkan descriptor pools have to be sized to an exact number of descriptors. This means // In Vulkan descriptor pools have to be sized to an exact number of descriptors. This means
// it's hard to have something where we can mix different types of descriptor sets because // it's hard to have something where we can mix different types of descriptor sets because

View File

@ -60,13 +60,10 @@ namespace dawn_native { namespace vulkan {
write.dstBinding = static_cast<uint32_t>(bindingNumber); write.dstBinding = static_cast<uint32_t>(bindingNumber);
write.dstArrayElement = 0; write.dstArrayElement = 0;
write.descriptorCount = 1; write.descriptorCount = 1;
write.descriptorType = write.descriptorType = VulkanDescriptorType(bindingInfo);
VulkanDescriptorType(bindingInfo.type, bindingInfo.hasDynamicOffset);
switch (bindingInfo.type) { switch (bindingInfo.bindingType) {
case wgpu::BindingType::UniformBuffer: case BindingInfoType::Buffer: {
case wgpu::BindingType::StorageBuffer:
case wgpu::BindingType::ReadonlyStorageBuffer: {
BufferBinding binding = GetBindingAsBufferBinding(bindingIndex); BufferBinding binding = GetBindingAsBufferBinding(bindingIndex);
writeBufferInfo[numWrites].buffer = ToBackend(binding.buffer)->GetHandle(); writeBufferInfo[numWrites].buffer = ToBackend(binding.buffer)->GetHandle();
@ -76,16 +73,14 @@ namespace dawn_native { namespace vulkan {
break; break;
} }
case wgpu::BindingType::Sampler: case BindingInfoType::Sampler: {
case wgpu::BindingType::ComparisonSampler: {
Sampler* sampler = ToBackend(GetBindingAsSampler(bindingIndex)); Sampler* sampler = ToBackend(GetBindingAsSampler(bindingIndex));
writeImageInfo[numWrites].sampler = sampler->GetHandle(); writeImageInfo[numWrites].sampler = sampler->GetHandle();
write.pImageInfo = &writeImageInfo[numWrites]; write.pImageInfo = &writeImageInfo[numWrites];
break; break;
} }
case wgpu::BindingType::SampledTexture: case BindingInfoType::Texture: {
case wgpu::BindingType::MultisampledTexture: {
TextureView* view = ToBackend(GetBindingAsTextureView(bindingIndex)); TextureView* view = ToBackend(GetBindingAsTextureView(bindingIndex));
writeImageInfo[numWrites].imageView = view->GetHandle(); writeImageInfo[numWrites].imageView = view->GetHandle();
@ -98,8 +93,7 @@ namespace dawn_native { namespace vulkan {
break; break;
} }
case wgpu::BindingType::ReadonlyStorageTexture: case BindingInfoType::StorageTexture: {
case wgpu::BindingType::WriteonlyStorageTexture: {
TextureView* view = ToBackend(GetBindingAsTextureView(bindingIndex)); TextureView* view = ToBackend(GetBindingAsTextureView(bindingIndex));
writeImageInfo[numWrites].imageView = view->GetHandle(); writeImageInfo[numWrites].imageView = view->GetHandle();
@ -108,9 +102,6 @@ namespace dawn_native { namespace vulkan {
write.pImageInfo = &writeImageInfo[numWrites]; write.pImageInfo = &writeImageInfo[numWrites];
break; break;
} }
case wgpu::BindingType::Undefined:
UNREACHABLE();
} }
numWrites++; numWrites++;

View File

@ -155,23 +155,35 @@ namespace dawn_native { namespace vulkan {
for (BindGroupIndex index : IterateBitSet(mBindGroupLayoutsMask)) { for (BindGroupIndex index : IterateBitSet(mBindGroupLayoutsMask)) {
BindGroupLayoutBase* layout = mBindGroups[index]->GetLayout(); BindGroupLayoutBase* layout = mBindGroups[index]->GetLayout();
for (BindingIndex binding{0}; binding < layout->GetBindingCount(); ++binding) { for (BindingIndex binding{0}; binding < layout->GetBindingCount(); ++binding) {
switch (layout->GetBindingInfo(binding).type) { const BindingInfo& bindingInfo = layout->GetBindingInfo(binding);
case wgpu::BindingType::StorageBuffer:
case wgpu::BindingType::ReadonlyStorageBuffer: { switch (bindingInfo.bindingType) {
case BindingInfoType::Buffer: {
wgpu::BufferUsage usage;
switch (bindingInfo.buffer.type) {
case wgpu::BufferBindingType::Uniform:
usage = wgpu::BufferUsage::Uniform;
break;
case wgpu::BufferBindingType::Storage:
case wgpu::BufferBindingType::ReadOnlyStorage:
usage = wgpu::BufferUsage::Storage;
break;
case wgpu::BufferBindingType::Undefined:
UNREACHABLE();
}
VkBufferMemoryBarrier bufferBarrier; VkBufferMemoryBarrier bufferBarrier;
if (ToBackend(mBindGroups[index] if (ToBackend(mBindGroups[index]
->GetBindingAsBufferBinding(binding) ->GetBindingAsBufferBinding(binding)
.buffer) .buffer)
->TransitionUsageAndGetResourceBarrier( ->TransitionUsageAndGetResourceBarrier(
wgpu::BufferUsage::Storage, &bufferBarrier, &srcStages, usage, &bufferBarrier, &srcStages, &dstStages)) {
&dstStages)) {
bufferBarriers.push_back(bufferBarrier); bufferBarriers.push_back(bufferBarrier);
} }
break; break;
} }
case wgpu::BindingType::ReadonlyStorageTexture: case BindingInfoType::StorageTexture: {
case wgpu::BindingType::WriteonlyStorageTexture: {
TextureViewBase* view = TextureViewBase* view =
mBindGroups[index]->GetBindingAsTextureView(binding); mBindGroups[index]->GetBindingAsTextureView(binding);
ToBackend(view->GetTexture()) ToBackend(view->GetTexture())
@ -180,21 +192,8 @@ namespace dawn_native { namespace vulkan {
&imageBarriers, &srcStages, &dstStages); &imageBarriers, &srcStages, &dstStages);
break; break;
} }
case wgpu::BindingType::UniformBuffer: {
VkBufferMemoryBarrier bufferBarrier;
if (ToBackend(mBindGroups[index]
->GetBindingAsBufferBinding(binding)
.buffer)
->TransitionUsageAndGetResourceBarrier(
wgpu::BufferUsage::Uniform, &bufferBarrier, &srcStages,
&dstStages)) {
bufferBarriers.push_back(bufferBarrier);
}
break;
}
case wgpu::BindingType::SampledTexture: case BindingInfoType::Texture: {
case wgpu::BindingType::MultisampledTexture: {
TextureViewBase* view = TextureViewBase* view =
mBindGroups[index]->GetBindingAsTextureView(binding); mBindGroups[index]->GetBindingAsTextureView(binding);
ToBackend(view->GetTexture()) ToBackend(view->GetTexture())
@ -204,13 +203,9 @@ namespace dawn_native { namespace vulkan {
break; break;
} }
case wgpu::BindingType::Sampler: case BindingInfoType::Sampler:
case wgpu::BindingType::ComparisonSampler:
// Don't require barriers. // Don't require barriers.
break; break;
case wgpu::BindingType::Undefined:
UNREACHABLE();
} }
} }
} }

View File

@ -414,13 +414,19 @@ TEST_F(StorageTextureValidationTests, UnsupportedTextureViewDimensionInBindGroup
// render and compute pipeline, the binding type in the bind group layout must match the // render and compute pipeline, the binding type in the bind group layout must match the
// declaration in the shader. // declaration in the shader.
TEST_F(StorageTextureValidationTests, BindGroupLayoutEntryTypeMatchesShaderDeclaration) { TEST_F(StorageTextureValidationTests, BindGroupLayoutEntryTypeMatchesShaderDeclaration) {
constexpr std::array<wgpu::BindingType, 7> kSupportedBindingTypes = {
wgpu::BindingType::UniformBuffer, wgpu::BindingType::StorageBuffer,
wgpu::BindingType::ReadonlyStorageBuffer, wgpu::BindingType::Sampler,
wgpu::BindingType::SampledTexture, wgpu::BindingType::ReadonlyStorageTexture,
wgpu::BindingType::WriteonlyStorageTexture};
constexpr wgpu::TextureFormat kStorageTextureFormat = wgpu::TextureFormat::R32Float; constexpr wgpu::TextureFormat kStorageTextureFormat = wgpu::TextureFormat::R32Float;
std::initializer_list<utils::BindingLayoutEntryInitializationHelper> kSupportedBindingTypes = {
{0, wgpu::ShaderStage::Compute, wgpu::BufferBindingType::Uniform},
{0, wgpu::ShaderStage::Compute, wgpu::BufferBindingType::Storage},
{0, wgpu::ShaderStage::Compute, wgpu::BufferBindingType::ReadOnlyStorage},
{0, wgpu::ShaderStage::Compute, wgpu::SamplerBindingType::Filtering},
{0, wgpu::ShaderStage::Compute, wgpu::TextureSampleType::Float},
{0, wgpu::ShaderStage::Compute, wgpu::StorageTextureAccess::ReadOnly,
kStorageTextureFormat},
{0, wgpu::ShaderStage::Compute, wgpu::StorageTextureAccess::WriteOnly,
kStorageTextureFormat}};
for (wgpu::StorageTextureAccess bindingTypeInShader : kSupportedStorageTextureAccess) { for (wgpu::StorageTextureAccess bindingTypeInShader : kSupportedStorageTextureAccess) {
// Create the compute shader with the given binding type. // Create the compute shader with the given binding type.
std::string computeShader = std::string computeShader =
@ -433,30 +439,20 @@ TEST_F(StorageTextureValidationTests, BindGroupLayoutEntryTypeMatchesShaderDecla
defaultComputePipelineDescriptor.computeStage.module = csModule; defaultComputePipelineDescriptor.computeStage.module = csModule;
defaultComputePipelineDescriptor.computeStage.entryPoint = "main"; defaultComputePipelineDescriptor.computeStage.entryPoint = "main";
// Set common fileds of bind group layout binding. for (utils::BindingLayoutEntryInitializationHelper bindingLayoutEntry :
wgpu::BindGroupLayoutEntry defaultBindGroupLayoutEntry; kSupportedBindingTypes) {
defaultBindGroupLayoutEntry.binding = 0;
defaultBindGroupLayoutEntry.visibility = wgpu::ShaderStage::Compute;
defaultBindGroupLayoutEntry.storageTextureFormat = kStorageTextureFormat;
for (wgpu::BindingType bindingTypeInBindgroupLayout : kSupportedBindingTypes) {
wgpu::ComputePipelineDescriptor computePipelineDescriptor = wgpu::ComputePipelineDescriptor computePipelineDescriptor =
defaultComputePipelineDescriptor; defaultComputePipelineDescriptor;
// Create bind group layout with different binding types. // Create bind group layout with different binding types.
wgpu::BindGroupLayoutEntry bindGroupLayoutBinding = defaultBindGroupLayoutEntry;
bindGroupLayoutBinding.type = bindingTypeInBindgroupLayout;
wgpu::BindGroupLayout bindGroupLayout = wgpu::BindGroupLayout bindGroupLayout =
utils::MakeBindGroupLayout(device, {bindGroupLayoutBinding}); utils::MakeBindGroupLayout(device, {bindingLayoutEntry});
computePipelineDescriptor.layout = computePipelineDescriptor.layout =
utils::MakeBasicPipelineLayout(device, &bindGroupLayout); utils::MakeBasicPipelineLayout(device, &bindGroupLayout);
// The binding type in the bind group layout must the same as the related image object // The binding type in the bind group layout must the same as the related image object
// declared in shader. // declared in shader.
if ((bindingTypeInBindgroupLayout == wgpu::BindingType::ReadonlyStorageTexture && if (bindingLayoutEntry.storageTexture.access == bindingTypeInShader) {
bindingTypeInShader == wgpu::StorageTextureAccess::ReadOnly) ||
(bindingTypeInBindgroupLayout == wgpu::BindingType::WriteonlyStorageTexture &&
bindingTypeInShader == wgpu::StorageTextureAccess::WriteOnly)) {
device.CreateComputePipeline(&computePipelineDescriptor); device.CreateComputePipeline(&computePipelineDescriptor);
} else { } else {
ASSERT_DEVICE_ERROR(device.CreateComputePipeline(&computePipelineDescriptor)); ASSERT_DEVICE_ERROR(device.CreateComputePipeline(&computePipelineDescriptor));