Integrate Multiplanar External Texture Transform

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>
This commit is contained in:
Brandon Jones 2022-02-10 19:31:13 +00:00 committed by Dawn LUCI CQ
parent e6e2bcf436
commit cff04b4d3f
21 changed files with 505 additions and 161 deletions

View File

@ -58,7 +58,7 @@ static constexpr uint32_t kMaxQueryCount = 8192u;
// An external texture occupies multiple binding slots. These are the per-external-texture bindings // An external texture occupies multiple binding slots. These are the per-external-texture bindings
// needed. // needed.
static constexpr uint8_t kSampledTexturesPerExternalTexture = 3u; static constexpr uint8_t kSampledTexturesPerExternalTexture = 4u;
static constexpr uint8_t kSamplersPerExternalTexture = 1u; static constexpr uint8_t kSamplersPerExternalTexture = 1u;
static constexpr uint8_t kUniformsPerExternalTexture = 1u; static constexpr uint8_t kUniformsPerExternalTexture = 1u;

View File

@ -240,12 +240,10 @@ namespace dawn::native {
return {}; return {};
} }
MaybeError ValidateExternalTextureBinding(const DeviceBase* device, MaybeError ValidateExternalTextureBinding(
const BindGroupEntry& entry, const DeviceBase* device,
const BindingInfo& bindingInfo) { const BindGroupEntry& entry,
const ExternalTextureBindingEntry* externalTextureBindingEntry = nullptr; const ExternalTextureBindingEntry* externalTextureBindingEntry) {
FindInChain(entry.nextInChain, &externalTextureBindingEntry);
DAWN_INVALID_IF(externalTextureBindingEntry == nullptr, DAWN_INVALID_IF(externalTextureBindingEntry == nullptr,
"Binding entry external texture not set."); "Binding entry external texture not set.");
@ -270,7 +268,7 @@ namespace dawn::native {
DAWN_TRY(device->ValidateObject(descriptor->layout)); DAWN_TRY(device->ValidateObject(descriptor->layout));
DAWN_INVALID_IF( 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", "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->entryCount, static_cast<uint32_t>(descriptor->layout->GetBindingCount()),
descriptor->layout); descriptor->layout);
@ -296,6 +294,21 @@ namespace dawn::native {
bindingsSet.set(bindingIndex); 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); const BindingInfo& bindingInfo = descriptor->layout->GetBindingInfo(bindingIndex);
// Perform binding-type specific validation. // Perform binding-type specific validation.
@ -314,8 +327,7 @@ namespace dawn::native {
"validating entries[%u] as a Sampler", i); "validating entries[%u] as a Sampler", i);
break; break;
case BindingInfoType::ExternalTexture: case BindingInfoType::ExternalTexture:
DAWN_TRY_CONTEXT(ValidateExternalTextureBinding(device, entry, bindingInfo), UNREACHABLE();
"validating entries[%u] as an ExternalTexture", i);
break; break;
} }
} }
@ -325,7 +337,7 @@ namespace dawn::native {
// - Each binding must be set at most once // - 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. // 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 {}; return {};
} // anonymous namespace } // anonymous namespace
@ -377,11 +389,45 @@ namespace dawn::native {
continue; 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; const ExternalTextureBindingEntry* externalTextureBindingEntry = nullptr;
FindInChain(entry.nextInChain, &externalTextureBindingEntry); FindInChain(entry.nextInChain, &externalTextureBindingEntry);
if (externalTextureBindingEntry != nullptr) { if (externalTextureBindingEntry != nullptr) {
ASSERT(mBindingData.bindings[bindingIndex] == nullptr); mBoundExternalTextures.push_back(externalTextureBindingEntry->externalTexture);
mBindingData.bindings[bindingIndex] = 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; continue;
} }
} }
@ -475,12 +521,8 @@ namespace dawn::native {
return static_cast<TextureViewBase*>(mBindingData.bindings[bindingIndex].Get()); return static_cast<TextureViewBase*>(mBindingData.bindings[bindingIndex].Get());
} }
ExternalTextureBase* BindGroupBase::GetBindingAsExternalTexture(BindingIndex bindingIndex) { const std::vector<Ref<ExternalTextureBase>>& BindGroupBase::GetBoundExternalTextures() const {
ASSERT(!IsError()); return mBoundExternalTextures;
ASSERT(bindingIndex < mLayout->GetBindingCount());
ASSERT(mLayout->GetBindingInfo(bindingIndex).bindingType ==
BindingInfoType::ExternalTexture);
return static_cast<ExternalTextureBase*>(mBindingData.bindings[bindingIndex].Get());
} }
} // namespace dawn::native } // namespace dawn::native

View File

@ -51,7 +51,7 @@ namespace dawn::native {
SamplerBase* GetBindingAsSampler(BindingIndex bindingIndex) const; SamplerBase* GetBindingAsSampler(BindingIndex bindingIndex) const;
TextureViewBase* GetBindingAsTextureView(BindingIndex bindingIndex); TextureViewBase* GetBindingAsTextureView(BindingIndex bindingIndex);
const ityp::span<uint32_t, uint64_t>& GetUnverifiedBufferSizes() const; const ityp::span<uint32_t, uint64_t>& GetUnverifiedBufferSizes() const;
ExternalTextureBase* GetBindingAsExternalTexture(BindingIndex bindingIndex); const std::vector<Ref<ExternalTextureBase>>& GetBoundExternalTextures() const;
protected: protected:
// To save memory, the size of a bind group is dynamically determined and the bind group is // To save memory, the size of a bind group is dynamically determined and the bind group is
@ -85,6 +85,10 @@ namespace dawn::native {
Ref<BindGroupLayoutBase> mLayout; Ref<BindGroupLayoutBase> mLayout;
BindGroupLayoutBase::BindingDataPointers mBindingData; BindGroupLayoutBase::BindingDataPointers mBindingData;
// TODO:(dawn:1293): Store external textures in
// BindGroupLayoutBase::BindingDataPointers::bindings
std::vector<Ref<ExternalTextureBase>> mBoundExternalTextures;
}; };
} // namespace dawn::native } // namespace dawn::native

View File

@ -153,6 +153,90 @@ namespace dawn::native {
return {}; 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 } // anonymous namespace
MaybeError ValidateBindGroupLayoutDescriptor(DeviceBase* device, MaybeError ValidateBindGroupLayoutDescriptor(DeviceBase* device,
@ -370,21 +454,21 @@ namespace dawn::native {
PipelineCompatibilityToken pipelineCompatibilityToken, PipelineCompatibilityToken pipelineCompatibilityToken,
ApiObjectBase::UntrackedByDeviceTag tag) ApiObjectBase::UntrackedByDeviceTag tag)
: ApiObjectBase(device, descriptor->label), : ApiObjectBase(device, descriptor->label),
mBindingInfo(BindingIndex(descriptor->entryCount)), mPipelineCompatibilityToken(pipelineCompatibilityToken),
mPipelineCompatibilityToken(pipelineCompatibilityToken) { mUnexpandedBindingCount(descriptor->entryCount) {
std::vector<BindGroupLayoutEntry> sortedBindings( std::vector<BindGroupLayoutEntry> sortedBindings = ExtractAndExpandBglEntries(
descriptor->entries, descriptor->entries + descriptor->entryCount); descriptor, &mBindingCounts, &mExternalTextureBindingExpansionMap);
std::sort(sortedBindings.begin(), sortedBindings.end(), SortBindingsCompare); 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)]; const BindGroupLayoutEntry& binding = sortedBindings[static_cast<uint32_t>(i)];
mBindingInfo[i] = CreateBindGroupLayoutInfo(binding); mBindingInfo.push_back(CreateBindGroupLayoutInfo(binding));
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.
ASSERT(GetBufferCount() == i); ASSERT(GetBufferCount() == BindingIndex(i));
} }
IncrementBindingCounts(&mBindingCounts, binding); IncrementBindingCounts(&mBindingCounts, binding);
@ -489,10 +573,23 @@ namespace dawn::native {
return mBindingCounts.unverifiedBufferCount; return mBindingCounts.unverifiedBufferCount;
} }
uint32_t BindGroupLayoutBase::GetExternalTextureBindingCount() const {
return mExternalTextureBindingExpansionMap.size();
}
const BindingCounts& BindGroupLayoutBase::GetBindingCountInfo() const { const BindingCounts& BindGroupLayoutBase::GetBindingCountInfo() const {
return mBindingCounts; return mBindingCounts;
} }
const ExternalTextureBindingExpansionMap&
BindGroupLayoutBase::GetExternalTextureBindingExpansionMap() const {
return mExternalTextureBindingExpansionMap;
}
uint32_t BindGroupLayoutBase::GetUnexpandedBindingCount() const {
return mUnexpandedBindingCount;
}
bool BindGroupLayoutBase::IsLayoutEqual(const BindGroupLayoutBase* other, bool BindGroupLayoutBase::IsLayoutEqual(const BindGroupLayoutBase* other,
bool excludePipelineCompatibiltyToken) const { bool excludePipelineCompatibiltyToken) const {
if (!excludePipelineCompatibiltyToken && if (!excludePipelineCompatibiltyToken &&

View File

@ -32,6 +32,15 @@
#include <map> #include <map>
namespace dawn::native { 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, MaybeError ValidateBindGroupLayoutDescriptor(DeviceBase* device,
const BindGroupLayoutDescriptor* descriptor, const BindGroupLayoutDescriptor* descriptor,
@ -85,6 +94,13 @@ namespace dawn::native {
// should be used to get typed integer counts. // should be used to get typed integer counts.
const BindingCounts& GetBindingCountInfo() const; 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, // Tests that the BindingInfo of two bind groups are equal,
// ignoring their compatibility groups. // ignoring their compatibility groups.
bool IsLayoutEqual(const BindGroupLayoutBase* other, bool IsLayoutEqual(const BindGroupLayoutBase* other,
@ -137,9 +153,13 @@ namespace dawn::native {
// Map from BindGroupLayoutEntry.binding to packed indices. // Map from BindGroupLayoutEntry.binding to packed indices.
BindingMap mBindingMap; BindingMap mBindingMap;
ExternalTextureBindingExpansionMap mExternalTextureBindingExpansionMap;
// Non-0 if this BindGroupLayout was created as part of a default PipelineLayout. // Non-0 if this BindGroupLayout was created as part of a default PipelineLayout.
const PipelineCompatibilityToken mPipelineCompatibilityToken = const PipelineCompatibilityToken mPipelineCompatibilityToken =
PipelineCompatibilityToken(0); PipelineCompatibilityToken(0);
uint32_t mUnexpandedBindingCount;
}; };
} // namespace dawn::native } // namespace dawn::native

View File

@ -219,6 +219,10 @@ namespace dawn::native {
return new ExternalTextureBase(device, ObjectBase::kError); return new ExternalTextureBase(device, ObjectBase::kError);
} }
BufferBase* ExternalTextureBase::GetParamsBuffer() const {
return mParamsBuffer.Get();
}
ObjectType ExternalTextureBase::GetType() const { ObjectType ExternalTextureBase::GetType() const {
return ObjectType::ExternalTexture; return ObjectType::ExternalTexture;
} }

View File

@ -43,14 +43,13 @@ namespace dawn::native {
DeviceBase* device, DeviceBase* device,
const ExternalTextureDescriptor* descriptor); const ExternalTextureDescriptor* descriptor);
BufferBase* GetParamsBuffer() const;
const std::array<Ref<TextureViewBase>, kMaxPlanesPerFormat>& GetTextureViews() const; const std::array<Ref<TextureViewBase>, kMaxPlanesPerFormat>& GetTextureViews() const;
ObjectType GetType() const override;
MaybeError ValidateCanUseInSubmitNow() const; MaybeError ValidateCanUseInSubmitNow() const;
MaybeError Initialize(DeviceBase* device, const ExternalTextureDescriptor* descriptor);
static ExternalTextureBase* MakeError(DeviceBase* device); static ExternalTextureBase* MakeError(DeviceBase* device);
ObjectType GetType() const override;
void APIDestroy(); void APIDestroy();
protected: protected:
@ -61,9 +60,11 @@ namespace dawn::native {
~ExternalTextureBase() override; ~ExternalTextureBase() override;
private: private:
enum class ExternalTextureState { Alive, Destroyed };
ExternalTextureBase(DeviceBase* device, const ExternalTextureDescriptor* descriptor); ExternalTextureBase(DeviceBase* device, const ExternalTextureDescriptor* descriptor);
enum class ExternalTextureState { Alive, Destroyed };
ExternalTextureBase(DeviceBase* device, ObjectBase::ErrorTag tag); ExternalTextureBase(DeviceBase* device, ObjectBase::ErrorTag tag);
MaybeError Initialize(DeviceBase* device, const ExternalTextureDescriptor* descriptor);
Ref<TextureBase> mDummyTexture; Ref<TextureBase> mDummyTexture;
Ref<BufferBase> mParamsBuffer; Ref<BufferBase> mParamsBuffer;

View File

@ -124,24 +124,18 @@ namespace dawn::native {
break; break;
} }
case BindingInfoType::ExternalTexture: { case BindingInfoType::ExternalTexture:
ExternalTextureBase* externalTexture = UNREACHABLE();
group->GetBindingAsExternalTexture(bindingIndex);
const std::array<Ref<TextureViewBase>, kMaxPlanesPerFormat>& textureViews =
externalTexture->GetTextureViews();
ASSERT(textureViews[2].Get() == nullptr);
mExternalTextureUsages.insert(externalTexture);
TextureViewUsedAs(textureViews[0].Get(), wgpu::TextureUsage::TextureBinding);
break; break;
}
case BindingInfoType::Sampler: case BindingInfoType::Sampler:
break; break;
} }
} }
for (const Ref<ExternalTextureBase>& externalTexture : group->GetBoundExternalTextures()) {
mExternalTextureUsages.insert(externalTexture.Get());
}
} }
SyncScopeResourceUsage SyncScopeUsageTracker::AcquireSyncScopeUsage() { SyncScopeResourceUsage SyncScopeUsageTracker::AcquireSyncScopeUsage() {
@ -196,24 +190,17 @@ namespace dawn::native {
break; break;
} }
case BindingInfoType::ExternalTexture: { case BindingInfoType::ExternalTexture:
ExternalTextureBase* externalTexture = UNREACHABLE();
group->GetBindingAsExternalTexture(index);
const std::array<Ref<TextureViewBase>, kMaxPlanesPerFormat>& textureViews =
externalTexture->GetTextureViews();
ASSERT(textureViews[2].Get() == nullptr);
mUsage.referencedExternalTextures.insert(externalTexture);
mUsage.referencedTextures.insert(textureViews[0].Get()->GetTexture());
break;
}
case BindingInfoType::StorageTexture: case BindingInfoType::StorageTexture:
case BindingInfoType::Sampler: case BindingInfoType::Sampler:
break; break;
} }
} }
for (const Ref<ExternalTextureBase>& externalTexture : group->GetBoundExternalTextures()) {
mUsage.referencedExternalTextures.insert(externalTexture.Get());
}
} }
ComputePassResourceUsage ComputePassResourceUsageTracker::AcquireResourceUsage() { ComputePassResourceUsage ComputePassResourceUsageTracker::AcquireResourceUsage() {

View File

@ -15,6 +15,7 @@
#include "dawn/native/ShaderModule.h" #include "dawn/native/ShaderModule.h"
#include "absl/strings/str_format.h" #include "absl/strings/str_format.h"
#include "dawn/common/BitSetIterator.h"
#include "dawn/common/Constants.h" #include "dawn/common/Constants.h"
#include "dawn/common/HashUtils.h" #include "dawn/common/HashUtils.h"
#include "dawn/native/BindGroupLayout.h" #include "dawn/native/BindGroupLayout.h"
@ -444,6 +445,26 @@ namespace dawn::native {
const ShaderBindingInfo& shaderInfo) { const ShaderBindingInfo& shaderInfo) {
const BindGroupLayoutBase::BindingMap& layoutBindings = layout->GetBindingMap(); const BindGroupLayoutBase::BindingMap& layoutBindings = layout->GetBindingMap();
// An external texture binding found in the shader will later be expanded into multiple
// bindings at compile time. This expansion will have already happened in the bgl - so
// the shader and bgl will always mismatch at this point. Expansion info is contained in
// the bgl object, so we can still verify the bgl used to have an external texture in
// the slot corresponding to the shader reflection.
if (shaderInfo.bindingType == BindingInfoType::ExternalTexture) {
// If an external texture binding used to exist in the bgl, it will be found as a
// key in the ExternalTextureBindingExpansions map.
ExternalTextureBindingExpansionMap expansions =
layout->GetExternalTextureBindingExpansionMap();
std::map<BindingNumber, dawn_native::ExternalTextureBindingExpansion>::iterator it =
expansions.find(bindingNumber);
// TODO(dawn:563): Provide info about the binding types.
DAWN_INVALID_IF(it == expansions.end(),
"Binding type in the shader (texture_external) doesn't match the "
"type in the layout.");
return {};
}
const auto& bindingIt = layoutBindings.find(bindingNumber); const auto& bindingIt = layoutBindings.find(bindingNumber);
DAWN_INVALID_IF(bindingIt == layoutBindings.end(), "Binding doesn't exist in %s.", DAWN_INVALID_IF(bindingIt == layoutBindings.end(), "Binding doesn't exist in %s.",
layout); layout);
@ -452,9 +473,16 @@ namespace dawn::native {
const BindingInfo& layoutInfo = layout->GetBindingInfo(bindingIndex); const BindingInfo& layoutInfo = layout->GetBindingInfo(bindingIndex);
// TODO(dawn:563): Provide info about the binding types. // TODO(dawn:563): Provide info about the binding types.
DAWN_INVALID_IF(layoutInfo.bindingType != shaderInfo.bindingType, DAWN_INVALID_IF(
"Binding type (buffer vs. texture vs. sampler) doesn't match the type " layoutInfo.bindingType != shaderInfo.bindingType,
"in the layout."); "Binding type (buffer vs. texture vs. sampler vs. external) doesn't match the type "
"in the layout.");
ExternalTextureBindingExpansionMap expansions =
layout->GetExternalTextureBindingExpansionMap();
DAWN_INVALID_IF(expansions.find(bindingNumber) != expansions.end(),
"Binding type (buffer vs. texture vs. sampler vs. external) doesn't "
"match the type in the layout.");
// TODO(dawn:563): Provide info about the visibility. // TODO(dawn:563): Provide info about the visibility.
DAWN_INVALID_IF( DAWN_INVALID_IF(
@ -509,11 +537,6 @@ namespace dawn::native {
break; break;
} }
case BindingInfoType::ExternalTexture: {
// Nothing to validate! (yet?)
break;
}
case BindingInfoType::Buffer: { case BindingInfoType::Buffer: {
// Binding mismatch between shader and bind group is invalid. For example, a // Binding mismatch between shader and bind group is invalid. For example, a
// writable binding in the shader with a readonly storage buffer in the bind // writable binding in the shader with a readonly storage buffer in the bind
@ -551,6 +574,11 @@ namespace dawn::native {
shaderInfo.sampler.isComparison, shaderInfo.sampler.isComparison,
layoutInfo.sampler.type == wgpu::SamplerBindingType::Comparison); layoutInfo.sampler.type == wgpu::SamplerBindingType::Comparison);
break; break;
case BindingInfoType::ExternalTexture: {
UNREACHABLE();
break;
}
} }
return {}; return {};
@ -1264,6 +1292,30 @@ namespace dawn::native {
return mCompilationMessages.get(); return mCompilationMessages.get();
} }
// static
void ShaderModuleBase::AddExternalTextureTransform(const PipelineLayoutBase* layout,
tint::transform::Manager* transformManager,
tint::transform::DataMap* transformInputs) {
tint::transform::MultiplanarExternalTexture::BindingsMap newBindingsMap;
for (BindGroupIndex i : IterateBitSet(layout->GetBindGroupLayoutsMask())) {
const BindGroupLayoutBase* bgl = layout->GetBindGroupLayout(i);
for (const auto& expansion : bgl->GetExternalTextureBindingExpansionMap()) {
newBindingsMap[{static_cast<uint32_t>(i),
static_cast<uint32_t>(expansion.second.plane0)}] = {
{static_cast<uint32_t>(i), static_cast<uint32_t>(expansion.second.plane1)},
{static_cast<uint32_t>(i), static_cast<uint32_t>(expansion.second.params)}};
}
}
tint::transform::Manager m;
if (!newBindingsMap.empty()) {
transformManager->Add<tint::transform::MultiplanarExternalTexture>();
transformInputs->Add<tint::transform::MultiplanarExternalTexture::NewBindingPoints>(
newBindingsMap);
}
}
MaybeError ShaderModuleBase::InitializeBase(ShaderModuleParseResult* parseResult) { MaybeError ShaderModuleBase::InitializeBase(ShaderModuleParseResult* parseResult) {
mTintProgram = std::move(parseResult->tintProgram); mTintProgram = std::move(parseResult->tintProgram);
mTintSource = std::move(parseResult->tintSource); mTintSource = std::move(parseResult->tintSource);

View File

@ -41,6 +41,7 @@ namespace tint {
namespace transform { namespace transform {
class DataMap; class DataMap;
class Manager;
class Transform; class Transform;
class VertexPulling; class VertexPulling;
} // namespace transform } // namespace transform
@ -282,6 +283,10 @@ namespace dawn::native {
MaybeError InitializeBase(ShaderModuleParseResult* parseResult); MaybeError InitializeBase(ShaderModuleParseResult* parseResult);
static void AddExternalTextureTransform(const PipelineLayoutBase* layout,
tint::transform::Manager* transformManager,
tint::transform::DataMap* transformInputs);
private: private:
ShaderModuleBase(DeviceBase* device, ObjectBase::ErrorTag tag); ShaderModuleBase(DeviceBase* device, ObjectBase::ErrorTag tag);

View File

@ -177,21 +177,7 @@ namespace dawn::native::d3d12 {
} }
case BindingInfoType::ExternalTexture: { case BindingInfoType::ExternalTexture: {
const std::array<Ref<TextureViewBase>, kMaxPlanesPerFormat>& views = UNREACHABLE();
GetBindingAsExternalTexture(bindingIndex)->GetTextureViews();
ASSERT(views[2].Get() == nullptr);
auto& srv = ToBackend(views[0])->GetSRVDescriptor();
ID3D12Resource* resource =
ToBackend(views[0]->GetTexture())->GetD3D12Resource();
d3d12Device->CreateShaderResourceView(
resource, &srv,
viewAllocation.OffsetFrom(viewSizeIncrement,
descriptorHeapOffsets[bindingIndex]));
break;
} }
case BindingInfoType::Sampler: { case BindingInfoType::Sampler: {

View File

@ -753,7 +753,7 @@ namespace dawn::native::d3d12 {
ResultOrError<CompiledShader> ShaderModule::Compile(const ProgrammableStage& programmableStage, ResultOrError<CompiledShader> ShaderModule::Compile(const ProgrammableStage& programmableStage,
SingleShaderStage stage, SingleShaderStage stage,
PipelineLayout* layout, const PipelineLayout* layout,
uint32_t compileFlags) { uint32_t compileFlags) {
TRACE_EVENT0(GetDevice()->GetPlatform(), General, "ShaderModuleD3D12::Compile"); TRACE_EVENT0(GetDevice()->GetPlatform(), General, "ShaderModuleD3D12::Compile");
ASSERT(!IsError()); ASSERT(!IsError());
@ -767,19 +767,24 @@ namespace dawn::native::d3d12 {
tint::transform::Manager transformManager; tint::transform::Manager transformManager;
tint::transform::DataMap transformInputs; tint::transform::DataMap transformInputs;
const tint::Program* program; const tint::Program* program = GetTintProgram();
tint::Program programAsValue; tint::Program programAsValue;
AddExternalTextureTransform(layout, &transformManager, &transformInputs);
if (stage == SingleShaderStage::Vertex) { if (stage == SingleShaderStage::Vertex) {
transformManager.Add<tint::transform::FirstIndexOffset>(); transformManager.Add<tint::transform::FirstIndexOffset>();
transformInputs.Add<tint::transform::FirstIndexOffset::BindingPoint>( transformInputs.Add<tint::transform::FirstIndexOffset::BindingPoint>(
layout->GetFirstIndexOffsetShaderRegister(), layout->GetFirstIndexOffsetShaderRegister(),
layout->GetFirstIndexOffsetRegisterSpace()); layout->GetFirstIndexOffsetRegisterSpace());
}
tint::transform::DataMap transformOutputs; tint::transform::DataMap transformOutputs;
DAWN_TRY_ASSIGN(programAsValue, DAWN_TRY_ASSIGN(programAsValue, RunTransforms(&transformManager, program, transformInputs,
RunTransforms(&transformManager, GetTintProgram(), transformInputs, &transformOutputs, nullptr));
&transformOutputs, nullptr)); program = &programAsValue;
if (stage == SingleShaderStage::Vertex) {
if (auto* data = transformOutputs.Get<tint::transform::FirstIndexOffset::Data>()) { if (auto* data = transformOutputs.Get<tint::transform::FirstIndexOffset::Data>()) {
// TODO(dawn:549): Consider adding this information to the pipeline cache once we // TODO(dawn:549): Consider adding this information to the pipeline cache once we
// can store more than the shader blob in it. // can store more than the shader blob in it.
@ -793,10 +798,6 @@ namespace dawn::native::d3d12 {
data->first_instance_offset; data->first_instance_offset;
} }
} }
program = &programAsValue;
} else {
program = GetTintProgram();
} }
ShaderCompilationRequest request; ShaderCompilationRequest request;

View File

@ -55,7 +55,7 @@ namespace dawn::native::d3d12 {
ResultOrError<CompiledShader> Compile(const ProgrammableStage& programmableStage, ResultOrError<CompiledShader> Compile(const ProgrammableStage& programmableStage,
SingleShaderStage stage, SingleShaderStage stage,
PipelineLayout* layout, const PipelineLayout* layout,
uint32_t compileFlags); uint32_t compileFlags);
private: private:

View File

@ -517,28 +517,8 @@ namespace dawn::native::metal {
break; break;
} }
case BindingInfoType::ExternalTexture: { case BindingInfoType::ExternalTexture:
const std::array<Ref<TextureViewBase>, kMaxPlanesPerFormat>& views = UNREACHABLE();
group->GetBindingAsExternalTexture(bindingIndex)->GetTextureViews();
ASSERT(views[2].Get() == nullptr);
TextureView* textureView = ToBackend(views[0].Get());
if (hasVertStage) {
[render setVertexTexture:textureView->GetMTLTexture()
atIndex:vertIndex];
}
if (hasFragStage) {
[render setFragmentTexture:textureView->GetMTLTexture()
atIndex:fragIndex];
}
if (hasComputeStage) {
[compute setTexture:textureView->GetMTLTexture()
atIndex:computeIndex];
}
break;
}
} }
} }
} }

View File

@ -97,6 +97,8 @@ namespace dawn::native::metal {
transformManager.Add<tint::transform::SingleEntryPoint>(); transformManager.Add<tint::transform::SingleEntryPoint>();
transformInputs.Add<tint::transform::SingleEntryPoint::Config>(entryPointName); transformInputs.Add<tint::transform::SingleEntryPoint::Config>(entryPointName);
AddExternalTextureTransform(layout, &transformManager, &transformInputs);
if (stage == SingleShaderStage::Vertex && if (stage == SingleShaderStage::Vertex &&
GetDevice()->IsToggleEnabled(Toggle::MetalEnableVertexPulling)) { GetDevice()->IsToggleEnabled(Toggle::MetalEnableVertexPulling)) {
transformManager.Add<tint::transform::VertexPulling>(); transformManager.Add<tint::transform::VertexPulling>();

View File

@ -364,25 +364,9 @@ namespace dawn::native::opengl {
break; break;
} }
case BindingInfoType::ExternalTexture: { case BindingInfoType::ExternalTexture:
const std::array<Ref<TextureViewBase>, kMaxPlanesPerFormat>& UNREACHABLE();
textureViews = mBindGroups[index]
->GetBindingAsExternalTexture(bindingIndex)
->GetTextureViews();
ASSERT(textureViews[2].Get() == nullptr);
TextureView* view = ToBackend(textureViews[0].Get());
GLuint handle = view->GetHandle();
GLenum target = view->GetGLTarget();
GLuint viewIndex = indices[bindingIndex];
for (auto unit : mPipeline->GetTextureUnitsForTextureView(viewIndex)) {
gl.ActiveTexture(GL_TEXTURE0 + unit);
gl.BindTexture(target, handle);
}
break; break;
}
} }
} }
} }

View File

@ -268,15 +268,18 @@ namespace dawn::native::opengl {
const PipelineLayout* layout, const PipelineLayout* layout,
bool* needsDummySampler) const { bool* needsDummySampler) const {
TRACE_EVENT0(GetDevice()->GetPlatform(), General, "TranslateToGLSL"); TRACE_EVENT0(GetDevice()->GetPlatform(), General, "TranslateToGLSL");
tint::transform::SingleEntryPoint singleEntryPointTransform; tint::transform::Manager transformManager;
transformManager.append(std::make_unique<tint::transform::SingleEntryPoint>());
tint::transform::DataMap transformInputs; tint::transform::DataMap transformInputs;
transformInputs.Add<tint::transform::SingleEntryPoint::Config>(entryPointName); transformInputs.Add<tint::transform::SingleEntryPoint::Config>(entryPointName);
AddExternalTextureTransform(layout, &transformManager, &transformInputs);
tint::Program program; tint::Program program;
{ {
TRACE_EVENT0(GetDevice()->GetPlatform(), General, "RunTransforms"); TRACE_EVENT0(GetDevice()->GetPlatform(), General, "RunTransforms");
DAWN_TRY_ASSIGN(program, RunTransforms(&singleEntryPointTransform, GetTintProgram(), DAWN_TRY_ASSIGN(program, RunTransforms(&transformManager, GetTintProgram(),
transformInputs, nullptr, nullptr)); transformInputs, nullptr, nullptr));
} }

View File

@ -130,21 +130,9 @@ namespace dawn::native::vulkan {
break; break;
} }
case BindingInfoType::ExternalTexture: { case BindingInfoType::ExternalTexture:
const std::array<Ref<dawn::native::TextureViewBase>, kMaxPlanesPerFormat>& UNREACHABLE();
textureViews = GetBindingAsExternalTexture(bindingIndex)->GetTextureViews();
ASSERT(textureViews[2].Get() == nullptr);
TextureView* view = ToBackend(textureViews[0].Get());
writeImageInfo[numWrites].imageView = view->GetHandle();
writeImageInfo[numWrites].imageLayout = VulkanImageLayout(
ToBackend(view->GetTexture()), wgpu::TextureUsage::TextureBinding);
write.pImageInfo = &writeImageInfo[numWrites];
break; break;
}
} }
numWrites++; numWrites++;

View File

@ -165,6 +165,35 @@ namespace dawn::native::vulkan {
/* mayCollide */ false); /* mayCollide */ false);
transformInputs.Add<tint::transform::SingleEntryPoint::Config>(entryPointName); transformInputs.Add<tint::transform::SingleEntryPoint::Config>(entryPointName);
// Transform external textures into the binding locations specified in the bgl
// TODO(dawn:1082): Replace this block with ShaderModuleBase::AddExternalTextureTransform.
tint::transform::MultiplanarExternalTexture::BindingsMap newBindingsMap;
for (BindGroupIndex i : IterateBitSet(layout->GetBindGroupLayoutsMask())) {
BindGroupLayoutBase* bgl = layout->GetBindGroupLayout(i);
ExternalTextureBindingExpansionMap expansions =
bgl->GetExternalTextureBindingExpansionMap();
std::map<BindingNumber, dawn_native::ExternalTextureBindingExpansion>::iterator it =
expansions.begin();
while (it != expansions.end()) {
newBindingsMap[{static_cast<uint32_t>(i),
static_cast<uint32_t>(bgl->GetBindingIndex(it->second.plane0))}] = {
{static_cast<uint32_t>(i),
static_cast<uint32_t>(bgl->GetBindingIndex(it->second.plane1))},
{static_cast<uint32_t>(i),
static_cast<uint32_t>(bgl->GetBindingIndex(it->second.params))}};
it++;
}
}
if (!newBindingsMap.empty()) {
transformManager.Add<tint::transform::MultiplanarExternalTexture>();
transformInputs.Add<tint::transform::MultiplanarExternalTexture::NewBindingPoints>(
newBindingsMap);
}
tint::Program program; tint::Program program;
{ {
TRACE_EVENT0(GetDevice()->GetPlatform(), General, "RunTransforms"); TRACE_EVENT0(GetDevice()->GetPlatform(), General, "RunTransforms");

View File

@ -61,9 +61,13 @@ TEST_P(ExternalTextureTests, CreateExternalTextureSuccess) {
} }
TEST_P(ExternalTextureTests, SampleExternalTexture) { TEST_P(ExternalTextureTests, SampleExternalTexture) {
wgpu::ShaderModule vsModule = utils::CreateShaderModule(device, R"( // TODO(crbug.com/dawn/1263): SPIR-V has an issue compiling the output from Tint's external
// texture transform. Re-enable this test for OpenGL when the switch to Tint is complete.
DAWN_SUPPRESS_TEST_IF(IsOpenGL() || IsOpenGLES());
const wgpu::ShaderModule vsModule = utils::CreateShaderModule(device, R"(
@stage(vertex) fn main(@builtin(vertex_index) VertexIndex : u32) -> @builtin(position) vec4<f32> { @stage(vertex) fn main(@builtin(vertex_index) VertexIndex : u32) -> @builtin(position) vec4<f32> {
var positions : array<vec4<f32>, 3> = array<vec4<f32>, 3>( var positions = array<vec4<f32>, 3>(
vec4<f32>(-1.0, 1.0, 0.0, 1.0), vec4<f32>(-1.0, 1.0, 0.0, 1.0),
vec4<f32>(-1.0, -1.0, 0.0, 1.0), vec4<f32>(-1.0, -1.0, 0.0, 1.0),
vec4<f32>(1.0, 1.0, 0.0, 1.0) vec4<f32>(1.0, 1.0, 0.0, 1.0)
@ -102,6 +106,13 @@ TEST_P(ExternalTextureTests, SampleExternalTexture) {
queue.Submit(1, &commands); queue.Submit(1, &commands);
} }
// Pipeline Creation
utils::ComboRenderPipelineDescriptor descriptor;
descriptor.vertex.module = vsModule;
descriptor.cFragment.module = fsModule;
descriptor.cTargets[0].format = kFormat;
wgpu::RenderPipeline pipeline = device.CreateRenderPipeline(&descriptor);
// Create an ExternalTextureDescriptor from the texture view // Create an ExternalTextureDescriptor from the texture view
wgpu::ExternalTextureDescriptor externalDesc; wgpu::ExternalTextureDescriptor externalDesc;
externalDesc.plane0 = externalView; externalDesc.plane0 = externalView;
@ -112,19 +123,8 @@ TEST_P(ExternalTextureTests, SampleExternalTexture) {
// Create a sampler and bind group // Create a sampler and bind group
wgpu::Sampler sampler = device.CreateSampler(); wgpu::Sampler sampler = device.CreateSampler();
wgpu::BindGroupLayout bgl = utils::MakeBindGroupLayout( wgpu::BindGroup bindGroup = utils::MakeBindGroup(device, pipeline.GetBindGroupLayout(0),
device, {{0, wgpu::ShaderStage::Fragment, wgpu::SamplerBindingType::Filtering}, {{0, sampler}, {1, externalTexture}});
{1, wgpu::ShaderStage::Fragment, &utils::kExternalTextureBindingLayout}});
wgpu::BindGroup bindGroup =
utils::MakeBindGroup(device, bgl, {{0, sampler}, {1, externalTexture}});
// Pipeline Creation
utils::ComboRenderPipelineDescriptor descriptor;
descriptor.layout = utils::MakeBasicPipelineLayout(device, &bgl);
descriptor.vertex.module = vsModule;
descriptor.cFragment.module = fsModule;
descriptor.cTargets[0].format = kFormat;
wgpu::RenderPipeline pipeline = device.CreateRenderPipeline(&descriptor);
// Run the shader, which should sample from the external texture and draw a triangle into the // Run the shader, which should sample from the external texture and draw a triangle into the
// upper left corner of the render texture. // upper left corner of the render texture.
@ -145,6 +145,114 @@ TEST_P(ExternalTextureTests, SampleExternalTexture) {
EXPECT_PIXEL_RGBA8_EQ(RGBA8::kGreen, renderTexture, 0, 0); EXPECT_PIXEL_RGBA8_EQ(RGBA8::kGreen, renderTexture, 0, 0);
} }
TEST_P(ExternalTextureTests, SampleMultiplanarExternalTexture) {
// TODO(crbug.com/dawn/1263): SPIR-V has an issue compiling the output from Tint's external
// texture transform. Re-enable this test for OpenGL when the switch to Tint is complete.
DAWN_SUPPRESS_TEST_IF(IsOpenGL() || IsOpenGLES());
const wgpu::ShaderModule vsModule = utils::CreateShaderModule(device, R"(
@stage(vertex) fn main(@builtin(vertex_index) VertexIndex : u32) -> @builtin(position) vec4<f32> {
var positions = array<vec4<f32>, 3>(
vec4<f32>(-1.0, 1.0, 0.0, 1.0),
vec4<f32>(-1.0, -1.0, 0.0, 1.0),
vec4<f32>(1.0, 1.0, 0.0, 1.0)
);
return positions[VertexIndex];
})");
const wgpu::ShaderModule fsModule = utils::CreateShaderModule(device, R"(
@group(0) @binding(0) var s : sampler;
@group(0) @binding(1) var t : texture_external;
@stage(fragment) fn main(@builtin(position) FragCoord : vec4<f32>)
-> @location(0) vec4<f32> {
return textureSampleLevel(t, s, FragCoord.xy / vec2<f32>(4.0, 4.0));
})");
wgpu::Texture sampledTexturePlane0 =
Create2DTexture(device, kWidth, kHeight, wgpu::TextureFormat::R8Unorm,
wgpu::TextureUsage::TextureBinding | wgpu::TextureUsage::RenderAttachment);
wgpu::Texture sampledTexturePlane1 =
Create2DTexture(device, kWidth, kHeight, wgpu::TextureFormat::RG8Unorm,
wgpu::TextureUsage::TextureBinding | wgpu::TextureUsage::RenderAttachment);
wgpu::Texture renderTexture =
Create2DTexture(device, kWidth, kHeight, kFormat,
wgpu::TextureUsage::CopySrc | wgpu::TextureUsage::RenderAttachment);
// Create a texture view for the external texture
wgpu::TextureView externalViewPlane0 = sampledTexturePlane0.CreateView();
wgpu::TextureView externalViewPlane1 = sampledTexturePlane1.CreateView();
struct ConversionExpectation {
double y;
double u;
double v;
RGBA8 rgba;
};
std::array<ConversionExpectation, 4> expectations = {{{0.0f, 0.5f, 0.5f, RGBA8::kBlack},
{0.298f, 0.329f, 1.0f, RGBA8::kRed},
{0.584f, -0.168f, -0.823f, RGBA8::kGreen},
{0.113f, 1.0f, 0.419f, RGBA8::kBlue}}};
for (ConversionExpectation expectation : expectations) {
// Initialize the texture planes with YUV data
{
utils::ComboRenderPassDescriptor renderPass({externalViewPlane0, externalViewPlane1},
nullptr);
renderPass.cColorAttachments[0].clearColor = {expectation.y, 0.0f, 0.0f, 0.0f};
renderPass.cColorAttachments[1].clearColor = {expectation.u, expectation.v, 0.0f, 0.0f};
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass);
pass.End();
wgpu::CommandBuffer commands = encoder.Finish();
queue.Submit(1, &commands);
}
// Pipeline Creation
utils::ComboRenderPipelineDescriptor descriptor;
// descriptor.layout = utils::MakeBasicPipelineLayout(device, &bgl);
descriptor.vertex.module = vsModule;
descriptor.cFragment.module = fsModule;
descriptor.cTargets[0].format = kFormat;
wgpu::RenderPipeline pipeline = device.CreateRenderPipeline(&descriptor);
// Create an ExternalTextureDescriptor from the texture views
wgpu::ExternalTextureDescriptor externalDesc;
externalDesc.plane0 = externalViewPlane0;
externalDesc.plane1 = externalViewPlane1;
// Import the external texture
wgpu::ExternalTexture externalTexture = device.CreateExternalTexture(&externalDesc);
// Create a sampler and bind group
wgpu::Sampler sampler = device.CreateSampler();
wgpu::BindGroup bindGroup = utils::MakeBindGroup(device, pipeline.GetBindGroupLayout(0),
{{0, sampler}, {1, externalTexture}});
// Run the shader, which should sample from the external texture and draw a triangle into
// the upper left corner of the render texture.
wgpu::TextureView renderView = renderTexture.CreateView();
utils::ComboRenderPassDescriptor renderPass({renderView}, nullptr);
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass);
{
pass.SetPipeline(pipeline);
pass.SetBindGroup(0, bindGroup);
pass.Draw(3);
pass.End();
}
wgpu::CommandBuffer commands = encoder.Finish();
queue.Submit(1, &commands);
EXPECT_PIXEL_RGBA8_EQ(expectation.rgba, renderTexture, 0, 0);
}
}
DAWN_INSTANTIATE_TEST(ExternalTextureTests, DAWN_INSTANTIATE_TEST(ExternalTextureTests,
D3D12Backend(), D3D12Backend(),
MetalBackend(), MetalBackend(),

View File

@ -264,6 +264,57 @@ namespace {
} }
} }
// Test that submitting a render pass that contains a dereferenced external texture results in
// success
TEST_F(ExternalTextureTest, SubmitDereferencedExternalTextureInRenderPass) {
wgpu::TextureDescriptor textureDescriptor = CreateTextureDescriptor();
wgpu::Texture texture = device.CreateTexture(&textureDescriptor);
wgpu::ExternalTextureDescriptor externalDesc;
externalDesc.plane0 = texture.CreateView();
wgpu::ExternalTexture externalTexture = device.CreateExternalTexture(&externalDesc);
// Create a bind group that contains the external texture.
wgpu::BindGroupLayout bgl = utils::MakeBindGroupLayout(
device, {{0, wgpu::ShaderStage::Fragment, &utils::kExternalTextureBindingLayout}});
wgpu::BindGroup bindGroup = utils::MakeBindGroup(device, bgl, {{0, externalTexture}});
// Create another texture to use as a color attachment.
wgpu::TextureDescriptor renderTextureDescriptor = CreateTextureDescriptor();
wgpu::Texture renderTexture = device.CreateTexture(&renderTextureDescriptor);
wgpu::TextureView renderView = renderTexture.CreateView();
utils::ComboRenderPassDescriptor renderPass({renderView}, nullptr);
// Control case should succeed.
{
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass);
{
pass.SetBindGroup(0, bindGroup);
pass.End();
}
wgpu::CommandBuffer commands = encoder.Finish();
queue.Submit(1, &commands);
}
// Dereferencing the external texture should not result in a use-after-free error.
{
externalTexture = nullptr;
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass);
{
pass.SetBindGroup(0, bindGroup);
pass.End();
}
wgpu::CommandBuffer commands = encoder.Finish();
queue.Submit(1, &commands);
}
}
// Test that submitting a render pass that contains a destroyed external texture plane // Test that submitting a render pass that contains a destroyed external texture plane
// results in an error. // results in an error.
TEST_F(ExternalTextureTest, SubmitDestroyedExternalTexturePlaneInRenderPass) { TEST_F(ExternalTextureTest, SubmitDestroyedExternalTexturePlaneInRenderPass) {