Skip to content

Commit

Permalink
Integrate Multiplanar External Texture Transform
Browse files Browse the repository at this point in the history
Introduces the majority of the logic associated with enabling
multiplanar external textures. Removes most backend logic associated
with external textures in favor of expanding them into their components
in the frontend. Includes a basic e2e test demonstrating multiplanar
YUV-to-RGB conversion.

Bug: dawn:1082
Change-Id: Ib5c042e5639b1a8efe2954680abc346c8c6c76d7
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/78248
Reviewed-by: Austin Eng <enga@chromium.org>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Commit-Queue: Brandon1 Jones <brandon1.jones@intel.com>
  • Loading branch information
bjjones authored and Dawn LUCI CQ committed Feb 10, 2022
1 parent e6e2bcf commit cff04b4
Show file tree
Hide file tree
Showing 21 changed files with 505 additions and 161 deletions.
2 changes: 1 addition & 1 deletion src/dawn/common/Constants.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ static constexpr uint32_t kMaxQueryCount = 8192u;

// An external texture occupies multiple binding slots. These are the per-external-texture bindings
// needed.
static constexpr uint8_t kSampledTexturesPerExternalTexture = 3u;
static constexpr uint8_t kSampledTexturesPerExternalTexture = 4u;
static constexpr uint8_t kSamplersPerExternalTexture = 1u;
static constexpr uint8_t kUniformsPerExternalTexture = 1u;

Expand Down
78 changes: 60 additions & 18 deletions src/dawn/native/BindGroup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -240,12 +240,10 @@ namespace dawn::native {
return {};
}

MaybeError ValidateExternalTextureBinding(const DeviceBase* device,
const BindGroupEntry& entry,
const BindingInfo& bindingInfo) {
const ExternalTextureBindingEntry* externalTextureBindingEntry = nullptr;
FindInChain(entry.nextInChain, &externalTextureBindingEntry);

MaybeError ValidateExternalTextureBinding(
const DeviceBase* device,
const BindGroupEntry& entry,
const ExternalTextureBindingEntry* externalTextureBindingEntry) {
DAWN_INVALID_IF(externalTextureBindingEntry == nullptr,
"Binding entry external texture not set.");

Expand All @@ -270,7 +268,7 @@ namespace dawn::native {
DAWN_TRY(device->ValidateObject(descriptor->layout));

DAWN_INVALID_IF(
BindingIndex(descriptor->entryCount) != descriptor->layout->GetBindingCount(),
descriptor->entryCount != descriptor->layout->GetUnexpandedBindingCount(),
"Number of entries (%u) did not match the number of entries (%u) specified in %s",
descriptor->entryCount, static_cast<uint32_t>(descriptor->layout->GetBindingCount()),
descriptor->layout);
Expand All @@ -296,6 +294,21 @@ namespace dawn::native {

bindingsSet.set(bindingIndex);

// Below this block we validate entries based on the bind group layout, in which
// external textures have been expanded into their underlying contents. For this reason
// we must identify external texture binding entries by checking the bind group entry
// itself.
// TODO:(dawn:1293): Store external textures in
// BindGroupLayoutBase::BindingDataPointers::bindings so checking external textures can
// be moved in the switch below.
const ExternalTextureBindingEntry* externalTextureBindingEntry = nullptr;
FindInChain(entry.nextInChain, &externalTextureBindingEntry);
if (externalTextureBindingEntry != nullptr) {
DAWN_TRY(
ValidateExternalTextureBinding(device, entry, externalTextureBindingEntry));
continue;
}

const BindingInfo& bindingInfo = descriptor->layout->GetBindingInfo(bindingIndex);

// Perform binding-type specific validation.
Expand All @@ -314,8 +327,7 @@ namespace dawn::native {
"validating entries[%u] as a Sampler", i);
break;
case BindingInfoType::ExternalTexture:
DAWN_TRY_CONTEXT(ValidateExternalTextureBinding(device, entry, bindingInfo),
"validating entries[%u] as an ExternalTexture", i);
UNREACHABLE();
break;
}
}
Expand All @@ -325,7 +337,7 @@ namespace dawn::native {
// - Each binding must be set at most once
//
// We don't validate the equality because it wouldn't be possible to cover it with a test.
ASSERT(bindingsSet.count() == bindingMap.size());
ASSERT(bindingsSet.count() == descriptor->layout->GetUnexpandedBindingCount());

return {};
} // anonymous namespace
Expand Down Expand Up @@ -377,11 +389,45 @@ namespace dawn::native {
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
// underlying resources.
const ExternalTextureBindingEntry* externalTextureBindingEntry = nullptr;
FindInChain(entry.nextInChain, &externalTextureBindingEntry);
if (externalTextureBindingEntry != nullptr) {
ASSERT(mBindingData.bindings[bindingIndex] == nullptr);
mBindingData.bindings[bindingIndex] = externalTextureBindingEntry->externalTexture;
mBoundExternalTextures.push_back(externalTextureBindingEntry->externalTexture);

ExternalTextureBindingExpansionMap expansions =
mLayout->GetExternalTextureBindingExpansionMap();
ExternalTextureBindingExpansionMap::iterator it =
expansions.find(BindingNumber(entry.binding));

ASSERT(it != expansions.end());

BindingIndex plane0BindingIndex =
descriptor->layout->GetBindingIndex(it->second.plane0);
BindingIndex plane1BindingIndex =
descriptor->layout->GetBindingIndex(it->second.plane1);
BindingIndex paramsBindingIndex =
descriptor->layout->GetBindingIndex(it->second.params);

ASSERT(mBindingData.bindings[plane0BindingIndex] == nullptr);

mBindingData.bindings[plane0BindingIndex] =
externalTextureBindingEntry->externalTexture->GetTextureViews()[0];

ASSERT(mBindingData.bindings[plane1BindingIndex] == nullptr);
mBindingData.bindings[plane1BindingIndex] =
externalTextureBindingEntry->externalTexture->GetTextureViews()[1];

ASSERT(mBindingData.bindings[paramsBindingIndex] == nullptr);
mBindingData.bindings[paramsBindingIndex] =
externalTextureBindingEntry->externalTexture->GetParamsBuffer();
mBindingData.bufferData[paramsBindingIndex].offset = 0;
mBindingData.bufferData[paramsBindingIndex].size =
sizeof(dawn_native::ExternalTextureParams);

continue;
}
}
Expand Down Expand Up @@ -475,12 +521,8 @@ namespace dawn::native {
return static_cast<TextureViewBase*>(mBindingData.bindings[bindingIndex].Get());
}

ExternalTextureBase* BindGroupBase::GetBindingAsExternalTexture(BindingIndex bindingIndex) {
ASSERT(!IsError());
ASSERT(bindingIndex < mLayout->GetBindingCount());
ASSERT(mLayout->GetBindingInfo(bindingIndex).bindingType ==
BindingInfoType::ExternalTexture);
return static_cast<ExternalTextureBase*>(mBindingData.bindings[bindingIndex].Get());
const std::vector<Ref<ExternalTextureBase>>& BindGroupBase::GetBoundExternalTextures() const {
return mBoundExternalTextures;
}

} // namespace dawn::native
6 changes: 5 additions & 1 deletion src/dawn/native/BindGroup.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ namespace dawn::native {
SamplerBase* GetBindingAsSampler(BindingIndex bindingIndex) const;
TextureViewBase* GetBindingAsTextureView(BindingIndex bindingIndex);
const ityp::span<uint32_t, uint64_t>& GetUnverifiedBufferSizes() const;
ExternalTextureBase* GetBindingAsExternalTexture(BindingIndex bindingIndex);
const std::vector<Ref<ExternalTextureBase>>& GetBoundExternalTextures() const;

protected:
// To save memory, the size of a bind group is dynamically determined and the bind group is
Expand Down Expand Up @@ -85,6 +85,10 @@ namespace dawn::native {

Ref<BindGroupLayoutBase> mLayout;
BindGroupLayoutBase::BindingDataPointers mBindingData;

// TODO:(dawn:1293): Store external textures in
// BindGroupLayoutBase::BindingDataPointers::bindings
std::vector<Ref<ExternalTextureBase>> mBoundExternalTextures;
};

} // namespace dawn::native
Expand Down
111 changes: 104 additions & 7 deletions src/dawn/native/BindGroupLayout.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,90 @@ namespace dawn::native {
return {};
}

BindGroupLayoutEntry CreateSampledTextureBindingForExternalTexture(
uint32_t binding,
wgpu::ShaderStage visibility) {
BindGroupLayoutEntry entry;
entry.binding = binding;
entry.visibility = visibility;
entry.texture.viewDimension = wgpu::TextureViewDimension::e2D;
entry.texture.multisampled = false;
entry.texture.sampleType = wgpu::TextureSampleType::Float;
return entry;
}

BindGroupLayoutEntry CreateUniformBindingForExternalTexture(uint32_t binding,
wgpu::ShaderStage visibility) {
BindGroupLayoutEntry entry;
entry.binding = binding;
entry.visibility = visibility;
entry.buffer.hasDynamicOffset = false;
entry.buffer.type = wgpu::BufferBindingType::Uniform;
return entry;
}

std::vector<BindGroupLayoutEntry> ExtractAndExpandBglEntries(
const BindGroupLayoutDescriptor* descriptor,
BindingCounts* bindingCounts,
ExternalTextureBindingExpansionMap* externalTextureBindingExpansions) {
std::vector<BindGroupLayoutEntry> expandedOutput;

// When new bgl entries are created, we use binding numbers larger than
// kMaxBindingNumber to ensure there are no collisions.
uint32_t nextOpenBindingNumberForNewEntry = kMaxBindingNumber + 1;
for (uint32_t i = 0; i < descriptor->entryCount; i++) {
const BindGroupLayoutEntry& entry = descriptor->entries[i];
const ExternalTextureBindingLayout* externalTextureBindingLayout = nullptr;
FindInChain(entry.nextInChain, &externalTextureBindingLayout);
// External textures are expanded from a texture_external into two sampled texture
// bindings and one uniform buffer binding. The original binding number is used
// for the first sampled texture.
if (externalTextureBindingLayout != nullptr) {
for (SingleShaderStage stage : IterateStages(entry.visibility)) {
// External textures are not fully implemented, which means that expanding
// the external texture at this time will not occupy the same number of
// binding slots as defined in the WebGPU specification. Here we prematurely
// increment the binding counts for an additional sampled textures and a
// sampler so that an external texture will occupy the correct number of
// slots for correct validation of shader binding limits.
// TODO:(dawn:1082): Consider removing this and instead making a change to
// the validation.
constexpr uint32_t kUnimplementedSampledTexturesPerExternalTexture = 2;
constexpr uint32_t kUnimplementedSamplersPerExternalTexture = 1;
bindingCounts->perStage[stage].sampledTextureCount +=
kUnimplementedSampledTexturesPerExternalTexture;
bindingCounts->perStage[stage].samplerCount +=
kUnimplementedSamplersPerExternalTexture;
}

dawn_native::ExternalTextureBindingExpansion bindingExpansion;

BindGroupLayoutEntry plane0Entry =
CreateSampledTextureBindingForExternalTexture(entry.binding,
entry.visibility);
bindingExpansion.plane0 = BindingNumber(plane0Entry.binding);
expandedOutput.push_back(plane0Entry);

BindGroupLayoutEntry plane1Entry =
CreateSampledTextureBindingForExternalTexture(
nextOpenBindingNumberForNewEntry++, entry.visibility);
bindingExpansion.plane1 = BindingNumber(plane1Entry.binding);
expandedOutput.push_back(plane1Entry);

BindGroupLayoutEntry paramsEntry = CreateUniformBindingForExternalTexture(
nextOpenBindingNumberForNewEntry++, entry.visibility);
bindingExpansion.params = BindingNumber(paramsEntry.binding);
expandedOutput.push_back(paramsEntry);

externalTextureBindingExpansions->insert(
{BindingNumber(entry.binding), bindingExpansion});
} else {
expandedOutput.push_back(entry);
}
}

return expandedOutput;
}
} // anonymous namespace

MaybeError ValidateBindGroupLayoutDescriptor(DeviceBase* device,
Expand Down Expand Up @@ -370,21 +454,21 @@ namespace dawn::native {
PipelineCompatibilityToken pipelineCompatibilityToken,
ApiObjectBase::UntrackedByDeviceTag tag)
: ApiObjectBase(device, descriptor->label),
mBindingInfo(BindingIndex(descriptor->entryCount)),
mPipelineCompatibilityToken(pipelineCompatibilityToken) {
std::vector<BindGroupLayoutEntry> sortedBindings(
descriptor->entries, descriptor->entries + descriptor->entryCount);
mPipelineCompatibilityToken(pipelineCompatibilityToken),
mUnexpandedBindingCount(descriptor->entryCount) {
std::vector<BindGroupLayoutEntry> sortedBindings = ExtractAndExpandBglEntries(
descriptor, &mBindingCounts, &mExternalTextureBindingExpansionMap);

std::sort(sortedBindings.begin(), sortedBindings.end(), SortBindingsCompare);

for (BindingIndex i{0}; i < mBindingInfo.size(); ++i) {
for (uint32_t i = 0; i < sortedBindings.size(); ++i) {
const BindGroupLayoutEntry& binding = sortedBindings[static_cast<uint32_t>(i)];

mBindingInfo[i] = CreateBindGroupLayoutInfo(binding);
mBindingInfo.push_back(CreateBindGroupLayoutInfo(binding));

if (IsBufferBinding(binding)) {
// Buffers must be contiguously packed at the start of the binding info.
ASSERT(GetBufferCount() == i);
ASSERT(GetBufferCount() == BindingIndex(i));
}
IncrementBindingCounts(&mBindingCounts, binding);

Expand Down Expand Up @@ -489,10 +573,23 @@ namespace dawn::native {
return mBindingCounts.unverifiedBufferCount;
}

uint32_t BindGroupLayoutBase::GetExternalTextureBindingCount() const {
return mExternalTextureBindingExpansionMap.size();
}

const BindingCounts& BindGroupLayoutBase::GetBindingCountInfo() const {
return mBindingCounts;
}

const ExternalTextureBindingExpansionMap&
BindGroupLayoutBase::GetExternalTextureBindingExpansionMap() const {
return mExternalTextureBindingExpansionMap;
}

uint32_t BindGroupLayoutBase::GetUnexpandedBindingCount() const {
return mUnexpandedBindingCount;
}

bool BindGroupLayoutBase::IsLayoutEqual(const BindGroupLayoutBase* other,
bool excludePipelineCompatibiltyToken) const {
if (!excludePipelineCompatibiltyToken &&
Expand Down
20 changes: 20 additions & 0 deletions src/dawn/native/BindGroupLayout.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,15 @@
#include <map>

namespace dawn::native {
// TODO(dawn:1082): Minor optimization to use BindingIndex instead of BindingNumber
struct ExternalTextureBindingExpansion {
BindingNumber plane0;
BindingNumber plane1;
BindingNumber params;
};

using ExternalTextureBindingExpansionMap =
std::map<BindingNumber, ExternalTextureBindingExpansion>;

MaybeError ValidateBindGroupLayoutDescriptor(DeviceBase* device,
const BindGroupLayoutDescriptor* descriptor,
Expand Down Expand Up @@ -85,6 +94,13 @@ namespace dawn::native {
// should be used to get typed integer counts.
const BindingCounts& GetBindingCountInfo() const;

uint32_t GetExternalTextureBindingCount() const;

// Used to specify unpacked external texture binding slots when transforming shader modules.
const ExternalTextureBindingExpansionMap& GetExternalTextureBindingExpansionMap() const;

uint32_t GetUnexpandedBindingCount() const;

// Tests that the BindingInfo of two bind groups are equal,
// ignoring their compatibility groups.
bool IsLayoutEqual(const BindGroupLayoutBase* other,
Expand Down Expand Up @@ -137,9 +153,13 @@ namespace dawn::native {
// Map from BindGroupLayoutEntry.binding to packed indices.
BindingMap mBindingMap;

ExternalTextureBindingExpansionMap mExternalTextureBindingExpansionMap;

// Non-0 if this BindGroupLayout was created as part of a default PipelineLayout.
const PipelineCompatibilityToken mPipelineCompatibilityToken =
PipelineCompatibilityToken(0);

uint32_t mUnexpandedBindingCount;
};

} // namespace dawn::native
Expand Down
4 changes: 4 additions & 0 deletions src/dawn/native/ExternalTexture.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,10 @@ namespace dawn::native {
return new ExternalTextureBase(device, ObjectBase::kError);
}

BufferBase* ExternalTextureBase::GetParamsBuffer() const {
return mParamsBuffer.Get();
}

ObjectType ExternalTextureBase::GetType() const {
return ObjectType::ExternalTexture;
}
Expand Down
9 changes: 5 additions & 4 deletions src/dawn/native/ExternalTexture.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,14 +43,13 @@ namespace dawn::native {
DeviceBase* device,
const ExternalTextureDescriptor* descriptor);

BufferBase* GetParamsBuffer() const;
const std::array<Ref<TextureViewBase>, kMaxPlanesPerFormat>& GetTextureViews() const;
ObjectType GetType() const override;

MaybeError ValidateCanUseInSubmitNow() const;
MaybeError Initialize(DeviceBase* device, const ExternalTextureDescriptor* descriptor);
static ExternalTextureBase* MakeError(DeviceBase* device);

ObjectType GetType() const override;

void APIDestroy();

protected:
Expand All @@ -61,9 +60,11 @@ namespace dawn::native {
~ExternalTextureBase() override;

private:
enum class ExternalTextureState { Alive, Destroyed };
ExternalTextureBase(DeviceBase* device, const ExternalTextureDescriptor* descriptor);

enum class ExternalTextureState { Alive, Destroyed };
ExternalTextureBase(DeviceBase* device, ObjectBase::ErrorTag tag);
MaybeError Initialize(DeviceBase* device, const ExternalTextureDescriptor* descriptor);

Ref<TextureBase> mDummyTexture;
Ref<BufferBase> mParamsBuffer;
Expand Down
Loading

0 comments on commit cff04b4

Please sign in to comment.