[dawn][native] Introduce new `TexelBuffer` binding
* Extended binding info, shader modules, and pipeline layout tracking
for texel buffers.
* Stub backend handling across D3D, Metal, OpenGL and Vulkan.
Bug: 382544164
Change-Id: I0c32ac0e848ddacfb2cf477e636e92c95aecd5c1
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/256995
Reviewed-by: Loko Kung <lokokung@google.com>
Reviewed-by: Diego Rodrigues <diejorarr@gmail.com>
Commit-Queue: Diego Rodrigues <diejorarr@gmail.com>
diff --git a/src/dawn/native/BindGroup.cpp b/src/dawn/native/BindGroup.cpp
index 6c7d65e..3075b45 100644
--- a/src/dawn/native/BindGroup.cpp
+++ b/src/dawn/native/BindGroup.cpp
@@ -47,6 +47,7 @@
#include "dawn/native/ObjectBase.h"
#include "dawn/native/ObjectType_autogen.h"
#include "dawn/native/Sampler.h"
+#include "dawn/native/TexelBufferView.h"
#include "dawn/native/Texture.h"
#include "dawn/native/utils/WGPUHelpers.h"
@@ -315,6 +316,32 @@
return {};
}
+MaybeError ValidateTexelBufferBinding(DeviceBase* device,
+ const BindGroupEntry& entry,
+ const TexelBufferBindingEntry* texelBufferBindingEntry,
+ const TexelBufferBindingInfo& layout,
+ UsageValidationMode mode) {
+ DAWN_INVALID_IF(
+ entry.buffer != nullptr || entry.sampler != nullptr || entry.textureView != nullptr,
+ "Expected only texelBufferView to be set for binding entry.");
+
+ DAWN_TRY(device->ValidateObject(texelBufferBindingEntry->texelBufferView));
+
+ BufferBase* buffer = texelBufferBindingEntry->texelBufferView->GetBuffer();
+ DAWN_TRY(ValidateCanUseAs(buffer, wgpu::BufferUsage::TexelBuffer));
+
+ DAWN_INVALID_IF(texelBufferBindingEntry->texelBufferView->GetFormat() != layout.format,
+ "Format (%s) of %s expected to be (%s).",
+ texelBufferBindingEntry->texelBufferView->GetFormat(),
+ texelBufferBindingEntry->texelBufferView, layout.format);
+
+ if (layout.access == wgpu::TexelBufferAccess::ReadWrite) {
+ DAWN_TRY(ValidateCanUseAs(buffer, wgpu::BufferUsage::Storage));
+ }
+
+ return {};
+}
+
MaybeError ValidateSamplerBinding(const DeviceBase* device,
const BindGroupEntry& entry,
const SamplerBindingInfo& layout) {
@@ -569,9 +596,10 @@
// TODO(42240282): Store external textures in
// BindGroupLayoutBase::BindingDataPointers::bindings so checking external textures can
// be moved in the switch below.
+ UnpackedPtr<BindGroupEntry> unpacked;
+ DAWN_TRY_ASSIGN(unpacked, ValidateAndUnpack(&entry));
+
if (layout->GetExternalTextureBindingExpansionMap().contains(binding)) {
- UnpackedPtr<BindGroupEntry> unpacked;
- DAWN_TRY_ASSIGN(unpacked, ValidateAndUnpack(&entry));
if (auto* externalTextureBindingEntry = unpacked.Get<ExternalTextureBindingEntry>()) {
DAWN_TRY(ValidateExternalTextureBinding(
device, entry, externalTextureBindingEntry,
@@ -590,7 +618,12 @@
"entry.",
i);
}
- DAWN_INVALID_IF(entry.nextInChain != nullptr, "nextInChain must be nullptr.");
+
+ const TexelBufferBindingEntry* texelBufferEntry = unpacked.Get<TexelBufferBindingEntry>();
+ DAWN_INVALID_IF(
+ texelBufferEntry != nullptr &&
+ !std::holds_alternative<TexelBufferBindingInfo>(bindingInfo.bindingLayout),
+ "nextInChain must be nullptr.");
// Perform binding-type specific validation.
DAWN_TRY(MatchVariant(
@@ -622,6 +655,20 @@
i, layout);
return {};
},
+ [&](const TexelBufferBindingInfo& layout) -> MaybeError {
+ if (texelBufferEntry) {
+ DAWN_TRY_CONTEXT(
+ ValidateTexelBufferBinding(device, entry, texelBufferEntry, layout, mode),
+ "validating entries[%u] as a Texel Buffer."
+ "\nExpected entry layout: %s",
+ i, layout);
+ return {};
+ }
+ return DAWN_VALIDATION_ERROR(
+ "entries[%u] not a TexelBuffer when the layout contains an TexelBuffer "
+ "entry.",
+ i);
+ },
[&](const SamplerBindingInfo& layout) -> MaybeError {
DAWN_TRY_CONTEXT(ValidateSamplerBinding(device, entry, layout),
"validating entries[%u] as a Sampler."
@@ -774,6 +821,12 @@
continue;
}
+ if (auto* texelBufferBindingEntry = entry.Get<TexelBufferBindingEntry>()) {
+ DAWN_ASSERT(mBindingData.bindings[bindingIndex] == nullptr);
+ mBindingData.bindings[bindingIndex] = texelBufferBindingEntry->texelBufferView;
+ continue;
+ }
+
// Here we unpack external texture bindings into multiple additional bindings for the
// external texture's contents. New binding locations previously determined in the bind
// group layout are created in this bind group and filled with the external texture's
@@ -957,6 +1010,15 @@
mBindingData.bufferData[bindingIndex].size};
}
+TexelBufferViewBase* BindGroupBase::GetBindingAsTexelBufferView(BindingIndex bindingIndex) {
+ DAWN_ASSERT(!IsError());
+ const BindGroupLayoutInternalBase* layout = GetLayout();
+ DAWN_ASSERT(bindingIndex < layout->GetBindingCount());
+ DAWN_ASSERT(std::holds_alternative<TexelBufferBindingInfo>(
+ layout->GetBindingInfo(bindingIndex).bindingLayout));
+ return static_cast<TexelBufferViewBase*>(mBindingData.bindings[bindingIndex].Get());
+}
+
const std::vector<Ref<ExternalTextureBase>>& BindGroupBase::GetBoundExternalTextures() const {
DAWN_ASSERT(!IsError());
return mBoundExternalTextures;
diff --git a/src/dawn/native/BindGroup.h b/src/dawn/native/BindGroup.h
index e98e948..006e143 100644
--- a/src/dawn/native/BindGroup.h
+++ b/src/dawn/native/BindGroup.h
@@ -80,6 +80,7 @@
SamplerBase* GetBindingAsSampler(BindingIndex bindingIndex) const;
TextureViewBase* GetBindingAsTextureView(BindingIndex bindingIndex);
BufferBinding GetBindingAsBufferBinding(BindingIndex bindingIndex);
+ TexelBufferViewBase* GetBindingAsTexelBufferView(BindingIndex bindingIndex);
const ityp::span<uint32_t, uint64_t>& GetUnverifiedBufferSizes() const;
const std::vector<Ref<ExternalTextureBase>>& GetBoundExternalTextures() const;
diff --git a/src/dawn/native/BindGroupLayoutInternal.cpp b/src/dawn/native/BindGroupLayoutInternal.cpp
index 5d490ab..6a79e85 100644
--- a/src/dawn/native/BindGroupLayoutInternal.cpp
+++ b/src/dawn/native/BindGroupLayoutInternal.cpp
@@ -512,22 +512,7 @@
} else if (binding->storageTexture.access != wgpu::StorageTextureAccess::BindingNotUsed) {
bindingInfo.bindingLayout = StorageTextureBindingInfo::From(binding->storageTexture);
} else if (auto* texelBufferLayout = binding.Get<TexelBufferBindingLayout>()) {
- // TODO(382544164): Prototype texel buffer feature.
- // Placeholder implementation for `TexelBufferBindingLayout` from `TexelBufferBindingInfo`.
- BufferBindingInfo bufferInfo{};
- switch (texelBufferLayout->access) {
- case wgpu::TexelBufferAccess::ReadOnly:
- bufferInfo.type = wgpu::BufferBindingType::ReadOnlyStorage;
- break;
- case wgpu::TexelBufferAccess::ReadWrite:
- bufferInfo.type = wgpu::BufferBindingType::Storage;
- break;
- default:
- DAWN_UNREACHABLE();
- }
- bufferInfo.minBindingSize = 0;
- bufferInfo.hasDynamicOffset = false;
- bindingInfo.bindingLayout = bufferInfo;
+ bindingInfo.bindingLayout = TexelBufferBindingInfo::From(*texelBufferLayout);
} else if (auto* staticSamplerBindingLayout = binding.Get<StaticSamplerBindingLayout>()) {
bindingInfo.bindingLayout = StaticSamplerBindingInfo::From(*staticSamplerBindingLayout);
} else {
@@ -706,6 +691,7 @@
mNeedsCrossBindingValidation = true;
}
},
+ [&](const TexelBufferBindingInfo&) { counts[Order_TexelBuffer]++; },
[&](const InputAttachmentBindingInfo&) { counts[Order_InputAttachment]++; });
}
@@ -753,6 +739,7 @@
[&](const StorageTextureBindingInfo&) { return Order_StorageTexture; },
[&](const SamplerBindingInfo&) { return Order_RegularSampler; },
[&](const StaticSamplerBindingInfo&) { return Order_StaticSampler; },
+ [&](const TexelBufferBindingInfo&) { return Order_TexelBuffer; },
[&](const InputAttachmentBindingInfo&) { return Order_InputAttachment; });
};
@@ -876,6 +863,9 @@
recorder.Record(BindingInfoType::StorageTexture, layout.access, layout.format,
layout.viewDimension);
},
+ [&](const TexelBufferBindingInfo& layout) {
+ recorder.Record(BindingInfoType::TexelBuffer, layout.format, layout.access);
+ },
[&](const StaticSamplerBindingInfo& layout) {
recorder.Record(BindingInfoType::StaticSampler, layout.sampler->GetContentHash());
},
@@ -961,6 +951,10 @@
GetBindingTypeEnd(Order_StorageTexture));
}
+BeginEndRange<BindingIndex> BindGroupLayoutInternalBase::GetTexelBufferIndices() const {
+ return Range(GetBindingTypeStart(Order_TexelBuffer), GetBindingTypeEnd(Order_TexelBuffer));
+}
+
BeginEndRange<BindingIndex> BindGroupLayoutInternalBase::GetSampledTextureIndices() const {
return Range(GetBindingTypeStart(Order_SampledTexture),
GetBindingTypeEnd(Order_SampledTexture));
diff --git a/src/dawn/native/BindGroupLayoutInternal.h b/src/dawn/native/BindGroupLayoutInternal.h
index a3b6cf3..496b6df 100644
--- a/src/dawn/native/BindGroupLayoutInternal.h
+++ b/src/dawn/native/BindGroupLayoutInternal.h
@@ -101,6 +101,7 @@
BeginEndRange<BindingIndex> GetDynamicBufferIndices() const;
BeginEndRange<BindingIndex> GetBufferIndices() const;
BeginEndRange<BindingIndex> GetStorageTextureIndices() const;
+ BeginEndRange<BindingIndex> GetTexelBufferIndices() const;
BeginEndRange<BindingIndex> GetSampledTextureIndices() const;
BeginEndRange<BindingIndex> GetTextureIndices() const;
BeginEndRange<BindingIndex> GetSamplerIndices() const;
@@ -196,6 +197,8 @@
// Samplers
Order_StaticSampler,
Order_RegularSampler,
+ // Texel Buffers
+ Order_TexelBuffer,
Order_Count,
};
static bool SortBindingsCompare(const BindingInfo& a, const BindingInfo& b);
diff --git a/src/dawn/native/BindingInfo.cpp b/src/dawn/native/BindingInfo.cpp
index 97ff4ee..4a2ccde 100644
--- a/src/dawn/native/BindingInfo.cpp
+++ b/src/dawn/native/BindingInfo.cpp
@@ -46,6 +46,9 @@
[](const StorageTextureBindingInfo&) -> BindingInfoType {
return BindingInfoType::StorageTexture;
},
+ [](const TexelBufferBindingInfo&) -> BindingInfoType {
+ return BindingInfoType::TexelBuffer;
+ },
[](const StaticSamplerBindingInfo&) -> BindingInfoType {
return BindingInfoType::StaticSampler;
},
@@ -323,6 +326,17 @@
}};
}
+// TexelBufferBindingInfo
+
+// static
+TexelBufferBindingInfo TexelBufferBindingInfo::From(const TexelBufferBindingLayout& layout) {
+ TexelBufferBindingLayout defaultedLayout = layout.WithTrivialFrontendDefaults();
+ return {{
+ .format = defaultedLayout.format,
+ .access = defaultedLayout.access,
+ }};
+}
+
// StorageTextureBindingInfo
// static
diff --git a/src/dawn/native/BindingInfo.h b/src/dawn/native/BindingInfo.h
index 4b51171..451f343 100644
--- a/src/dawn/native/BindingInfo.h
+++ b/src/dawn/native/BindingInfo.h
@@ -63,6 +63,7 @@
Sampler,
Texture,
StorageTexture,
+ TexelBuffer,
ExternalTexture,
StaticSampler,
// Internal to vulkan only.
@@ -102,6 +103,15 @@
};
#undef STORAGE_TEXTURE_BINDING_INFO_MEMBER
+// A mirror of wgpu::TexelBufferBindingLayout for use inside dawn::native.
+#define TEXEL_BUFFER_BINDING_INFO_MEMBER(X) \
+ X(wgpu::TextureFormat, format) \
+ X(wgpu::TexelBufferAccess, access)
+DAWN_SERIALIZABLE(struct, TexelBufferBindingInfo, TEXEL_BUFFER_BINDING_INFO_MEMBER) {
+ static TexelBufferBindingInfo From(const TexelBufferBindingLayout& layout);
+};
+#undef TEXEL_BUFFER_BINDING_INFO_MEMBER
+
// A mirror of wgpu::SamplerBindingLayout for use inside dawn::native.
#define SAMPLER_BINDING_INFO_MEMBER(X) \
/* For shader reflection NonFiltering is never used and Filtering is used for */ \
@@ -149,6 +159,7 @@
std::variant<BufferBindingInfo,
SamplerBindingInfo,
TextureBindingInfo,
+ TexelBufferBindingInfo,
StorageTextureBindingInfo,
StaticSamplerBindingInfo,
InputAttachmentBindingInfo>
diff --git a/src/dawn/native/PassResourceUsageTracker.cpp b/src/dawn/native/PassResourceUsageTracker.cpp
index 89f07f8..cc99ace 100644
--- a/src/dawn/native/PassResourceUsageTracker.cpp
+++ b/src/dawn/native/PassResourceUsageTracker.cpp
@@ -36,6 +36,7 @@
#include "dawn/native/ExternalTexture.h"
#include "dawn/native/Format.h"
#include "dawn/native/QuerySet.h"
+#include "dawn/native/TexelBufferView.h"
#include "dawn/native/Texture.h"
namespace dawn::native {
@@ -198,6 +199,27 @@
TextureViewUsedAs(view, usage, bindingInfo.visibility);
}
+ for (BindingIndex i : layout->GetTexelBufferIndices()) {
+ const BindingInfo& bindingInfo = group->GetLayout()->GetBindingInfo(i);
+ const TexelBufferBindingInfo& texelInfo =
+ std::get<TexelBufferBindingInfo>(bindingInfo.bindingLayout);
+
+ wgpu::BufferUsage usage = wgpu::BufferUsage::None;
+ switch (texelInfo.access) {
+ case wgpu::TexelBufferAccess::ReadOnly:
+ usage = kReadOnlyTexelBuffer;
+ break;
+ case wgpu::TexelBufferAccess::ReadWrite:
+ usage = wgpu::BufferUsage::Storage;
+ break;
+ case wgpu::TexelBufferAccess::Undefined:
+ DAWN_UNREACHABLE();
+ }
+
+ BufferBase* buffer = group->GetBindingAsTexelBufferView(i)->GetBuffer();
+ BufferUsedAs(buffer, usage, bindingInfo.visibility);
+ }
+
for (const Ref<ExternalTextureBase>& externalTexture : group->GetBoundExternalTextures()) {
mExternalTextureUsages.insert(externalTexture.Get());
}
@@ -263,6 +285,10 @@
mUsage.referencedTextures.insert(group->GetBindingAsTextureView(i)->GetTexture());
}
+ for (BindingIndex i : layout->GetTexelBufferIndices()) {
+ mUsage.referencedBuffers.insert(group->GetBindingAsTexelBufferView(i)->GetBuffer());
+ }
+
for (const Ref<ExternalTextureBase>& externalTexture : group->GetBoundExternalTextures()) {
mUsage.referencedExternalTextures.insert(externalTexture.Get());
}
diff --git a/src/dawn/native/PipelineLayout.cpp b/src/dawn/native/PipelineLayout.cpp
index 23a4ab8..ca7a55e 100644
--- a/src/dawn/native/PipelineLayout.cpp
+++ b/src/dawn/native/PipelineLayout.cpp
@@ -29,6 +29,7 @@
#include <algorithm>
#include <map>
+#include <memory>
#include <utility>
#include "absl/container/inlined_vector.h"
@@ -274,9 +275,12 @@
};
// Does the trivial conversions from a ShaderBindingInfo to a BindGroupLayoutEntry
+ std::vector<std::unique_ptr<wgpu::TexelBufferBindingLayout>> texelBufferLayouts;
+
auto ConvertMetadataToEntry =
- [](const ShaderBindingInfo& shaderBinding,
- const ExternalTextureBindingLayout* externalTextureBindingEntry) -> EntryData {
+ [&texelBufferLayouts](
+ BindGroupIndex /*group*/, const ShaderBindingInfo& shaderBinding,
+ const ExternalTextureBindingLayout* externalTextureBindingEntry) -> EntryData {
EntryData entry = {};
entry.bindingArraySize = uint32_t(shaderBinding.arraySize);
@@ -303,6 +307,13 @@
entry.storageTexture.format = bindingInfo.format;
entry.storageTexture.viewDimension = bindingInfo.viewDimension;
},
+ [&](const TexelBufferBindingInfo& bindingInfo) {
+ auto layout = std::make_unique<wgpu::TexelBufferBindingLayout>();
+ layout->format = bindingInfo.format;
+ layout->access = bindingInfo.access;
+ texelBufferLayouts.push_back(std::move(layout));
+ entry.nextInChain = texelBufferLayouts.back().get();
+ },
[&](const ExternalTextureBindingInfo&) {
entry.nextInChain = externalTextureBindingEntry;
},
@@ -373,7 +384,7 @@
for (const auto& [bindingNumber, shaderBinding] : groupBindings) {
// Create the BindGroupLayoutEntry
EntryData entry =
- ConvertMetadataToEntry(shaderBinding, &externalTextureBindingLayout);
+ ConvertMetadataToEntry(group, shaderBinding, &externalTextureBindingLayout);
entry.binding = uint32_t(bindingNumber);
entry.visibility = StageBit(stage.shaderStage);
diff --git a/src/dawn/native/ShaderModule.cpp b/src/dawn/native/ShaderModule.cpp
index c54ee5d..c81e0fd 100644
--- a/src/dawn/native/ShaderModule.cpp
+++ b/src/dawn/native/ShaderModule.cpp
@@ -89,6 +89,9 @@
case tint::inspector::ResourceBinding::ResourceType::kReadOnlyStorageTexture:
case tint::inspector::ResourceBinding::ResourceType::kReadWriteStorageTexture:
return BindingInfoType::StorageTexture;
+ case tint::inspector::ResourceBinding::ResourceType::kReadOnlyTexelBuffer:
+ case tint::inspector::ResourceBinding::ResourceType::kReadWriteTexelBuffer:
+ return BindingInfoType::TexelBuffer;
case tint::inspector::ResourceBinding::ResourceType::kExternalTexture:
return BindingInfoType::ExternalTexture;
case tint::inspector::ResourceBinding::ResourceType::kInputAttachment:
@@ -291,6 +294,19 @@
DAWN_UNREACHABLE();
}
+ResultOrError<wgpu::TexelBufferAccess> TintResourceTypeToTexelBufferAccess(
+ tint::inspector::ResourceBinding::ResourceType resource_type) {
+ switch (resource_type) {
+ case tint::inspector::ResourceBinding::ResourceType::kReadOnlyTexelBuffer:
+ return wgpu::TexelBufferAccess::ReadOnly;
+ case tint::inspector::ResourceBinding::ResourceType::kReadWriteTexelBuffer:
+ return wgpu::TexelBufferAccess::ReadWrite;
+ default:
+ return DAWN_VALIDATION_ERROR("Attempted to convert non-texel buffer resource type");
+ }
+ DAWN_UNREACHABLE();
+}
+
ResultOrError<InterStageComponentType> TintComponentTypeToInterStageComponentType(
tint::inspector::ComponentType type) {
switch (type) {
@@ -576,6 +592,7 @@
[](const SamplerBindingInfo&) { return BindingInfoType::Sampler; },
[](const TextureBindingInfo&) { return BindingInfoType::Texture; },
[](const StorageTextureBindingInfo&) { return BindingInfoType::StorageTexture; },
+ [](const TexelBufferBindingInfo&) { return BindingInfoType::TexelBuffer; },
[](const ExternalTextureBindingInfo&) { return BindingInfoType::ExternalTexture; },
[](const InputAttachmentBindingInfo&) { return BindingInfoType::InputAttachment; });
}
@@ -697,6 +714,23 @@
bindingLayout.viewDimension, bindingInfo.viewDimension);
return {};
},
+ [&](const TexelBufferBindingInfo& bindingInfo) -> MaybeError {
+ const TexelBufferBindingInfo& bindingLayout =
+ std::get<TexelBufferBindingInfo>(layoutInfo.bindingLayout);
+ DAWN_ASSERT(bindingLayout.format != wgpu::TextureFormat::Undefined);
+ DAWN_ASSERT(bindingInfo.format != wgpu::TextureFormat::Undefined);
+
+ DAWN_INVALID_IF(bindingLayout.access != bindingInfo.access,
+ "The layout's binding access (%s) doesn't match the shader's binding "
+ "access (%s).",
+ bindingLayout.access, bindingInfo.access);
+
+ DAWN_INVALID_IF(bindingLayout.format != bindingInfo.format,
+ "The layout's binding format (%s) doesn't match the shader's binding "
+ "format (%s).",
+ bindingLayout.format, bindingInfo.format);
+ return {};
+ },
[&](const BufferBindingInfo& bindingInfo) -> MaybeError {
const BufferBindingInfo& bindingLayout =
std::get<BufferBindingInfo>(layoutInfo.bindingLayout);
@@ -1203,6 +1237,16 @@
break;
}
+ case BindingInfoType::TexelBuffer: {
+ TexelBufferBindingInfo bindingInfo = {};
+ DAWN_TRY_ASSIGN(bindingInfo.access,
+ TintResourceTypeToTexelBufferAccess(resource.resource_type));
+ bindingInfo.format = TintImageFormatToTextureFormat(resource.image_format);
+
+ info.bindingInfo = bindingInfo;
+ break;
+ }
+
case BindingInfoType::ExternalTexture: {
info.bindingInfo.emplace<ExternalTextureBindingInfo>();
break;
diff --git a/src/dawn/native/ShaderModule.h b/src/dawn/native/ShaderModule.h
index fa70634..2fa5c26 100644
--- a/src/dawn/native/ShaderModule.h
+++ b/src/dawn/native/ShaderModule.h
@@ -188,6 +188,7 @@
SamplerBindingInfo,
TextureBindingInfo,
StorageTextureBindingInfo,
+ TexelBufferBindingInfo,
ExternalTextureBindingInfo,
InputAttachmentBindingInfo>;
#define SHADER_BINDING_INFO_MEMBER(X) \
diff --git a/src/dawn/native/d3d11/BindGroupTrackerD3D11.cpp b/src/dawn/native/d3d11/BindGroupTrackerD3D11.cpp
index 1107aed..ed1b534 100644
--- a/src/dawn/native/d3d11/BindGroupTrackerD3D11.cpp
+++ b/src/dawn/native/d3d11/BindGroupTrackerD3D11.cpp
@@ -616,6 +616,12 @@
}
return {};
},
+ [&](const TexelBufferBindingInfo&) -> MaybeError {
+ // D3D11 does not support texel buffers.
+ // TODO(crbug/382544164): Prototype texel buffer feature
+ DAWN_UNREACHABLE();
+ return {};
+ },
[](const InputAttachmentBindingInfo&) -> MaybeError {
DAWN_UNREACHABLE();
return {};
@@ -689,6 +695,11 @@
DAWN_UNREACHABLE();
}
},
+ [&](const TexelBufferBindingInfo&) {
+ // D3D11 does not support texel buffers.
+ // TODO(crbug/382544164): Prototype texel buffer feature
+ DAWN_UNREACHABLE();
+ },
[](const InputAttachmentBindingInfo&) { DAWN_UNREACHABLE(); });
}
}
@@ -815,6 +826,12 @@
DAWN_UNREACHABLE();
return {};
},
+ [](const TexelBufferBindingInfo&) -> MaybeError {
+ // D3D11 does not support texel buffers.
+ // TODO(crbug/382544164): Prototype texel buffer feature
+ DAWN_UNREACHABLE();
+ return {};
+ },
[](const InputAttachmentBindingInfo&) -> MaybeError {
DAWN_UNREACHABLE();
return {};
diff --git a/src/dawn/native/d3d11/PipelineLayoutD3D11.cpp b/src/dawn/native/d3d11/PipelineLayoutD3D11.cpp
index 744766c..d283841 100644
--- a/src/dawn/native/d3d11/PipelineLayoutD3D11.cpp
+++ b/src/dawn/native/d3d11/PipelineLayoutD3D11.cpp
@@ -133,6 +133,12 @@
}
return kInvalidSlots;
},
+ [&](const TexelBufferBindingInfo&) -> PerStage<uint32_t> {
+ // D3D11 does not support texel buffers.
+ // TODO(crbug/382544164): Prototype texel buffer feature
+ DAWN_UNREACHABLE();
+ return kInvalidSlots;
+ },
[&](const InputAttachmentBindingInfo&) -> PerStage<uint32_t> {
DAWN_UNREACHABLE();
return kInvalidSlots;
diff --git a/src/dawn/native/d3d12/BindGroupD3D12.cpp b/src/dawn/native/d3d12/BindGroupD3D12.cpp
index 22dbf99..104d096 100644
--- a/src/dawn/native/d3d12/BindGroupD3D12.cpp
+++ b/src/dawn/native/d3d12/BindGroupD3D12.cpp
@@ -200,6 +200,11 @@
DAWN_UNREACHABLE();
}
},
+ [&](const TexelBufferBindingInfo&) {
+ // D3D12 does not support texel buffers.
+ // TODO(crbug/382544164): Prototype texel buffer feature
+ DAWN_UNREACHABLE();
+ },
[](const StaticSamplerBindingInfo&) {
// Static samplers are already initialized in the pipeline layout.
},
diff --git a/src/dawn/native/d3d12/BindGroupLayoutD3D12.cpp b/src/dawn/native/d3d12/BindGroupLayoutD3D12.cpp
index 9441520..e2a6615 100644
--- a/src/dawn/native/d3d12/BindGroupLayoutD3D12.cpp
+++ b/src/dawn/native/d3d12/BindGroupLayoutD3D12.cpp
@@ -79,6 +79,12 @@
DAWN_UNREACHABLE();
}
},
+ [](const TexelBufferBindingInfo&) -> D3D12_DESCRIPTOR_RANGE_TYPE {
+ // D3D12 does not support texel buffers.
+ // TODO(crbug/382544164): Prototype texel buffer feature
+ DAWN_UNREACHABLE();
+ return D3D12_DESCRIPTOR_RANGE_TYPE_SRV;
+ },
[](const InputAttachmentBindingInfo&) -> D3D12_DESCRIPTOR_RANGE_TYPE {
DAWN_UNREACHABLE();
return D3D12_DESCRIPTOR_RANGE_TYPE_SRV;
@@ -193,6 +199,12 @@
[](const StorageTextureBindingInfo&) -> D3D12_DESCRIPTOR_RANGE_FLAGS {
return D3D12_DESCRIPTOR_RANGE_FLAG_DATA_VOLATILE;
},
+ [](const TexelBufferBindingInfo&) -> D3D12_DESCRIPTOR_RANGE_FLAGS {
+ // D3D12 does not support texel buffers.
+ // TODO(crbug/382544164): Prototype texel buffer feature
+ DAWN_UNREACHABLE();
+ return D3D12_DESCRIPTOR_RANGE_FLAG_DATA_VOLATILE;
+ },
[](const InputAttachmentBindingInfo&) -> D3D12_DESCRIPTOR_RANGE_FLAGS {
DAWN_UNREACHABLE();
return D3D12_DESCRIPTOR_RANGE_FLAG_DATA_VOLATILE;
diff --git a/src/dawn/native/metal/BindGroupLayoutMTL.mm b/src/dawn/native/metal/BindGroupLayoutMTL.mm
index 4bf029f..b5eb201 100644
--- a/src/dawn/native/metal/BindGroupLayoutMTL.mm
+++ b/src/dawn/native/metal/BindGroupLayoutMTL.mm
@@ -76,6 +76,7 @@
},
[&](const TextureBindingInfo&) { desc.dataType = MTLDataTypeTexture; },
[&](const StorageTextureBindingInfo&) { DAWN_CHECK(false); },
+ [&](const TexelBufferBindingInfo&) { DAWN_CHECK(false); },
[](const InputAttachmentBindingInfo&) { DAWN_CHECK(false); });
descriptors.push_back(desc);
diff --git a/src/dawn/native/metal/BindGroupMTL.mm b/src/dawn/native/metal/BindGroupMTL.mm
index 894967a..e79f2a3 100644
--- a/src/dawn/native/metal/BindGroupMTL.mm
+++ b/src/dawn/native/metal/BindGroupMTL.mm
@@ -103,6 +103,11 @@
},
[&](const TextureBindingInfo&) { HandleTextureBinding(); },
[&](const StorageTextureBindingInfo&) { HandleTextureBinding(); },
+ [&](const TexelBufferBindingInfo&) {
+ // Metal does not support texel buffers.
+ // TODO(crbug/382544164): Prototype texel buffer feature
+ DAWN_CHECK(false);
+ },
[](const InputAttachmentBindingInfo&) { DAWN_CHECK(false); });
}
diff --git a/src/dawn/native/metal/CommandBufferMTL.mm b/src/dawn/native/metal/CommandBufferMTL.mm
index 8e935c8..ce91b34 100644
--- a/src/dawn/native/metal/CommandBufferMTL.mm
+++ b/src/dawn/native/metal/CommandBufferMTL.mm
@@ -824,6 +824,11 @@
},
[&](const TextureBindingInfo&) { HandleTextureBinding(); },
[&](const StorageTextureBindingInfo&) { HandleTextureBinding(); },
+ [&](const TexelBufferBindingInfo&) {
+ // Metal does not support texel buffers.
+ // TODO(crbug/382544164): Prototype texel buffer feature
+ DAWN_UNREACHABLE();
+ },
[](const InputAttachmentBindingInfo&) { DAWN_UNREACHABLE(); });
}
}
@@ -853,6 +858,11 @@
},
[&](const TextureBindingInfo&) {}, //
[&](const StorageTextureBindingInfo&) {},
+ [&](const TexelBufferBindingInfo&) {
+ // Metal does not support texel buffers.
+ // TODO(crbug/382544164): Prototype texel buffer feature
+ DAWN_CHECK(false);
+ },
[](const InputAttachmentBindingInfo&) { DAWN_CHECK(false); });
}
diff --git a/src/dawn/native/metal/PipelineLayoutMTL.mm b/src/dawn/native/metal/PipelineLayoutMTL.mm
index 323819a..ecb671f 100644
--- a/src/dawn/native/metal/PipelineLayoutMTL.mm
+++ b/src/dawn/native/metal/PipelineLayoutMTL.mm
@@ -78,6 +78,11 @@
mIndexInfo[stage][group][bindingIndex] = textureIndex;
textureIndex++;
},
+ [&](const TexelBufferBindingInfo&) {
+ // Metal does not support texel buffers.
+ // TODO(crbug/382544164): Prototype texel buffer feature
+ DAWN_UNREACHABLE();
+ },
[&](const StaticSamplerBindingInfo&) {
// Static samplers are handled in the frontend.
// TODO(crbug.com/dawn/2482): Implement static samplers in the
diff --git a/src/dawn/native/metal/ShaderModuleMTL.mm b/src/dawn/native/metal/ShaderModuleMTL.mm
index dfa18ab..479e81c 100644
--- a/src/dawn/native/metal/ShaderModuleMTL.mm
+++ b/src/dawn/native/metal/ShaderModuleMTL.mm
@@ -192,6 +192,11 @@
[&](const StorageTextureBindingInfo& bindingInfo) {
bindings.storage_texture.emplace(srcBindingPoint, dstBindingPoint);
},
+ [&](const TexelBufferBindingInfo& bindingInfo) {
+ // Metal does not support texel buffers.
+ // TODO(crbug/382544164): Prototype texel buffer feature
+ DAWN_UNREACHABLE();
+ },
[&](const ExternalTextureBindingInfo& bindingInfo) {
const auto& etBindingMap = bgl->GetExternalTextureBindingExpansionMap();
const auto& expansion = etBindingMap.find(binding);
@@ -261,7 +266,7 @@
},
[&](const SamplerBindingInfo& bindingInfo) {},
[&](const StaticSamplerBindingInfo& bindingInfo) {},
- [&](const TextureBindingInfo& bindingInfo) {},
+ [&](const TextureBindingInfo& bindingInfo) {}, [](const TexelBufferBindingInfo&) {},
[&](const StorageTextureBindingInfo& bindingInfo) {},
[](const InputAttachmentBindingInfo&) { DAWN_CHECK(false); });
}
diff --git a/src/dawn/native/opengl/CommandBufferGL.cpp b/src/dawn/native/opengl/CommandBufferGL.cpp
index 03b29c0..5ac27fa 100644
--- a/src/dawn/native/opengl/CommandBufferGL.cpp
+++ b/src/dawn/native/opengl/CommandBufferGL.cpp
@@ -487,6 +487,12 @@
texture->GetGLFormat().internalFormat));
return {};
},
+ [&](const TexelBufferBindingInfo&) -> MaybeError {
+ // OpenGL does not support texel buffers.
+ // TODO(crbug/382544164): Prototype texel buffer feature
+ DAWN_UNREACHABLE();
+ return {};
+ },
[](const InputAttachmentBindingInfo&) -> MaybeError { DAWN_UNREACHABLE(); }));
}
diff --git a/src/dawn/native/opengl/PipelineLayoutGL.cpp b/src/dawn/native/opengl/PipelineLayoutGL.cpp
index 02718c3..274f988 100644
--- a/src/dawn/native/opengl/PipelineLayoutGL.cpp
+++ b/src/dawn/native/opengl/PipelineLayoutGL.cpp
@@ -84,6 +84,11 @@
mIndexInfo[group][bindingIndex] = storageTextureIndex;
storageTextureIndex++;
},
+ [&](const TexelBufferBindingInfo&) {
+ // OpenGL does not support texel buffers.
+ // TODO(crbug/382544164): Prototype texel buffer feature
+ DAWN_UNREACHABLE();
+ },
[](const InputAttachmentBindingInfo&) { DAWN_UNREACHABLE(); });
}
}
diff --git a/src/dawn/native/opengl/ShaderModuleGL.cpp b/src/dawn/native/opengl/ShaderModuleGL.cpp
index 41ec8ed..8693f67 100644
--- a/src/dawn/native/opengl/ShaderModuleGL.cpp
+++ b/src/dawn/native/opengl/ShaderModuleGL.cpp
@@ -275,7 +275,7 @@
},
[](const StaticSamplerBindingInfo&) {}, [](const SamplerBindingInfo&) {},
[](const TextureBindingInfo&) {}, [](const StorageTextureBindingInfo&) {},
- [](const InputAttachmentBindingInfo&) {});
+ [](const TexelBufferBindingInfo&) {}, [](const InputAttachmentBindingInfo&) {});
}
}
diff --git a/src/dawn/native/vulkan/BindGroupLayoutVk.cpp b/src/dawn/native/vulkan/BindGroupLayoutVk.cpp
index d6e380d..7326af4 100644
--- a/src/dawn/native/vulkan/BindGroupLayoutVk.cpp
+++ b/src/dawn/native/vulkan/BindGroupLayoutVk.cpp
@@ -222,6 +222,12 @@
},
[](const TextureBindingInfo&) { return VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE; },
[](const StorageTextureBindingInfo&) { return VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; },
+ [](const TexelBufferBindingInfo&) {
+ // TODO(crbug/382544164): Prototype texel buffer feature
+ DAWN_UNREACHABLE();
+ return VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER;
+ },
+
[](const InputAttachmentBindingInfo&) { return VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT; });
}
diff --git a/src/dawn/native/vulkan/ShaderModuleVk.cpp b/src/dawn/native/vulkan/ShaderModuleVk.cpp
index 8a03626..844aba7 100644
--- a/src/dawn/native/vulkan/ShaderModuleVk.cpp
+++ b/src/dawn/native/vulkan/ShaderModuleVk.cpp
@@ -196,6 +196,10 @@
[&](const StorageTextureBindingInfo& bindingInfo) {
bindings.storage_texture.emplace(srcBindingPoint, dstBindingPoint);
},
+ [&](const TexelBufferBindingInfo& bindingInfo) {
+ // TODO(crbug/382544164): Prototype texel buffer feature
+ DAWN_UNREACHABLE();
+ },
[&](const ExternalTextureBindingInfo& bindingInfo) {
const auto& bindingMap = bgl->GetExternalTextureBindingExpansionMap();
const auto& expansion = bindingMap.find(binding);
diff --git a/src/dawn/native/webgpu_absl_format.cpp b/src/dawn/native/webgpu_absl_format.cpp
index 5b886af..e1c21c9 100644
--- a/src/dawn/native/webgpu_absl_format.cpp
+++ b/src/dawn/native/webgpu_absl_format.cpp
@@ -139,6 +139,9 @@
[&](const StorageTextureBindingInfo& layout) {
s->Append(absl::StrFormat("%s: %s ", BindingInfoType::StorageTexture, layout));
},
+ [&](const TexelBufferBindingInfo& layout) {
+ s->Append(absl::StrFormat("%s: %s ", BindingInfoType::TexelBuffer, layout));
+ },
[&](const InputAttachmentBindingInfo& layout) {
s->Append(absl::StrFormat("%s: %s ", BindingInfoType::InputAttachment, layout));
});
@@ -199,6 +202,22 @@
}
absl::FormatConvertResult<absl::FormatConversionCharSet::kString> AbslFormatConvert(
+ const TexelBufferBindingInfo& value,
+ const absl::FormatConversionSpec& spec,
+ absl::FormatSink* s) {
+ s->Append(absl::StrFormat("{format: %s, access: %s}", value.format, value.access));
+ return {true};
+}
+
+absl::FormatConvertResult<absl::FormatConversionCharSet::kString> AbslFormatConvert(
+ const TexelBufferBindingLayout& value,
+ const absl::FormatConversionSpec& spec,
+ absl::FormatSink* s) {
+ auto info = TexelBufferBindingInfo::From(value);
+ return AbslFormatConvert(info, spec, s);
+}
+
+absl::FormatConvertResult<absl::FormatConversionCharSet::kString> AbslFormatConvert(
const SamplerBindingInfo& value,
const absl::FormatConversionSpec& spec,
absl::FormatSink* s) {
@@ -544,6 +563,9 @@
case BindingInfoType::ExternalTexture:
s->Append("externalTexture");
break;
+ case BindingInfoType::TexelBuffer:
+ s->Append("texelBuffer");
+ break;
case BindingInfoType::StaticSampler:
s->Append("staticSampler");
break;
diff --git a/src/dawn/native/webgpu_absl_format.h b/src/dawn/native/webgpu_absl_format.h
index b8e19e1..b52b699 100644
--- a/src/dawn/native/webgpu_absl_format.h
+++ b/src/dawn/native/webgpu_absl_format.h
@@ -120,6 +120,18 @@
const absl::FormatConversionSpec& spec,
absl::FormatSink* s);
+struct TexelBufferBindingInfo;
+absl::FormatConvertResult<absl::FormatConversionCharSet::kString> AbslFormatConvert(
+ const TexelBufferBindingInfo& value,
+ const absl::FormatConversionSpec& spec,
+ absl::FormatSink* s);
+
+struct TexelBufferBindingLayout;
+absl::FormatConvertResult<absl::FormatConversionCharSet::kString> AbslFormatConvert(
+ const TexelBufferBindingLayout& value,
+ const absl::FormatConversionSpec& spec,
+ absl::FormatSink* s);
+
struct SamplerBindingInfo;
absl::FormatConvertResult<absl::FormatConversionCharSet::kString> AbslFormatConvert(
const SamplerBindingInfo& value,
diff --git a/src/dawn/tests/unittests/validation/GetBindGroupLayoutValidationTests.cpp b/src/dawn/tests/unittests/validation/GetBindGroupLayoutValidationTests.cpp
index 120f00b..cc38b5a 100644
--- a/src/dawn/tests/unittests/validation/GetBindGroupLayoutValidationTests.cpp
+++ b/src/dawn/tests/unittests/validation/GetBindGroupLayoutValidationTests.cpp
@@ -549,6 +549,35 @@
BindGroupLayoutCacheEq(pipeline.GetBindGroupLayout(0)));
}
+// Tests that the texel buffer binding type matches with a texel_buffer declared in the shader.
+TEST_F(GetBindGroupLayoutTests, TexelBufferBindingType) {
+ DAWN_SKIP_TEST_IF(UsesWire());
+
+ wgpu::TexelBufferBindingLayout layout = {};
+ layout.access = wgpu::TexelBufferAccess::ReadOnly;
+ layout.format = wgpu::TextureFormat::RGBA8Uint;
+
+ wgpu::BindGroupLayoutEntry entry = {};
+ entry.binding = 0;
+ entry.visibility = wgpu::ShaderStage::Fragment;
+ entry.nextInChain = &layout;
+
+ wgpu::BindGroupLayoutDescriptor desc = {};
+ desc.entryCount = 1;
+ desc.entries = &entry;
+
+ wgpu::RenderPipeline pipeline = RenderPipelineFromFragmentShader(R"(
+ requires texel_buffers;
+ @group(0) @binding(0) var myTexelBuffer: texel_buffer<rgba8uint, read>;
+
+ @fragment fn main() {
+ _ = textureDimensions(myTexelBuffer);
+ })");
+
+ EXPECT_THAT(device.CreateBindGroupLayout(&desc),
+ BindGroupLayoutCacheEq(pipeline.GetBindGroupLayout(0)));
+}
+
// Test that texture view dimension matches the shader.
TEST_F(GetBindGroupLayoutTests, TextureViewDimension) {
DAWN_SKIP_TEST_IF(UsesWire());
diff --git a/src/dawn/tests/unittests/validation/TexelBufferValidationTests.cpp b/src/dawn/tests/unittests/validation/TexelBufferValidationTests.cpp
index e1edd1f..94701df 100644
--- a/src/dawn/tests/unittests/validation/TexelBufferValidationTests.cpp
+++ b/src/dawn/tests/unittests/validation/TexelBufferValidationTests.cpp
@@ -142,6 +142,85 @@
EXPECT_EQ(texelEntry->texelBufferView.Get(), view.Get());
}
+// The format of a bound texel buffer view must match the layout.
+TEST_F(TexelBufferValidationTest, ViewFormatMustMatchLayout) {
+ wgpu::BufferDescriptor desc;
+ desc.size = 256;
+ desc.usage = wgpu::BufferUsage::TexelBuffer;
+ wgpu::Buffer buffer = device.CreateBuffer(&desc);
+
+ wgpu::TexelBufferViewDescriptor viewDesc = {};
+ viewDesc.format = wgpu::TextureFormat::RGBA8Uint;
+ viewDesc.offset = 0;
+ viewDesc.size = 256;
+ wgpu::TexelBufferView view = buffer.CreateTexelView(&viewDesc);
+
+ wgpu::TexelBufferBindingLayout layout = {};
+ layout.access = wgpu::TexelBufferAccess::ReadOnly;
+ layout.format = wgpu::TextureFormat::R32Uint;
+
+ wgpu::BindGroupLayout bgl =
+ utils::MakeBindGroupLayout(device, {{0, wgpu::ShaderStage::Compute, &layout}});
+
+ ASSERT_DEVICE_ERROR(utils::MakeBindGroup(device, bgl, {{0, view}}));
+}
+
+// Read-write texel buffer bindings require the buffer to also have STORAGE usage.
+TEST_F(TexelBufferValidationTest, ReadWriteBindingRequiresStorageUsage) {
+ wgpu::BufferDescriptor desc;
+ desc.size = 256;
+ desc.usage = wgpu::BufferUsage::TexelBuffer;
+ wgpu::Buffer buffer = device.CreateBuffer(&desc);
+
+ wgpu::TexelBufferViewDescriptor viewDesc = {};
+ viewDesc.format = wgpu::TextureFormat::R32Uint;
+ viewDesc.offset = 0;
+ viewDesc.size = 4;
+ wgpu::TexelBufferView view = buffer.CreateTexelView(&viewDesc);
+
+ wgpu::TexelBufferBindingLayout layout = {};
+ layout.access = wgpu::TexelBufferAccess::ReadWrite;
+ layout.format = wgpu::TextureFormat::R32Uint;
+
+ wgpu::BindGroupLayout bgl =
+ utils::MakeBindGroupLayout(device, {{0, wgpu::ShaderStage::Compute, &layout}});
+
+ ASSERT_DEVICE_ERROR(utils::MakeBindGroup(device, bgl, {{0, view}}));
+}
+
+// Binding a TexelBuffer to a texture binding slot fails.
+TEST_F(TexelBufferValidationTest, TexelBufferCannotBindToTextureSlot) {
+ wgpu::BindGroupLayoutEntry textureEntry = {};
+ textureEntry.binding = 0;
+ textureEntry.visibility = wgpu::ShaderStage::Compute;
+ textureEntry.texture.sampleType = wgpu::TextureSampleType::Float;
+ textureEntry.texture.viewDimension = wgpu::TextureViewDimension::e2D;
+
+ wgpu::BindGroupLayoutDescriptor bglDesc = {};
+ bglDesc.entryCount = 1;
+ bglDesc.entries = &textureEntry;
+ wgpu::BindGroupLayout bgl = device.CreateBindGroupLayout(&bglDesc);
+
+ wgpu::Buffer buffer = CreateTexelBuffer(4, wgpu::BufferUsage::TexelBuffer);
+ wgpu::TexelBufferViewDescriptor viewDesc = {};
+ viewDesc.format = wgpu::TextureFormat::R32Uint;
+ wgpu::TexelBufferView view = buffer.CreateTexelView(&viewDesc);
+
+ wgpu::TexelBufferBindingEntry texelEntry = {};
+ texelEntry.texelBufferView = view;
+
+ wgpu::BindGroupEntry bgEntry = {};
+ bgEntry.binding = 0;
+ bgEntry.nextInChain = &texelEntry;
+
+ wgpu::BindGroupDescriptor bgDesc = {};
+ bgDesc.layout = bgl;
+ bgDesc.entryCount = 1;
+ bgDesc.entries = &bgEntry;
+
+ ASSERT_DEVICE_ERROR(device.CreateBindGroup(&bgDesc));
+}
+
class TexelBufferValidationWithExtendedMapTest : public TexelBufferValidationTest {
protected:
void SetUp() override {