mirror of
https://github.com/encounter/dawn-cmake.git
synced 2025-05-17 04:41:23 +00:00
Implement External Texture Binding Functionality
Adds functionality to BindGroupLayout and BindGroup to allow GPUExternalTexture bindings. Bug: dawn:728 Change-Id: I651b28606dceda15f0a944711ddba639df77c1a3 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/47381 Reviewed-by: Corentin Wallez <cwallez@chromium.org> Commit-Queue: Corentin Wallez <cwallez@chromium.org>
This commit is contained in:
parent
a9e39e11a8
commit
39633e2da2
20
dawn.json
20
dawn.json
@ -65,7 +65,7 @@
|
|||||||
},
|
},
|
||||||
"bind group entry": {
|
"bind group entry": {
|
||||||
"category": "structure",
|
"category": "structure",
|
||||||
"extensible": false,
|
"extensible": true,
|
||||||
"members": [
|
"members": [
|
||||||
{"name": "binding", "type": "uint32_t"},
|
{"name": "binding", "type": "uint32_t"},
|
||||||
{"name": "buffer", "type": "buffer", "optional": true},
|
{"name": "buffer", "type": "buffer", "optional": true},
|
||||||
@ -146,6 +146,20 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
||||||
|
"external texture binding entry": {
|
||||||
|
"category": "structure",
|
||||||
|
"chained": true,
|
||||||
|
"members": [
|
||||||
|
{"name": "external texture", "type": "external texture"}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
"external texture binding layout": {
|
||||||
|
"category": "structure",
|
||||||
|
"chained": true,
|
||||||
|
"members": []
|
||||||
|
},
|
||||||
|
|
||||||
"storage texture access": {
|
"storage texture access": {
|
||||||
"category": "enum",
|
"category": "enum",
|
||||||
"values": [
|
"values": [
|
||||||
@ -1787,7 +1801,9 @@
|
|||||||
{"value": 5, "name": "shader module SPIRV descriptor"},
|
{"value": 5, "name": "shader module SPIRV descriptor"},
|
||||||
{"value": 6, "name": "shader module WGSL descriptor"},
|
{"value": 6, "name": "shader module WGSL descriptor"},
|
||||||
{"value": 7, "name": "primitive depth clamping state"},
|
{"value": 7, "name": "primitive depth clamping state"},
|
||||||
{"value": 8, "name": "surface descriptor from windows core window"}
|
{"value": 8, "name": "surface descriptor from windows core window"},
|
||||||
|
{"value": 9, "name": "external texture binding entry"},
|
||||||
|
{"value": 10, "name": "external texture binding layout"}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"texture": {
|
"texture": {
|
||||||
|
@ -68,4 +68,10 @@ static constexpr uint64_t kCopyBufferToBufferOffsetAlignment = 4u;
|
|||||||
// * 1024 / 8.
|
// * 1024 / 8.
|
||||||
static constexpr uint32_t kMaxQueryCount = 8192u;
|
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 kSamplersPerExternalTexture = 1u;
|
||||||
|
static constexpr uint8_t kUniformsPerExternalTexture = 1u;
|
||||||
|
|
||||||
#endif // COMMON_CONSTANTS_H_
|
#endif // COMMON_CONSTANTS_H_
|
||||||
|
@ -19,7 +19,9 @@
|
|||||||
#include "common/ityp_bitset.h"
|
#include "common/ityp_bitset.h"
|
||||||
#include "dawn_native/BindGroupLayout.h"
|
#include "dawn_native/BindGroupLayout.h"
|
||||||
#include "dawn_native/Buffer.h"
|
#include "dawn_native/Buffer.h"
|
||||||
|
#include "dawn_native/ChainUtils_autogen.h"
|
||||||
#include "dawn_native/Device.h"
|
#include "dawn_native/Device.h"
|
||||||
|
#include "dawn_native/ExternalTexture.h"
|
||||||
#include "dawn_native/Sampler.h"
|
#include "dawn_native/Sampler.h"
|
||||||
#include "dawn_native/Texture.h"
|
#include "dawn_native/Texture.h"
|
||||||
|
|
||||||
@ -33,7 +35,7 @@ namespace dawn_native {
|
|||||||
const BindGroupEntry& entry,
|
const BindGroupEntry& entry,
|
||||||
const BindingInfo& bindingInfo) {
|
const BindingInfo& bindingInfo) {
|
||||||
if (entry.buffer == nullptr || entry.sampler != nullptr ||
|
if (entry.buffer == nullptr || entry.sampler != nullptr ||
|
||||||
entry.textureView != nullptr) {
|
entry.textureView != nullptr || entry.nextInChain != nullptr) {
|
||||||
return DAWN_VALIDATION_ERROR("Expected buffer binding");
|
return DAWN_VALIDATION_ERROR("Expected buffer binding");
|
||||||
}
|
}
|
||||||
DAWN_TRY(device->ValidateObject(entry.buffer));
|
DAWN_TRY(device->ValidateObject(entry.buffer));
|
||||||
@ -111,7 +113,7 @@ namespace dawn_native {
|
|||||||
const BindGroupEntry& entry,
|
const BindGroupEntry& entry,
|
||||||
const BindingInfo& bindingInfo) {
|
const BindingInfo& bindingInfo) {
|
||||||
if (entry.textureView == nullptr || entry.sampler != nullptr ||
|
if (entry.textureView == nullptr || entry.sampler != nullptr ||
|
||||||
entry.buffer != nullptr) {
|
entry.buffer != nullptr || entry.nextInChain != nullptr) {
|
||||||
return DAWN_VALIDATION_ERROR("Expected texture binding");
|
return DAWN_VALIDATION_ERROR("Expected texture binding");
|
||||||
}
|
}
|
||||||
DAWN_TRY(device->ValidateObject(entry.textureView));
|
DAWN_TRY(device->ValidateObject(entry.textureView));
|
||||||
@ -176,7 +178,7 @@ namespace dawn_native {
|
|||||||
const BindGroupEntry& entry,
|
const BindGroupEntry& entry,
|
||||||
const BindingInfo& bindingInfo) {
|
const BindingInfo& bindingInfo) {
|
||||||
if (entry.sampler == nullptr || entry.textureView != nullptr ||
|
if (entry.sampler == nullptr || entry.textureView != nullptr ||
|
||||||
entry.buffer != nullptr) {
|
entry.buffer != nullptr || entry.nextInChain != nullptr) {
|
||||||
return DAWN_VALIDATION_ERROR("Expected sampler binding");
|
return DAWN_VALIDATION_ERROR("Expected sampler binding");
|
||||||
}
|
}
|
||||||
DAWN_TRY(device->ValidateObject(entry.sampler));
|
DAWN_TRY(device->ValidateObject(entry.sampler));
|
||||||
@ -203,6 +205,25 @@ namespace dawn_native {
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MaybeError ValidateExternalTextureBinding(const DeviceBase* device,
|
||||||
|
const BindGroupEntry& entry,
|
||||||
|
const BindingInfo& bindingInfo) {
|
||||||
|
const ExternalTextureBindingEntry* externalTextureBindingEntry = nullptr;
|
||||||
|
FindInChain(entry.nextInChain, &externalTextureBindingEntry);
|
||||||
|
|
||||||
|
if (entry.sampler != nullptr || entry.textureView != nullptr ||
|
||||||
|
entry.buffer != nullptr || externalTextureBindingEntry == nullptr) {
|
||||||
|
return DAWN_VALIDATION_ERROR("Expected external texture binding");
|
||||||
|
}
|
||||||
|
|
||||||
|
DAWN_TRY(ValidateSingleSType(externalTextureBindingEntry->nextInChain,
|
||||||
|
wgpu::SType::ExternalTextureBindingEntry));
|
||||||
|
|
||||||
|
DAWN_TRY(device->ValidateObject(externalTextureBindingEntry->externalTexture));
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
} // anonymous namespace
|
} // anonymous namespace
|
||||||
|
|
||||||
MaybeError ValidateBindGroupDescriptor(DeviceBase* device,
|
MaybeError ValidateBindGroupDescriptor(DeviceBase* device,
|
||||||
@ -250,6 +271,9 @@ namespace dawn_native {
|
|||||||
case BindingInfoType::Sampler:
|
case BindingInfoType::Sampler:
|
||||||
DAWN_TRY(ValidateSamplerBinding(device, entry, bindingInfo));
|
DAWN_TRY(ValidateSamplerBinding(device, entry, bindingInfo));
|
||||||
break;
|
break;
|
||||||
|
case BindingInfoType::ExternalTexture:
|
||||||
|
DAWN_TRY(ValidateExternalTextureBinding(device, entry, bindingInfo));
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -309,6 +333,14 @@ namespace dawn_native {
|
|||||||
mBindingData.bindings[bindingIndex] = entry.sampler;
|
mBindingData.bindings[bindingIndex] = entry.sampler;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const ExternalTextureBindingEntry* externalTextureBindingEntry = nullptr;
|
||||||
|
FindInChain(entry.nextInChain, &externalTextureBindingEntry);
|
||||||
|
if (externalTextureBindingEntry != nullptr) {
|
||||||
|
ASSERT(mBindingData.bindings[bindingIndex] == nullptr);
|
||||||
|
mBindingData.bindings[bindingIndex] = externalTextureBindingEntry->externalTexture;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t packedIdx = 0;
|
uint32_t packedIdx = 0;
|
||||||
@ -388,4 +420,12 @@ namespace dawn_native {
|
|||||||
return static_cast<TextureViewBase*>(mBindingData.bindings[bindingIndex].Get());
|
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());
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace dawn_native
|
} // namespace dawn_native
|
||||||
|
@ -49,6 +49,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);
|
||||||
|
|
||||||
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
|
||||||
|
@ -15,6 +15,8 @@
|
|||||||
#include "dawn_native/BindGroupLayout.h"
|
#include "dawn_native/BindGroupLayout.h"
|
||||||
|
|
||||||
#include "common/BitSetIterator.h"
|
#include "common/BitSetIterator.h"
|
||||||
|
|
||||||
|
#include "dawn_native/ChainUtils_autogen.h"
|
||||||
#include "dawn_native/Device.h"
|
#include "dawn_native/Device.h"
|
||||||
#include "dawn_native/ObjectContentHasher.h"
|
#include "dawn_native/ObjectContentHasher.h"
|
||||||
#include "dawn_native/PerStage.h"
|
#include "dawn_native/PerStage.h"
|
||||||
@ -147,10 +149,16 @@ namespace dawn_native {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const ExternalTextureBindingLayout* externalTextureBindingLayout = nullptr;
|
||||||
|
FindInChain(entry.nextInChain, &externalTextureBindingLayout);
|
||||||
|
if (externalTextureBindingLayout != nullptr) {
|
||||||
|
bindingMemberCount++;
|
||||||
|
}
|
||||||
|
|
||||||
if (bindingMemberCount != 1) {
|
if (bindingMemberCount != 1) {
|
||||||
return DAWN_VALIDATION_ERROR(
|
return DAWN_VALIDATION_ERROR(
|
||||||
"Exactly one of buffer, sampler, texture, or storageTexture must be set for "
|
"Exactly one of buffer, sampler, texture, storageTexture, or externalTexture "
|
||||||
"each BindGroupLayoutEntry");
|
"must be set for each BindGroupLayoutEntry");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!IsSubset(entry.visibility, allowedStages)) {
|
if (!IsSubset(entry.visibility, allowedStages)) {
|
||||||
@ -190,6 +198,8 @@ namespace dawn_native {
|
|||||||
return a.storageTexture.access != b.storageTexture.access ||
|
return a.storageTexture.access != b.storageTexture.access ||
|
||||||
a.storageTexture.viewDimension != b.storageTexture.viewDimension ||
|
a.storageTexture.viewDimension != b.storageTexture.viewDimension ||
|
||||||
a.storageTexture.format != b.storageTexture.format;
|
a.storageTexture.format != b.storageTexture.format;
|
||||||
|
case BindingInfoType::ExternalTexture:
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -229,6 +239,12 @@ namespace dawn_native {
|
|||||||
if (binding.storageTexture.viewDimension == wgpu::TextureViewDimension::Undefined) {
|
if (binding.storageTexture.viewDimension == wgpu::TextureViewDimension::Undefined) {
|
||||||
bindingInfo.storageTexture.viewDimension = wgpu::TextureViewDimension::e2D;
|
bindingInfo.storageTexture.viewDimension = wgpu::TextureViewDimension::e2D;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
const ExternalTextureBindingLayout* externalTextureBindingLayout = nullptr;
|
||||||
|
FindInChain(binding.nextInChain, &externalTextureBindingLayout);
|
||||||
|
if (externalTextureBindingLayout != nullptr) {
|
||||||
|
bindingInfo.bindingType = BindingInfoType::ExternalTexture;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return bindingInfo;
|
return bindingInfo;
|
||||||
@ -309,6 +325,8 @@ namespace dawn_native {
|
|||||||
return aInfo.storageTexture.format < bInfo.storageTexture.format;
|
return aInfo.storageTexture.format < bInfo.storageTexture.format;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case BindingInfoType::ExternalTexture:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,8 @@
|
|||||||
|
|
||||||
#include "dawn_native/BindingInfo.h"
|
#include "dawn_native/BindingInfo.h"
|
||||||
|
|
||||||
|
#include "dawn_native/ChainUtils_autogen.h"
|
||||||
|
|
||||||
namespace dawn_native {
|
namespace dawn_native {
|
||||||
|
|
||||||
void IncrementBindingCounts(BindingCounts* bindingCounts, const BindGroupLayoutEntry& entry) {
|
void IncrementBindingCounts(BindingCounts* bindingCounts, const BindGroupLayoutEntry& entry) {
|
||||||
@ -56,6 +58,12 @@ namespace dawn_native {
|
|||||||
perStageBindingCountMember = &PerStageBindingCounts::sampledTextureCount;
|
perStageBindingCountMember = &PerStageBindingCounts::sampledTextureCount;
|
||||||
} else if (entry.storageTexture.access != wgpu::StorageTextureAccess::Undefined) {
|
} else if (entry.storageTexture.access != wgpu::StorageTextureAccess::Undefined) {
|
||||||
perStageBindingCountMember = &PerStageBindingCounts::storageTextureCount;
|
perStageBindingCountMember = &PerStageBindingCounts::storageTextureCount;
|
||||||
|
} else {
|
||||||
|
const ExternalTextureBindingLayout* externalTextureBindingLayout;
|
||||||
|
FindInChain(entry.nextInChain, &externalTextureBindingLayout);
|
||||||
|
if (externalTextureBindingLayout != nullptr) {
|
||||||
|
perStageBindingCountMember = &PerStageBindingCounts::externalTextureCount;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ASSERT(perStageBindingCountMember != nullptr);
|
ASSERT(perStageBindingCountMember != nullptr);
|
||||||
@ -81,6 +89,8 @@ namespace dawn_native {
|
|||||||
rhs.perStage[stage].storageTextureCount;
|
rhs.perStage[stage].storageTextureCount;
|
||||||
bindingCounts->perStage[stage].uniformBufferCount +=
|
bindingCounts->perStage[stage].uniformBufferCount +=
|
||||||
rhs.perStage[stage].uniformBufferCount;
|
rhs.perStage[stage].uniformBufferCount;
|
||||||
|
bindingCounts->perStage[stage].externalTextureCount +=
|
||||||
|
rhs.perStage[stage].externalTextureCount;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -104,25 +114,65 @@ namespace dawn_native {
|
|||||||
"The number of sampled textures exceeds the maximum "
|
"The number of sampled textures exceeds the maximum "
|
||||||
"per-stage limit.");
|
"per-stage limit.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The per-stage number of external textures is bound by the maximum sampled textures
|
||||||
|
// per stage.
|
||||||
|
if (bindingCounts.perStage[stage].externalTextureCount >
|
||||||
|
kMaxSampledTexturesPerShaderStage / kSampledTexturesPerExternalTexture) {
|
||||||
|
return DAWN_VALIDATION_ERROR(
|
||||||
|
"The number of external textures exceeds the maximum "
|
||||||
|
"per-stage limit.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bindingCounts.perStage[stage].sampledTextureCount +
|
||||||
|
(bindingCounts.perStage[stage].externalTextureCount *
|
||||||
|
kSampledTexturesPerExternalTexture) >
|
||||||
|
kMaxSampledTexturesPerShaderStage) {
|
||||||
|
return DAWN_VALIDATION_ERROR(
|
||||||
|
"The combination of sampled textures and external textures exceeds the maximum "
|
||||||
|
"per-stage limit.");
|
||||||
|
}
|
||||||
|
|
||||||
if (bindingCounts.perStage[stage].samplerCount > kMaxSamplersPerShaderStage) {
|
if (bindingCounts.perStage[stage].samplerCount > kMaxSamplersPerShaderStage) {
|
||||||
return DAWN_VALIDATION_ERROR(
|
return DAWN_VALIDATION_ERROR(
|
||||||
"The number of samplers exceeds the maximum per-stage limit.");
|
"The number of samplers exceeds the maximum per-stage limit.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (bindingCounts.perStage[stage].samplerCount +
|
||||||
|
(bindingCounts.perStage[stage].externalTextureCount *
|
||||||
|
kSamplersPerExternalTexture) >
|
||||||
|
kMaxSamplersPerShaderStage) {
|
||||||
|
return DAWN_VALIDATION_ERROR(
|
||||||
|
"The combination of samplers and external textures exceeds the maximum "
|
||||||
|
"per-stage limit.");
|
||||||
|
}
|
||||||
|
|
||||||
if (bindingCounts.perStage[stage].storageBufferCount >
|
if (bindingCounts.perStage[stage].storageBufferCount >
|
||||||
kMaxStorageBuffersPerShaderStage) {
|
kMaxStorageBuffersPerShaderStage) {
|
||||||
return DAWN_VALIDATION_ERROR(
|
return DAWN_VALIDATION_ERROR(
|
||||||
"The number of storage buffers exceeds the maximum per-stage limit.");
|
"The number of storage buffers exceeds the maximum per-stage limit.");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bindingCounts.perStage[stage].storageTextureCount >
|
if (bindingCounts.perStage[stage].storageTextureCount >
|
||||||
kMaxStorageTexturesPerShaderStage) {
|
kMaxStorageTexturesPerShaderStage) {
|
||||||
return DAWN_VALIDATION_ERROR(
|
return DAWN_VALIDATION_ERROR(
|
||||||
"The number of storage textures exceeds the maximum per-stage limit.");
|
"The number of storage textures exceeds the maximum per-stage limit.");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bindingCounts.perStage[stage].uniformBufferCount >
|
if (bindingCounts.perStage[stage].uniformBufferCount >
|
||||||
kMaxUniformBuffersPerShaderStage) {
|
kMaxUniformBuffersPerShaderStage) {
|
||||||
return DAWN_VALIDATION_ERROR(
|
return DAWN_VALIDATION_ERROR(
|
||||||
"The number of uniform buffers exceeds the maximum per-stage limit.");
|
"The number of uniform buffers exceeds the maximum per-stage limit.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (bindingCounts.perStage[stage].uniformBufferCount +
|
||||||
|
(bindingCounts.perStage[stage].externalTextureCount *
|
||||||
|
kUniformsPerExternalTexture) >
|
||||||
|
kMaxUniformBuffersPerShaderStage) {
|
||||||
|
return DAWN_VALIDATION_ERROR(
|
||||||
|
"The combination of uniform buffers and external textures exceeds the maximum "
|
||||||
|
"per-stage limit.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
|
@ -48,12 +48,7 @@ namespace dawn_native {
|
|||||||
// TODO(enga): Figure out a good number for this.
|
// TODO(enga): Figure out a good number for this.
|
||||||
static constexpr uint32_t kMaxOptimalBindingsPerGroup = 32;
|
static constexpr uint32_t kMaxOptimalBindingsPerGroup = 32;
|
||||||
|
|
||||||
enum class BindingInfoType {
|
enum class BindingInfoType { Buffer, Sampler, Texture, StorageTexture, ExternalTexture };
|
||||||
Buffer,
|
|
||||||
Sampler,
|
|
||||||
Texture,
|
|
||||||
StorageTexture,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct BindingInfo {
|
struct BindingInfo {
|
||||||
BindingNumber binding;
|
BindingNumber binding;
|
||||||
@ -74,6 +69,7 @@ namespace dawn_native {
|
|||||||
uint32_t storageBufferCount;
|
uint32_t storageBufferCount;
|
||||||
uint32_t storageTextureCount;
|
uint32_t storageTextureCount;
|
||||||
uint32_t uniformBufferCount;
|
uint32_t uniformBufferCount;
|
||||||
|
uint32_t externalTextureCount;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct BindingCounts {
|
struct BindingCounts {
|
||||||
|
@ -85,7 +85,7 @@ namespace dawn_native {
|
|||||||
|
|
||||||
ExternalTextureBase::ExternalTextureBase(DeviceBase* device,
|
ExternalTextureBase::ExternalTextureBase(DeviceBase* device,
|
||||||
const ExternalTextureDescriptor* descriptor)
|
const ExternalTextureDescriptor* descriptor)
|
||||||
: ObjectBase(device) {
|
: ObjectBase(device), mState(ExternalTextureState::Alive) {
|
||||||
textureViews[0] = descriptor->plane0;
|
textureViews[0] = descriptor->plane0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -93,15 +93,24 @@ namespace dawn_native {
|
|||||||
: ObjectBase(device, tag) {
|
: ObjectBase(device, tag) {
|
||||||
}
|
}
|
||||||
|
|
||||||
std::array<Ref<TextureViewBase>, kMaxPlanesPerFormat> ExternalTextureBase::GetTextureViews()
|
const std::array<Ref<TextureViewBase>, kMaxPlanesPerFormat>&
|
||||||
const {
|
ExternalTextureBase::GetTextureViews() const {
|
||||||
return textureViews;
|
return textureViews;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MaybeError ExternalTextureBase::ValidateCanUseInSubmitNow() const {
|
||||||
|
ASSERT(!IsError());
|
||||||
|
if (mState == ExternalTextureState::Destroyed) {
|
||||||
|
return DAWN_VALIDATION_ERROR("Destroyed external texture used in a submit");
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
void ExternalTextureBase::APIDestroy() {
|
void ExternalTextureBase::APIDestroy() {
|
||||||
if (GetDevice()->ConsumedError(GetDevice()->ValidateObject(this))) {
|
if (GetDevice()->ConsumedError(GetDevice()->ValidateObject(this))) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
mState = ExternalTextureState::Destroyed;
|
||||||
ASSERT(!IsError());
|
ASSERT(!IsError());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,11 +31,14 @@ namespace dawn_native {
|
|||||||
|
|
||||||
class ExternalTextureBase : public ObjectBase {
|
class ExternalTextureBase : public ObjectBase {
|
||||||
public:
|
public:
|
||||||
|
enum class ExternalTextureState { Alive, Destroyed };
|
||||||
static ResultOrError<Ref<ExternalTextureBase>> Create(
|
static ResultOrError<Ref<ExternalTextureBase>> Create(
|
||||||
DeviceBase* device,
|
DeviceBase* device,
|
||||||
const ExternalTextureDescriptor* descriptor);
|
const ExternalTextureDescriptor* descriptor);
|
||||||
|
|
||||||
std::array<Ref<TextureViewBase>, kMaxPlanesPerFormat> GetTextureViews() const;
|
const std::array<Ref<TextureViewBase>, kMaxPlanesPerFormat>& GetTextureViews() const;
|
||||||
|
|
||||||
|
MaybeError ValidateCanUseInSubmitNow() const;
|
||||||
|
|
||||||
static ExternalTextureBase* MakeError(DeviceBase* device);
|
static ExternalTextureBase* MakeError(DeviceBase* device);
|
||||||
|
|
||||||
@ -45,6 +48,7 @@ namespace dawn_native {
|
|||||||
ExternalTextureBase(DeviceBase* device, const ExternalTextureDescriptor* descriptor);
|
ExternalTextureBase(DeviceBase* device, const ExternalTextureDescriptor* descriptor);
|
||||||
ExternalTextureBase(DeviceBase* device, ObjectBase::ErrorTag tag);
|
ExternalTextureBase(DeviceBase* device, ObjectBase::ErrorTag tag);
|
||||||
std::array<Ref<TextureViewBase>, kMaxPlanesPerFormat> textureViews;
|
std::array<Ref<TextureViewBase>, kMaxPlanesPerFormat> textureViews;
|
||||||
|
ExternalTextureState mState;
|
||||||
};
|
};
|
||||||
} // namespace dawn_native
|
} // namespace dawn_native
|
||||||
|
|
||||||
|
@ -30,6 +30,7 @@ namespace dawn_native {
|
|||||||
class CommandBufferBase;
|
class CommandBufferBase;
|
||||||
class CommandEncoder;
|
class CommandEncoder;
|
||||||
class ComputePassEncoder;
|
class ComputePassEncoder;
|
||||||
|
class ExternalTextureBase;
|
||||||
class Fence;
|
class Fence;
|
||||||
class InstanceBase;
|
class InstanceBase;
|
||||||
class PipelineBase;
|
class PipelineBase;
|
||||||
|
@ -44,6 +44,8 @@ namespace dawn_native {
|
|||||||
|
|
||||||
std::vector<TextureBase*> textures;
|
std::vector<TextureBase*> textures;
|
||||||
std::vector<TextureSubresourceUsage> textureUsages;
|
std::vector<TextureSubresourceUsage> textureUsages;
|
||||||
|
|
||||||
|
std::vector<ExternalTextureBase*> externalTextures;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Contains all the resource usage data for a compute pass.
|
// Contains all the resource usage data for a compute pass.
|
||||||
@ -64,6 +66,7 @@ namespace dawn_native {
|
|||||||
// All the resources referenced by this compute pass for validation in Queue::Submit.
|
// All the resources referenced by this compute pass for validation in Queue::Submit.
|
||||||
std::set<BufferBase*> referencedBuffers;
|
std::set<BufferBase*> referencedBuffers;
|
||||||
std::set<TextureBase*> referencedTextures;
|
std::set<TextureBase*> referencedTextures;
|
||||||
|
std::set<ExternalTextureBase*> referencedExternalTextures;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Contains all the resource usage data for a render pass.
|
// Contains all the resource usage data for a render pass.
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
#include "dawn_native/BindGroup.h"
|
#include "dawn_native/BindGroup.h"
|
||||||
#include "dawn_native/Buffer.h"
|
#include "dawn_native/Buffer.h"
|
||||||
#include "dawn_native/EnumMaskIterator.h"
|
#include "dawn_native/EnumMaskIterator.h"
|
||||||
|
#include "dawn_native/ExternalTexture.h"
|
||||||
#include "dawn_native/Format.h"
|
#include "dawn_native/Format.h"
|
||||||
#include "dawn_native/QuerySet.h"
|
#include "dawn_native/QuerySet.h"
|
||||||
#include "dawn_native/Texture.h"
|
#include "dawn_native/Texture.h"
|
||||||
@ -109,6 +110,23 @@ namespace dawn_native {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case BindingInfoType::ExternalTexture: {
|
||||||
|
ExternalTextureBase* externalTexture =
|
||||||
|
group->GetBindingAsExternalTexture(bindingIndex);
|
||||||
|
|
||||||
|
const std::array<Ref<TextureViewBase>, kMaxPlanesPerFormat>& textureViews =
|
||||||
|
externalTexture->GetTextureViews();
|
||||||
|
|
||||||
|
// Only single-plane formats are supported right now, so assert only one
|
||||||
|
// view exists.
|
||||||
|
ASSERT(textureViews[1].Get() == nullptr);
|
||||||
|
ASSERT(textureViews[2].Get() == nullptr);
|
||||||
|
|
||||||
|
mExternalTextureUsages.insert(externalTexture);
|
||||||
|
TextureViewUsedAs(textureViews[0].Get(), wgpu::TextureUsage::Sampled);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case BindingInfoType::Sampler:
|
case BindingInfoType::Sampler:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -132,8 +150,13 @@ namespace dawn_native {
|
|||||||
result.textureUsages.push_back(std::move(it.second));
|
result.textureUsages.push_back(std::move(it.second));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (auto& it : mExternalTextureUsages) {
|
||||||
|
result.externalTextures.push_back(it);
|
||||||
|
}
|
||||||
|
|
||||||
mBufferUsages.clear();
|
mBufferUsages.clear();
|
||||||
mTextureUsages.clear();
|
mTextureUsages.clear();
|
||||||
|
mExternalTextureUsages.clear();
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -162,6 +185,22 @@ namespace dawn_native {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case BindingInfoType::ExternalTexture: {
|
||||||
|
ExternalTextureBase* externalTexture =
|
||||||
|
group->GetBindingAsExternalTexture(index);
|
||||||
|
const std::array<Ref<TextureViewBase>, kMaxPlanesPerFormat>& textureViews =
|
||||||
|
externalTexture->GetTextureViews();
|
||||||
|
|
||||||
|
// Only single-plane formats are supported right now, so assert only one
|
||||||
|
// view exists.
|
||||||
|
ASSERT(textureViews[1].Get() == nullptr);
|
||||||
|
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;
|
||||||
|
@ -25,6 +25,7 @@ namespace dawn_native {
|
|||||||
|
|
||||||
class BindGroupBase;
|
class BindGroupBase;
|
||||||
class BufferBase;
|
class BufferBase;
|
||||||
|
class ExternalTextureBase;
|
||||||
class QuerySetBase;
|
class QuerySetBase;
|
||||||
class TextureBase;
|
class TextureBase;
|
||||||
|
|
||||||
@ -46,6 +47,7 @@ namespace dawn_native {
|
|||||||
private:
|
private:
|
||||||
std::map<BufferBase*, wgpu::BufferUsage> mBufferUsages;
|
std::map<BufferBase*, wgpu::BufferUsage> mBufferUsages;
|
||||||
std::map<TextureBase*, TextureSubresourceUsage> mTextureUsages;
|
std::map<TextureBase*, TextureSubresourceUsage> mTextureUsages;
|
||||||
|
std::set<ExternalTextureBase*> mExternalTextureUsages;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Helper class to build ComputePassResourceUsages
|
// Helper class to build ComputePassResourceUsages
|
||||||
|
@ -147,6 +147,15 @@ namespace dawn_native {
|
|||||||
case BindingInfoType::StorageTexture:
|
case BindingInfoType::StorageTexture:
|
||||||
entry.storageTexture = shaderBinding.storageTexture;
|
entry.storageTexture = shaderBinding.storageTexture;
|
||||||
break;
|
break;
|
||||||
|
case BindingInfoType::ExternalTexture:
|
||||||
|
// TODO(dawn:728) On backend configurations that use SPIRV-Cross to reflect
|
||||||
|
// shader info - the shader must have been already transformed prior to
|
||||||
|
// reflecting the shader. During transformation, all instances of
|
||||||
|
// texture_external are changed to texture_2d<f32>. This means that when
|
||||||
|
// extracting shader info, external textures will be seen as sampled 2d
|
||||||
|
// textures. In the future when Dawn no longer uses SPIRV-Cross, we should
|
||||||
|
// handle external textures here.
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
return entry;
|
return entry;
|
||||||
};
|
};
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
#include "dawn_native/CopyTextureForBrowserHelper.h"
|
#include "dawn_native/CopyTextureForBrowserHelper.h"
|
||||||
#include "dawn_native/Device.h"
|
#include "dawn_native/Device.h"
|
||||||
#include "dawn_native/DynamicUploader.h"
|
#include "dawn_native/DynamicUploader.h"
|
||||||
|
#include "dawn_native/ExternalTexture.h"
|
||||||
#include "dawn_native/QuerySet.h"
|
#include "dawn_native/QuerySet.h"
|
||||||
#include "dawn_native/RenderPassEncoder.h"
|
#include "dawn_native/RenderPassEncoder.h"
|
||||||
#include "dawn_native/RenderPipeline.h"
|
#include "dawn_native/RenderPipeline.h"
|
||||||
@ -382,6 +383,10 @@ namespace dawn_native {
|
|||||||
for (const TextureBase* texture : scope.textures) {
|
for (const TextureBase* texture : scope.textures) {
|
||||||
DAWN_TRY(texture->ValidateCanUseInSubmitNow());
|
DAWN_TRY(texture->ValidateCanUseInSubmitNow());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (const ExternalTextureBase* externalTexture : scope.externalTextures) {
|
||||||
|
DAWN_TRY(externalTexture->ValidateCanUseInSubmitNow());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const ComputePassResourceUsage& pass : usages.computePasses) {
|
for (const ComputePassResourceUsage& pass : usages.computePasses) {
|
||||||
@ -391,6 +396,9 @@ namespace dawn_native {
|
|||||||
for (const TextureBase* texture : pass.referencedTextures) {
|
for (const TextureBase* texture : pass.referencedTextures) {
|
||||||
DAWN_TRY(texture->ValidateCanUseInSubmitNow());
|
DAWN_TRY(texture->ValidateCanUseInSubmitNow());
|
||||||
}
|
}
|
||||||
|
for (const ExternalTextureBase* externalTexture : pass.referencedExternalTextures) {
|
||||||
|
DAWN_TRY(externalTexture->ValidateCanUseInSubmitNow());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const BufferBase* buffer : usages.topLevelBuffers) {
|
for (const BufferBase* buffer : usages.topLevelBuffers) {
|
||||||
|
@ -159,6 +159,8 @@ namespace dawn_native {
|
|||||||
case tint::inspector::ResourceBinding::ResourceType::kReadOnlyStorageTexture:
|
case tint::inspector::ResourceBinding::ResourceType::kReadOnlyStorageTexture:
|
||||||
case tint::inspector::ResourceBinding::ResourceType::kWriteOnlyStorageTexture:
|
case tint::inspector::ResourceBinding::ResourceType::kWriteOnlyStorageTexture:
|
||||||
return BindingInfoType::StorageTexture;
|
return BindingInfoType::StorageTexture;
|
||||||
|
case tint::inspector::ResourceBinding::ResourceType::kExternalTexture:
|
||||||
|
return BindingInfoType::ExternalTexture;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
@ -503,9 +505,19 @@ namespace dawn_native {
|
|||||||
const BindingInfo& layoutInfo = layout->GetBindingInfo(bindingIndex);
|
const BindingInfo& layoutInfo = layout->GetBindingInfo(bindingIndex);
|
||||||
|
|
||||||
if (layoutInfo.bindingType != shaderInfo.bindingType) {
|
if (layoutInfo.bindingType != shaderInfo.bindingType) {
|
||||||
return DAWN_VALIDATION_ERROR(
|
// TODO(dawn:728) On backend configurations that use SPIRV-Cross to reflect
|
||||||
"The binding type of the bind group layout entry conflicts " +
|
// shader info - the shader must have been already transformed prior to
|
||||||
GetShaderDeclarationString(group, bindingNumber));
|
// reflecting the shader. During transformation, all instances of
|
||||||
|
// texture_external are changed to texture_2d<f32>. This means that when
|
||||||
|
// extracting shader info, external textures will be seen as sampled 2d
|
||||||
|
// textures. In the future when Dawn no longer uses SPIRV-Cross, the
|
||||||
|
// if-statement below should be removed.
|
||||||
|
if (layoutInfo.bindingType != BindingInfoType::ExternalTexture ||
|
||||||
|
shaderInfo.bindingType != BindingInfoType::Texture) {
|
||||||
|
return DAWN_VALIDATION_ERROR(
|
||||||
|
"The binding type of the bind group layout entry conflicts " +
|
||||||
|
GetShaderDeclarationString(group, bindingNumber));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((layoutInfo.visibility & StageBit(entryPoint.stage)) == 0) {
|
if ((layoutInfo.visibility & StageBit(entryPoint.stage)) == 0) {
|
||||||
@ -567,6 +579,17 @@ namespace dawn_native {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case BindingInfoType::ExternalTexture: {
|
||||||
|
// TODO(dawn:728) On backend configurations that use SPIRV-Cross to reflect
|
||||||
|
// shader info - the shader must have been already transformed prior to
|
||||||
|
// reflecting the shader. During transformation, all instances of
|
||||||
|
// texture_external are changed to texture_2d<f32>. This means that when
|
||||||
|
// extracting shader info, external textures will be seen as sampled 2d
|
||||||
|
// textures. In the future when Dawn no longer uses SPIRV-Cross, we should
|
||||||
|
// handle external textures here.
|
||||||
|
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
|
||||||
@ -755,6 +778,11 @@ namespace dawn_native {
|
|||||||
}
|
}
|
||||||
case BindingInfoType::Sampler: {
|
case BindingInfoType::Sampler: {
|
||||||
info->sampler.type = wgpu::SamplerBindingType::Filtering;
|
info->sampler.type = wgpu::SamplerBindingType::Filtering;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case BindingInfoType::ExternalTexture: {
|
||||||
|
return DAWN_VALIDATION_ERROR("External textures are not supported.");
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -993,6 +1021,8 @@ namespace dawn_native {
|
|||||||
info->storageTexture.viewDimension =
|
info->storageTexture.viewDimension =
|
||||||
TintTextureDimensionToTextureViewDimension(resource.dim);
|
TintTextureDimensionToTextureViewDimension(resource.dim);
|
||||||
|
|
||||||
|
break;
|
||||||
|
case BindingInfoType::ExternalTexture:
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return DAWN_VALIDATION_ERROR("Unknown binding type in Shader");
|
return DAWN_VALIDATION_ERROR("Unknown binding type in Shader");
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
#include "dawn_native/d3d12/BindGroupD3D12.h"
|
#include "dawn_native/d3d12/BindGroupD3D12.h"
|
||||||
|
|
||||||
#include "common/BitSetIterator.h"
|
#include "common/BitSetIterator.h"
|
||||||
|
#include "dawn_native/ExternalTexture.h"
|
||||||
#include "dawn_native/d3d12/BindGroupLayoutD3D12.h"
|
#include "dawn_native/d3d12/BindGroupLayoutD3D12.h"
|
||||||
#include "dawn_native/d3d12/BufferD3D12.h"
|
#include "dawn_native/d3d12/BufferD3D12.h"
|
||||||
#include "dawn_native/d3d12/DeviceD3D12.h"
|
#include "dawn_native/d3d12/DeviceD3D12.h"
|
||||||
@ -185,6 +186,26 @@ namespace dawn_native { namespace d3d12 {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case BindingInfoType::ExternalTexture: {
|
||||||
|
const std::array<Ref<TextureViewBase>, kMaxPlanesPerFormat>& views =
|
||||||
|
GetBindingAsExternalTexture(bindingIndex)->GetTextureViews();
|
||||||
|
|
||||||
|
// Only single-plane formats are supported right now, so assert only one view
|
||||||
|
// exists.
|
||||||
|
ASSERT(views[1].Get() == nullptr);
|
||||||
|
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, bindingOffsets[bindingIndex]));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case BindingInfoType::Sampler: {
|
case BindingInfoType::Sampler: {
|
||||||
// No-op as samplers will be later initialized by CreateSamplers().
|
// No-op as samplers will be later initialized by CreateSamplers().
|
||||||
break;
|
break;
|
||||||
|
@ -41,6 +41,7 @@ namespace dawn_native { namespace d3d12 {
|
|||||||
return BindGroupLayout::DescriptorType::Sampler;
|
return BindGroupLayout::DescriptorType::Sampler;
|
||||||
|
|
||||||
case BindingInfoType::Texture:
|
case BindingInfoType::Texture:
|
||||||
|
case BindingInfoType::ExternalTexture:
|
||||||
return BindGroupLayout::DescriptorType::SRV;
|
return BindGroupLayout::DescriptorType::SRV;
|
||||||
|
|
||||||
case BindingInfoType::StorageTexture:
|
case BindingInfoType::StorageTexture:
|
||||||
@ -77,6 +78,8 @@ namespace dawn_native { namespace d3d12 {
|
|||||||
// dynamic resources in calculating the size of the descriptor heap.
|
// dynamic resources in calculating the size of the descriptor heap.
|
||||||
ASSERT(!bindingInfo.buffer.hasDynamicOffset);
|
ASSERT(!bindingInfo.buffer.hasDynamicOffset);
|
||||||
|
|
||||||
|
// TODO(dawn:728) In the future, special handling will be needed for external textures
|
||||||
|
// here because they encompass multiple views.
|
||||||
DescriptorType descriptorType = WGPUBindingInfoToDescriptorType(bindingInfo);
|
DescriptorType descriptorType = WGPUBindingInfoToDescriptorType(bindingInfo);
|
||||||
mBindingOffsets[bindingIndex] = mDescriptorCounts[descriptorType]++;
|
mBindingOffsets[bindingIndex] = mDescriptorCounts[descriptorType]++;
|
||||||
}
|
}
|
||||||
@ -135,6 +138,8 @@ namespace dawn_native { namespace d3d12 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO(shaobo.yan@intel.com): Implement dynamic buffer offset.
|
// TODO(shaobo.yan@intel.com): Implement dynamic buffer offset.
|
||||||
|
// TODO(dawn:728) In the future, special handling will be needed here for external
|
||||||
|
// textures because they encompass multiple views.
|
||||||
DescriptorType descriptorType = WGPUBindingInfoToDescriptorType(bindingInfo);
|
DescriptorType descriptorType = WGPUBindingInfoToDescriptorType(bindingInfo);
|
||||||
mBindingOffsets[bindingIndex] += descriptorOffsets[descriptorType];
|
mBindingOffsets[bindingIndex] += descriptorOffsets[descriptorType];
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
#include "dawn_native/BindGroupTracker.h"
|
#include "dawn_native/BindGroupTracker.h"
|
||||||
#include "dawn_native/CommandEncoder.h"
|
#include "dawn_native/CommandEncoder.h"
|
||||||
#include "dawn_native/Commands.h"
|
#include "dawn_native/Commands.h"
|
||||||
|
#include "dawn_native/ExternalTexture.h"
|
||||||
#include "dawn_native/RenderBundle.h"
|
#include "dawn_native/RenderBundle.h"
|
||||||
#include "dawn_native/metal/BindGroupMTL.h"
|
#include "dawn_native/metal/BindGroupMTL.h"
|
||||||
#include "dawn_native/metal/BufferMTL.h"
|
#include "dawn_native/metal/BufferMTL.h"
|
||||||
@ -467,6 +468,32 @@ namespace dawn_native { namespace metal {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case BindingInfoType::ExternalTexture: {
|
||||||
|
const std::array<Ref<TextureViewBase>, kMaxPlanesPerFormat>& views =
|
||||||
|
group->GetBindingAsExternalTexture(bindingIndex)->GetTextureViews();
|
||||||
|
|
||||||
|
// Only single-plane formats are supported right now, so assert only one
|
||||||
|
// view exists.
|
||||||
|
ASSERT(views[1].Get() == nullptr);
|
||||||
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -58,6 +58,7 @@ namespace dawn_native { namespace metal {
|
|||||||
|
|
||||||
case BindingInfoType::Texture:
|
case BindingInfoType::Texture:
|
||||||
case BindingInfoType::StorageTexture:
|
case BindingInfoType::StorageTexture:
|
||||||
|
case BindingInfoType::ExternalTexture:
|
||||||
mIndexInfo[stage][group][bindingIndex] = textureIndex;
|
mIndexInfo[stage][group][bindingIndex] = textureIndex;
|
||||||
textureIndex++;
|
textureIndex++;
|
||||||
break;
|
break;
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
#include "dawn_native/BindGroupTracker.h"
|
#include "dawn_native/BindGroupTracker.h"
|
||||||
#include "dawn_native/CommandEncoder.h"
|
#include "dawn_native/CommandEncoder.h"
|
||||||
#include "dawn_native/Commands.h"
|
#include "dawn_native/Commands.h"
|
||||||
|
#include "dawn_native/ExternalTexture.h"
|
||||||
#include "dawn_native/RenderBundle.h"
|
#include "dawn_native/RenderBundle.h"
|
||||||
#include "dawn_native/opengl/BufferGL.h"
|
#include "dawn_native/opengl/BufferGL.h"
|
||||||
#include "dawn_native/opengl/ComputePipelineGL.h"
|
#include "dawn_native/opengl/ComputePipelineGL.h"
|
||||||
@ -362,6 +363,29 @@ namespace dawn_native { namespace opengl {
|
|||||||
texture->GetGLFormat().internalFormat);
|
texture->GetGLFormat().internalFormat);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case BindingInfoType::ExternalTexture: {
|
||||||
|
const std::array<Ref<TextureViewBase>, kMaxPlanesPerFormat>&
|
||||||
|
textureViews = mBindGroups[index]
|
||||||
|
->GetBindingAsExternalTexture(bindingIndex)
|
||||||
|
->GetTextureViews();
|
||||||
|
|
||||||
|
// Only single-plane formats are supported right now, so assert only one
|
||||||
|
// view exists.
|
||||||
|
ASSERT(textureViews[1].Get() == nullptr);
|
||||||
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -58,6 +58,7 @@ namespace dawn_native { namespace opengl {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case BindingInfoType::Texture:
|
case BindingInfoType::Texture:
|
||||||
|
case BindingInfoType::ExternalTexture:
|
||||||
mIndexInfo[group][bindingIndex] = sampledTextureIndex;
|
mIndexInfo[group][bindingIndex] = sampledTextureIndex;
|
||||||
sampledTextureIndex++;
|
sampledTextureIndex++;
|
||||||
break;
|
break;
|
||||||
|
@ -67,6 +67,7 @@ namespace dawn_native { namespace vulkan {
|
|||||||
case BindingInfoType::Sampler:
|
case BindingInfoType::Sampler:
|
||||||
return VK_DESCRIPTOR_TYPE_SAMPLER;
|
return VK_DESCRIPTOR_TYPE_SAMPLER;
|
||||||
case BindingInfoType::Texture:
|
case BindingInfoType::Texture:
|
||||||
|
case BindingInfoType::ExternalTexture:
|
||||||
return VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
|
return VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
|
||||||
case BindingInfoType::StorageTexture:
|
case BindingInfoType::StorageTexture:
|
||||||
return VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
|
return VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
|
||||||
@ -99,6 +100,8 @@ namespace dawn_native { namespace vulkan {
|
|||||||
VkDescriptorSetLayoutBinding vkBinding;
|
VkDescriptorSetLayoutBinding vkBinding;
|
||||||
vkBinding.binding = useBindingIndex ? static_cast<uint32_t>(bindingIndex)
|
vkBinding.binding = useBindingIndex ? static_cast<uint32_t>(bindingIndex)
|
||||||
: static_cast<uint32_t>(bindingNumber);
|
: static_cast<uint32_t>(bindingNumber);
|
||||||
|
// TODO(dawn:728) In the future, special handling will be needed for external textures
|
||||||
|
// here because they encompass multiple views.
|
||||||
vkBinding.descriptorType = VulkanDescriptorType(bindingInfo);
|
vkBinding.descriptorType = VulkanDescriptorType(bindingInfo);
|
||||||
vkBinding.descriptorCount = 1;
|
vkBinding.descriptorCount = 1;
|
||||||
vkBinding.stageFlags = VulkanShaderStageFlags(bindingInfo.visibility);
|
vkBinding.stageFlags = VulkanShaderStageFlags(bindingInfo.visibility);
|
||||||
@ -123,6 +126,8 @@ namespace dawn_native { namespace vulkan {
|
|||||||
std::map<VkDescriptorType, uint32_t> descriptorCountPerType;
|
std::map<VkDescriptorType, uint32_t> descriptorCountPerType;
|
||||||
|
|
||||||
for (BindingIndex bindingIndex{0}; bindingIndex < GetBindingCount(); ++bindingIndex) {
|
for (BindingIndex bindingIndex{0}; bindingIndex < GetBindingCount(); ++bindingIndex) {
|
||||||
|
// TODO(dawn:728) In the future, special handling will be needed for external textures
|
||||||
|
// here because they encompass multiple views.
|
||||||
VkDescriptorType vulkanType = VulkanDescriptorType(GetBindingInfo(bindingIndex));
|
VkDescriptorType vulkanType = VulkanDescriptorType(GetBindingInfo(bindingIndex));
|
||||||
|
|
||||||
// map::operator[] will return 0 if the key doesn't exist.
|
// map::operator[] will return 0 if the key doesn't exist.
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
#include "common/BitSetIterator.h"
|
#include "common/BitSetIterator.h"
|
||||||
#include "common/ityp_stack_vec.h"
|
#include "common/ityp_stack_vec.h"
|
||||||
|
#include "dawn_native/ExternalTexture.h"
|
||||||
#include "dawn_native/vulkan/BindGroupLayoutVk.h"
|
#include "dawn_native/vulkan/BindGroupLayoutVk.h"
|
||||||
#include "dawn_native/vulkan/BufferVk.h"
|
#include "dawn_native/vulkan/BufferVk.h"
|
||||||
#include "dawn_native/vulkan/DeviceVk.h"
|
#include "dawn_native/vulkan/DeviceVk.h"
|
||||||
@ -113,6 +114,25 @@ namespace dawn_native { namespace vulkan {
|
|||||||
write.pImageInfo = &writeImageInfo[numWrites];
|
write.pImageInfo = &writeImageInfo[numWrites];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case BindingInfoType::ExternalTexture: {
|
||||||
|
const std::array<Ref<dawn_native::TextureViewBase>, kMaxPlanesPerFormat>&
|
||||||
|
textureViews = GetBindingAsExternalTexture(bindingIndex)->GetTextureViews();
|
||||||
|
|
||||||
|
// Only single-plane formats are supported right now, so ensure only one view
|
||||||
|
// exists.
|
||||||
|
ASSERT(textureViews[1].Get() == nullptr);
|
||||||
|
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::Sampled);
|
||||||
|
|
||||||
|
write.pImageInfo = &writeImageInfo[numWrites];
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
numWrites++;
|
numWrites++;
|
||||||
|
@ -1183,12 +1183,12 @@ TEST_P(BindGroupTests, ReallyLargeBindGroup) {
|
|||||||
for (uint32_t i = 0; i < kMaxSampledTexturesPerShaderStage; ++i) {
|
for (uint32_t i = 0; i < kMaxSampledTexturesPerShaderStage; ++i) {
|
||||||
wgpu::Texture texture = CreateTextureWithRedData(
|
wgpu::Texture texture = CreateTextureWithRedData(
|
||||||
wgpu::TextureFormat::R8Unorm, expectedValue, wgpu::TextureUsage::Sampled);
|
wgpu::TextureFormat::R8Unorm, expectedValue, wgpu::TextureUsage::Sampled);
|
||||||
bgEntries.push_back({binding, nullptr, 0, 0, nullptr, texture.CreateView()});
|
bgEntries.push_back({nullptr, binding, nullptr, 0, 0, nullptr, texture.CreateView()});
|
||||||
|
|
||||||
interface << "[[group(0), binding(" << binding++ << ")]] "
|
interface << "[[group(0), binding(" << binding++ << ")]] "
|
||||||
<< "var tex" << i << " : texture_2d<f32>;\n";
|
<< "var tex" << i << " : texture_2d<f32>;\n";
|
||||||
|
|
||||||
bgEntries.push_back({binding, nullptr, 0, 0, device.CreateSampler(), nullptr});
|
bgEntries.push_back({nullptr, binding, nullptr, 0, 0, device.CreateSampler(), nullptr});
|
||||||
|
|
||||||
interface << "[[group(0), binding(" << binding++ << ")]]"
|
interface << "[[group(0), binding(" << binding++ << ")]]"
|
||||||
<< "var samp" << i << " : sampler;\n";
|
<< "var samp" << i << " : sampler;\n";
|
||||||
@ -1202,7 +1202,7 @@ TEST_P(BindGroupTests, ReallyLargeBindGroup) {
|
|||||||
for (uint32_t i = 0; i < kMaxStorageTexturesPerShaderStage; ++i) {
|
for (uint32_t i = 0; i < kMaxStorageTexturesPerShaderStage; ++i) {
|
||||||
wgpu::Texture texture = CreateTextureWithRedData(
|
wgpu::Texture texture = CreateTextureWithRedData(
|
||||||
wgpu::TextureFormat::R32Uint, expectedValue, wgpu::TextureUsage::Storage);
|
wgpu::TextureFormat::R32Uint, expectedValue, wgpu::TextureUsage::Storage);
|
||||||
bgEntries.push_back({binding, nullptr, 0, 0, nullptr, texture.CreateView()});
|
bgEntries.push_back({nullptr, binding, nullptr, 0, 0, nullptr, texture.CreateView()});
|
||||||
|
|
||||||
interface << "[[group(0), binding(" << binding++ << ")]] "
|
interface << "[[group(0), binding(" << binding++ << ")]] "
|
||||||
<< "var image" << i << " : [[access(read)]] texture_storage_2d<r32uint>;\n";
|
<< "var image" << i << " : [[access(read)]] texture_storage_2d<r32uint>;\n";
|
||||||
@ -1216,7 +1216,7 @@ TEST_P(BindGroupTests, ReallyLargeBindGroup) {
|
|||||||
for (uint32_t i = 0; i < kMaxUniformBuffersPerShaderStage; ++i) {
|
for (uint32_t i = 0; i < kMaxUniformBuffersPerShaderStage; ++i) {
|
||||||
wgpu::Buffer buffer = utils::CreateBufferFromData<uint32_t>(
|
wgpu::Buffer buffer = utils::CreateBufferFromData<uint32_t>(
|
||||||
device, wgpu::BufferUsage::Uniform, {expectedValue, 0, 0, 0});
|
device, wgpu::BufferUsage::Uniform, {expectedValue, 0, 0, 0});
|
||||||
bgEntries.push_back({binding, buffer, 0, 4 * sizeof(uint32_t), nullptr, nullptr});
|
bgEntries.push_back({nullptr, binding, buffer, 0, 4 * sizeof(uint32_t), nullptr, nullptr});
|
||||||
|
|
||||||
interface << "[[block]] struct UniformBuffer" << i << R"({
|
interface << "[[block]] struct UniformBuffer" << i << R"({
|
||||||
value : u32;
|
value : u32;
|
||||||
@ -1233,7 +1233,7 @@ TEST_P(BindGroupTests, ReallyLargeBindGroup) {
|
|||||||
for (uint32_t i = 0; i < kMaxStorageBuffersPerShaderStage - 1; ++i) {
|
for (uint32_t i = 0; i < kMaxStorageBuffersPerShaderStage - 1; ++i) {
|
||||||
wgpu::Buffer buffer = utils::CreateBufferFromData<uint32_t>(
|
wgpu::Buffer buffer = utils::CreateBufferFromData<uint32_t>(
|
||||||
device, wgpu::BufferUsage::Storage, {expectedValue});
|
device, wgpu::BufferUsage::Storage, {expectedValue});
|
||||||
bgEntries.push_back({binding, buffer, 0, sizeof(uint32_t), nullptr, nullptr});
|
bgEntries.push_back({nullptr, binding, buffer, 0, sizeof(uint32_t), nullptr, nullptr});
|
||||||
|
|
||||||
interface << "[[block]] struct ReadOnlyStorageBuffer" << i << R"({
|
interface << "[[block]] struct ReadOnlyStorageBuffer" << i << R"({
|
||||||
value : u32;
|
value : u32;
|
||||||
@ -1250,7 +1250,7 @@ TEST_P(BindGroupTests, ReallyLargeBindGroup) {
|
|||||||
|
|
||||||
wgpu::Buffer result = utils::CreateBufferFromData<uint32_t>(
|
wgpu::Buffer result = utils::CreateBufferFromData<uint32_t>(
|
||||||
device, wgpu::BufferUsage::Storage | wgpu::BufferUsage::CopySrc, {0});
|
device, wgpu::BufferUsage::Storage | wgpu::BufferUsage::CopySrc, {0});
|
||||||
bgEntries.push_back({binding, result, 0, sizeof(uint32_t), nullptr, nullptr});
|
bgEntries.push_back({nullptr, binding, result, 0, sizeof(uint32_t), nullptr, nullptr});
|
||||||
|
|
||||||
interface << R"([[block]] struct ReadWriteStorageBuffer{
|
interface << R"([[block]] struct ReadWriteStorageBuffer{
|
||||||
value : u32;
|
value : u32;
|
||||||
|
@ -13,6 +13,8 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
#include "tests/DawnTest.h"
|
#include "tests/DawnTest.h"
|
||||||
|
#include "utils/ComboRenderPipelineDescriptor.h"
|
||||||
|
#include "utils/WGPUHelpers.h"
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
@ -43,8 +45,6 @@ namespace {
|
|||||||
} // anonymous namespace
|
} // anonymous namespace
|
||||||
|
|
||||||
TEST_P(ExternalTextureTests, CreateExternalTextureSuccess) {
|
TEST_P(ExternalTextureTests, CreateExternalTextureSuccess) {
|
||||||
DAWN_TEST_UNSUPPORTED_IF(UsesWire());
|
|
||||||
|
|
||||||
wgpu::Texture texture = Create2DTexture(device, kWidth, kHeight, kFormat, kSampledUsage);
|
wgpu::Texture texture = Create2DTexture(device, kWidth, kHeight, kFormat, kSampledUsage);
|
||||||
|
|
||||||
// Create a texture view for the external texture
|
// Create a texture view for the external texture
|
||||||
@ -61,6 +61,94 @@ TEST_P(ExternalTextureTests, CreateExternalTextureSuccess) {
|
|||||||
ASSERT_NE(externalTexture.Get(), nullptr);
|
ASSERT_NE(externalTexture.Get(), nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_P(ExternalTextureTests, SampleExternalTexture) {
|
||||||
|
wgpu::ShaderModule vsModule = utils::CreateShaderModule(device, R"(
|
||||||
|
[[stage(vertex)]] fn main([[builtin(vertex_idx)]] VertexIndex : u32) -> [[builtin(position)]] vec4<f32> {
|
||||||
|
|
||||||
|
let positions : array<vec4<f32>, 3> = 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 sampledTexture =
|
||||||
|
Create2DTexture(device, kWidth, kHeight, kFormat,
|
||||||
|
wgpu::TextureUsage::Sampled | 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 externalView = sampledTexture.CreateView();
|
||||||
|
|
||||||
|
// Initialize texture with green to ensure it is sampled from later.
|
||||||
|
{
|
||||||
|
utils::ComboRenderPassDescriptor renderPass({externalView}, nullptr);
|
||||||
|
renderPass.cColorAttachments[0].clearColor = {0.0f, 1.0f, 0.0f, 1.0f};
|
||||||
|
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
|
||||||
|
wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass);
|
||||||
|
pass.EndPass();
|
||||||
|
|
||||||
|
wgpu::CommandBuffer commands = encoder.Finish();
|
||||||
|
queue.Submit(1, &commands);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create an ExternalTextureDescriptor from the texture view
|
||||||
|
wgpu::ExternalTextureDescriptor externalDesc;
|
||||||
|
externalDesc.plane0 = externalView;
|
||||||
|
externalDesc.format = kFormat;
|
||||||
|
|
||||||
|
// Import the external texture
|
||||||
|
wgpu::ExternalTexture externalTexture = device.CreateExternalTexture(&externalDesc);
|
||||||
|
|
||||||
|
// Create a sampler and bind group
|
||||||
|
wgpu::Sampler sampler = device.CreateSampler();
|
||||||
|
|
||||||
|
wgpu::BindGroupLayout bgl = utils::MakeBindGroupLayout(
|
||||||
|
device, {{0, wgpu::ShaderStage::Fragment, wgpu::SamplerBindingType::Filtering},
|
||||||
|
{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
|
||||||
|
// 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.EndPass();
|
||||||
|
}
|
||||||
|
|
||||||
|
wgpu::CommandBuffer commands = encoder.Finish();
|
||||||
|
queue.Submit(1, &commands);
|
||||||
|
|
||||||
|
EXPECT_PIXEL_RGBA8_EQ(RGBA8::kGreen, renderTexture, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
DAWN_INSTANTIATE_TEST(ExternalTextureTests,
|
DAWN_INSTANTIATE_TEST(ExternalTextureTests,
|
||||||
D3D12Backend(),
|
D3D12Backend(),
|
||||||
MetalBackend(),
|
MetalBackend(),
|
||||||
|
@ -53,9 +53,14 @@ class BindGroupValidationTest : public ValidationTest {
|
|||||||
}
|
}
|
||||||
{ mSampler = device.CreateSampler(); }
|
{ mSampler = device.CreateSampler(); }
|
||||||
{
|
{
|
||||||
mSampledTexture =
|
mSampledTexture = CreateTexture(wgpu::TextureUsage::Sampled, kDefaultTextureFormat, 1);
|
||||||
CreateTexture(wgpu::TextureUsage::Sampled, wgpu::TextureFormat::RGBA8Unorm, 1);
|
|
||||||
mSampledTextureView = mSampledTexture.CreateView();
|
mSampledTextureView = mSampledTexture.CreateView();
|
||||||
|
|
||||||
|
wgpu::ExternalTextureDescriptor externalTextureDesc;
|
||||||
|
externalTextureDesc.format = kDefaultTextureFormat;
|
||||||
|
externalTextureDesc.plane0 = mSampledTextureView;
|
||||||
|
mExternalTexture = device.CreateExternalTexture(&externalTextureDesc);
|
||||||
|
mExternalTextureBindingEntry.externalTexture = mExternalTexture;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -65,6 +70,12 @@ class BindGroupValidationTest : public ValidationTest {
|
|||||||
wgpu::Sampler mSampler;
|
wgpu::Sampler mSampler;
|
||||||
wgpu::Texture mSampledTexture;
|
wgpu::Texture mSampledTexture;
|
||||||
wgpu::TextureView mSampledTextureView;
|
wgpu::TextureView mSampledTextureView;
|
||||||
|
wgpu::ExternalTextureBindingEntry mExternalTextureBindingEntry;
|
||||||
|
|
||||||
|
static constexpr wgpu::TextureFormat kDefaultTextureFormat = wgpu::TextureFormat::RGBA8Unorm;
|
||||||
|
|
||||||
|
private:
|
||||||
|
wgpu::ExternalTexture mExternalTexture;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Test the validation of BindGroupDescriptor::nextInChain
|
// Test the validation of BindGroupDescriptor::nextInChain
|
||||||
@ -159,6 +170,11 @@ TEST_F(BindGroupValidationTest, SamplerBindingType) {
|
|||||||
ASSERT_DEVICE_ERROR(device.CreateBindGroup(&descriptor));
|
ASSERT_DEVICE_ERROR(device.CreateBindGroup(&descriptor));
|
||||||
binding.buffer = nullptr;
|
binding.buffer = nullptr;
|
||||||
|
|
||||||
|
// Setting the external texture view as well is an error
|
||||||
|
binding.nextInChain = &mExternalTextureBindingEntry;
|
||||||
|
ASSERT_DEVICE_ERROR(device.CreateBindGroup(&descriptor));
|
||||||
|
binding.nextInChain = nullptr;
|
||||||
|
|
||||||
// Setting the sampler to an error sampler is an error.
|
// Setting the sampler to an error sampler is an error.
|
||||||
{
|
{
|
||||||
wgpu::SamplerDescriptor samplerDesc;
|
wgpu::SamplerDescriptor samplerDesc;
|
||||||
@ -208,10 +224,15 @@ TEST_F(BindGroupValidationTest, TextureBindingType) {
|
|||||||
ASSERT_DEVICE_ERROR(device.CreateBindGroup(&descriptor));
|
ASSERT_DEVICE_ERROR(device.CreateBindGroup(&descriptor));
|
||||||
binding.buffer = nullptr;
|
binding.buffer = nullptr;
|
||||||
|
|
||||||
|
// Setting the external texture view as well is an error
|
||||||
|
binding.nextInChain = &mExternalTextureBindingEntry;
|
||||||
|
ASSERT_DEVICE_ERROR(device.CreateBindGroup(&descriptor));
|
||||||
|
binding.nextInChain = nullptr;
|
||||||
|
|
||||||
// Setting the texture view to an error texture view is an error.
|
// Setting the texture view to an error texture view is an error.
|
||||||
{
|
{
|
||||||
wgpu::TextureViewDescriptor viewDesc;
|
wgpu::TextureViewDescriptor viewDesc;
|
||||||
viewDesc.format = wgpu::TextureFormat::RGBA8Unorm;
|
viewDesc.format = kDefaultTextureFormat;
|
||||||
viewDesc.dimension = wgpu::TextureViewDimension::e2D;
|
viewDesc.dimension = wgpu::TextureViewDimension::e2D;
|
||||||
viewDesc.baseMipLevel = 0;
|
viewDesc.baseMipLevel = 0;
|
||||||
viewDesc.mipLevelCount = 0;
|
viewDesc.mipLevelCount = 0;
|
||||||
@ -262,6 +283,11 @@ TEST_F(BindGroupValidationTest, BufferBindingType) {
|
|||||||
ASSERT_DEVICE_ERROR(device.CreateBindGroup(&descriptor));
|
ASSERT_DEVICE_ERROR(device.CreateBindGroup(&descriptor));
|
||||||
binding.sampler = nullptr;
|
binding.sampler = nullptr;
|
||||||
|
|
||||||
|
// Setting the external texture view as well is an error
|
||||||
|
binding.nextInChain = &mExternalTextureBindingEntry;
|
||||||
|
ASSERT_DEVICE_ERROR(device.CreateBindGroup(&descriptor));
|
||||||
|
binding.nextInChain = nullptr;
|
||||||
|
|
||||||
// Setting the buffer to an error buffer is an error.
|
// Setting the buffer to an error buffer is an error.
|
||||||
{
|
{
|
||||||
wgpu::BufferDescriptor bufferDesc;
|
wgpu::BufferDescriptor bufferDesc;
|
||||||
@ -277,6 +303,91 @@ TEST_F(BindGroupValidationTest, BufferBindingType) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check that an external texture binding must contain exactly an external texture
|
||||||
|
TEST_F(BindGroupValidationTest, ExternalTextureBindingType) {
|
||||||
|
// Create an external texture
|
||||||
|
wgpu::Texture texture = CreateTexture(wgpu::TextureUsage::Sampled, kDefaultTextureFormat, 1);
|
||||||
|
wgpu::ExternalTextureDescriptor externalDesc;
|
||||||
|
externalDesc.plane0 = texture.CreateView();
|
||||||
|
externalDesc.format = kDefaultTextureFormat;
|
||||||
|
wgpu::ExternalTexture externalTexture = device.CreateExternalTexture(&externalDesc);
|
||||||
|
|
||||||
|
// Create a bind group layout for a single external texture
|
||||||
|
wgpu::BindGroupLayout layout = utils::MakeBindGroupLayout(
|
||||||
|
device, {{0, wgpu::ShaderStage::Fragment, &utils::kExternalTextureBindingLayout}});
|
||||||
|
|
||||||
|
wgpu::BindGroupEntry binding;
|
||||||
|
binding.binding = 0;
|
||||||
|
binding.sampler = nullptr;
|
||||||
|
binding.textureView = nullptr;
|
||||||
|
binding.buffer = nullptr;
|
||||||
|
binding.offset = 0;
|
||||||
|
binding.size = 0;
|
||||||
|
|
||||||
|
wgpu::BindGroupDescriptor descriptor;
|
||||||
|
descriptor.layout = layout;
|
||||||
|
descriptor.entryCount = 1;
|
||||||
|
descriptor.entries = &binding;
|
||||||
|
|
||||||
|
// Not setting anything fails
|
||||||
|
ASSERT_DEVICE_ERROR(device.CreateBindGroup(&descriptor));
|
||||||
|
|
||||||
|
// Control case: setting just the external texture works
|
||||||
|
wgpu::ExternalTextureBindingEntry externalBindingEntry;
|
||||||
|
externalBindingEntry.externalTexture = externalTexture;
|
||||||
|
binding.nextInChain = &externalBindingEntry;
|
||||||
|
device.CreateBindGroup(&descriptor);
|
||||||
|
|
||||||
|
// Setting the texture view as well is an error
|
||||||
|
binding.textureView = mSampledTextureView;
|
||||||
|
ASSERT_DEVICE_ERROR(device.CreateBindGroup(&descriptor));
|
||||||
|
binding.textureView = nullptr;
|
||||||
|
|
||||||
|
// Setting the sampler as well is an error
|
||||||
|
binding.sampler = mSampler;
|
||||||
|
ASSERT_DEVICE_ERROR(device.CreateBindGroup(&descriptor));
|
||||||
|
binding.sampler = nullptr;
|
||||||
|
|
||||||
|
// Setting the buffer as well is an error
|
||||||
|
binding.buffer = mUBO;
|
||||||
|
ASSERT_DEVICE_ERROR(device.CreateBindGroup(&descriptor));
|
||||||
|
binding.buffer = nullptr;
|
||||||
|
|
||||||
|
// Setting the external texture to an error external texture is an error.
|
||||||
|
{
|
||||||
|
wgpu::ExternalTextureDescriptor errorExternalDesciptor;
|
||||||
|
errorExternalDesciptor.plane0 = texture.CreateView();
|
||||||
|
errorExternalDesciptor.format = wgpu::TextureFormat::R8Uint;
|
||||||
|
|
||||||
|
wgpu::ExternalTexture errorExternalTexture;
|
||||||
|
ASSERT_DEVICE_ERROR(errorExternalTexture =
|
||||||
|
device.CreateExternalTexture(&errorExternalDesciptor));
|
||||||
|
|
||||||
|
wgpu::ExternalTextureBindingEntry errorExternalBindingEntry;
|
||||||
|
errorExternalBindingEntry.externalTexture = errorExternalTexture;
|
||||||
|
binding.nextInChain = &errorExternalBindingEntry;
|
||||||
|
ASSERT_DEVICE_ERROR(device.CreateBindGroup(&descriptor));
|
||||||
|
binding.nextInChain = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setting an external texture with another external texture chained is an error.
|
||||||
|
{
|
||||||
|
wgpu::ExternalTexture externalTexture2 = device.CreateExternalTexture(&externalDesc);
|
||||||
|
wgpu::ExternalTextureBindingEntry externalBindingEntry2;
|
||||||
|
externalBindingEntry2.externalTexture = externalTexture2;
|
||||||
|
externalBindingEntry.nextInChain = &externalBindingEntry2;
|
||||||
|
|
||||||
|
ASSERT_DEVICE_ERROR(device.CreateBindGroup(&descriptor));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Chaining a struct that isn't an external texture binding entry is an error.
|
||||||
|
{
|
||||||
|
wgpu::ExternalTextureBindingLayout externalBindingLayout;
|
||||||
|
binding.nextInChain = &externalBindingLayout;
|
||||||
|
ASSERT_DEVICE_ERROR(device.CreateBindGroup(&descriptor));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Check that a texture must have the correct usage
|
// Check that a texture must have the correct usage
|
||||||
TEST_F(BindGroupValidationTest, TextureUsage) {
|
TEST_F(BindGroupValidationTest, TextureUsage) {
|
||||||
wgpu::BindGroupLayout layout = utils::MakeBindGroupLayout(
|
wgpu::BindGroupLayout layout = utils::MakeBindGroupLayout(
|
||||||
@ -746,7 +857,7 @@ TEST_F(BindGroupLayoutValidationTest, PerStageLimits) {
|
|||||||
wgpu::BindGroupLayoutEntry otherEntry;
|
wgpu::BindGroupLayoutEntry otherEntry;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::array<TestInfo, 7> kTestInfos = {
|
std::array<TestInfo, 8> kTestInfos = {
|
||||||
TestInfo{kMaxSampledTexturesPerShaderStage, BGLEntryType(wgpu::TextureSampleType::Float),
|
TestInfo{kMaxSampledTexturesPerShaderStage, BGLEntryType(wgpu::TextureSampleType::Float),
|
||||||
BGLEntryType(wgpu::BufferBindingType::Uniform)},
|
BGLEntryType(wgpu::BufferBindingType::Uniform)},
|
||||||
TestInfo{kMaxSamplersPerShaderStage, BGLEntryType(wgpu::SamplerBindingType::Filtering),
|
TestInfo{kMaxSamplersPerShaderStage, BGLEntryType(wgpu::SamplerBindingType::Filtering),
|
||||||
@ -765,7 +876,12 @@ TEST_F(BindGroupLayoutValidationTest, PerStageLimits) {
|
|||||||
BGLEntryType(wgpu::BufferBindingType::Uniform)},
|
BGLEntryType(wgpu::BufferBindingType::Uniform)},
|
||||||
TestInfo{kMaxUniformBuffersPerShaderStage, BGLEntryType(wgpu::BufferBindingType::Uniform),
|
TestInfo{kMaxUniformBuffersPerShaderStage, BGLEntryType(wgpu::BufferBindingType::Uniform),
|
||||||
BGLEntryType(wgpu::TextureSampleType::Float)},
|
BGLEntryType(wgpu::TextureSampleType::Float)},
|
||||||
};
|
// External textures use multiple bindings (3 sampled textures, 1 sampler, 1 uniform buffer)
|
||||||
|
// that count towards the per stage binding limits. The number of external textures are
|
||||||
|
// currently restricted by the maximum number of sampled textures.
|
||||||
|
TestInfo{kMaxSampledTexturesPerShaderStage / kSampledTexturesPerExternalTexture,
|
||||||
|
BGLEntryType(&utils::kExternalTextureBindingLayout),
|
||||||
|
BGLEntryType(wgpu::BufferBindingType::Uniform)}};
|
||||||
|
|
||||||
for (TestInfo info : kTestInfos) {
|
for (TestInfo info : kTestInfos) {
|
||||||
wgpu::BindGroupLayout bgl[2];
|
wgpu::BindGroupLayout bgl[2];
|
||||||
@ -829,6 +945,98 @@ TEST_F(BindGroupLayoutValidationTest, PerStageLimits) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// External textures require multiple binding slots (3 sampled texture, 1 uniform buffer, 1
|
||||||
|
// sampler), so ensure that these count towards the limit when combined non-external texture
|
||||||
|
// bindings.
|
||||||
|
TEST_F(BindGroupLayoutValidationTest, PerStageLimitsWithExternalTexture) {
|
||||||
|
struct TestInfo {
|
||||||
|
uint32_t maxCount;
|
||||||
|
uint32_t bindingsPerExternalTexture;
|
||||||
|
wgpu::BindGroupLayoutEntry entry;
|
||||||
|
wgpu::BindGroupLayoutEntry otherEntry;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::array<TestInfo, 3> kTestInfos = {
|
||||||
|
TestInfo{kMaxSampledTexturesPerShaderStage, kSampledTexturesPerExternalTexture,
|
||||||
|
BGLEntryType(wgpu::TextureSampleType::Float),
|
||||||
|
BGLEntryType(wgpu::BufferBindingType::Uniform)},
|
||||||
|
TestInfo{kMaxSamplersPerShaderStage, kSamplersPerExternalTexture,
|
||||||
|
BGLEntryType(wgpu::SamplerBindingType::Filtering),
|
||||||
|
BGLEntryType(wgpu::BufferBindingType::Uniform)},
|
||||||
|
TestInfo{kMaxUniformBuffersPerShaderStage, kUniformsPerExternalTexture,
|
||||||
|
BGLEntryType(wgpu::BufferBindingType::Uniform),
|
||||||
|
BGLEntryType(wgpu::TextureSampleType::Float)},
|
||||||
|
};
|
||||||
|
|
||||||
|
for (TestInfo info : kTestInfos) {
|
||||||
|
wgpu::BindGroupLayout bgl[2];
|
||||||
|
std::vector<utils::BindingLayoutEntryInitializationHelper> maxBindings;
|
||||||
|
|
||||||
|
// Create an external texture binding layout entry
|
||||||
|
wgpu::BindGroupLayoutEntry entry = BGLEntryType(&utils::kExternalTextureBindingLayout);
|
||||||
|
entry.binding = 0;
|
||||||
|
maxBindings.push_back(entry);
|
||||||
|
|
||||||
|
// Create the other bindings such that we reach the max bindings per stage when including
|
||||||
|
// the external texture.
|
||||||
|
for (uint32_t i = 1; i <= info.maxCount - info.bindingsPerExternalTexture; ++i) {
|
||||||
|
wgpu::BindGroupLayoutEntry entry = info.entry;
|
||||||
|
entry.binding = i;
|
||||||
|
maxBindings.push_back(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure that creation without the external texture works.
|
||||||
|
bgl[0] = MakeBindGroupLayout(maxBindings.data(), maxBindings.size());
|
||||||
|
|
||||||
|
// Adding an extra binding of a different type works.
|
||||||
|
{
|
||||||
|
std::vector<utils::BindingLayoutEntryInitializationHelper> bindings = maxBindings;
|
||||||
|
wgpu::BindGroupLayoutEntry entry = info.otherEntry;
|
||||||
|
entry.binding = info.maxCount;
|
||||||
|
bindings.push_back(entry);
|
||||||
|
MakeBindGroupLayout(bindings.data(), bindings.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Adding an extra binding of the maxed type in a different stage works
|
||||||
|
{
|
||||||
|
std::vector<utils::BindingLayoutEntryInitializationHelper> bindings = maxBindings;
|
||||||
|
wgpu::BindGroupLayoutEntry entry = info.entry;
|
||||||
|
entry.binding = info.maxCount;
|
||||||
|
entry.visibility = wgpu::ShaderStage::Fragment;
|
||||||
|
bindings.push_back(entry);
|
||||||
|
MakeBindGroupLayout(bindings.data(), bindings.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Adding an extra binding of the maxed type and stage exceeds the per stage limit.
|
||||||
|
{
|
||||||
|
std::vector<utils::BindingLayoutEntryInitializationHelper> bindings = maxBindings;
|
||||||
|
wgpu::BindGroupLayoutEntry entry = info.entry;
|
||||||
|
entry.binding = info.maxCount;
|
||||||
|
bindings.push_back(entry);
|
||||||
|
ASSERT_DEVICE_ERROR(MakeBindGroupLayout(bindings.data(), bindings.size()));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Creating a pipeline layout from the valid BGL works.
|
||||||
|
TestCreatePipelineLayout(bgl, 1, true);
|
||||||
|
|
||||||
|
// Adding an extra binding of a different type in a different BGL works
|
||||||
|
bgl[1] = utils::MakeBindGroupLayout(device, {info.otherEntry});
|
||||||
|
TestCreatePipelineLayout(bgl, 2, true);
|
||||||
|
|
||||||
|
{
|
||||||
|
// Adding an extra binding of the maxed type in a different stage works
|
||||||
|
wgpu::BindGroupLayoutEntry entry = info.entry;
|
||||||
|
entry.visibility = wgpu::ShaderStage::Fragment;
|
||||||
|
bgl[1] = utils::MakeBindGroupLayout(device, {entry});
|
||||||
|
TestCreatePipelineLayout(bgl, 2, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Adding an extra binding of the maxed type in a different BGL exceeds the per stage limit.
|
||||||
|
bgl[1] = utils::MakeBindGroupLayout(device, {info.entry});
|
||||||
|
TestCreatePipelineLayout(bgl, 2, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Check that dynamic buffer numbers exceed maximum value in one bind group layout.
|
// Check that dynamic buffer numbers exceed maximum value in one bind group layout.
|
||||||
TEST_F(BindGroupLayoutValidationTest, DynamicBufferNumberLimit) {
|
TEST_F(BindGroupLayoutValidationTest, DynamicBufferNumberLimit) {
|
||||||
wgpu::BindGroupLayout bgl[2];
|
wgpu::BindGroupLayout bgl[2];
|
||||||
@ -1847,6 +2055,28 @@ TEST_F(BindGroupLayoutCompatibilityTest, TextureViewDimension) {
|
|||||||
wgpu::TextureViewDimension::e2D}})}));
|
wgpu::TextureViewDimension::e2D}})}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO(dawn:728) Enable this test when Dawn no longer relies on SPIRV-Cross to extract shader info.
|
||||||
|
TEST_F(BindGroupLayoutCompatibilityTest, DISABLED_ExternalTextureBindGroupLayoutCompatibility) {
|
||||||
|
wgpu::BindGroupLayout bgl = utils::MakeBindGroupLayout(
|
||||||
|
device, {{0, wgpu::ShaderStage::Fragment, &utils::kExternalTextureBindingLayout}});
|
||||||
|
|
||||||
|
// Test that an external texture binding works with a texture_external in the shader.
|
||||||
|
CreateFSRenderPipeline(R"(
|
||||||
|
[[group(0), binding(0)]] var myExternalTexture: texture_external;
|
||||||
|
[[stage(fragment)]] fn main() {
|
||||||
|
textureDimensions(myExternalTexture);
|
||||||
|
})",
|
||||||
|
{bgl});
|
||||||
|
|
||||||
|
// Test that an external texture binding doesn't work with a texture_2d<f32> in the shader.
|
||||||
|
ASSERT_DEVICE_ERROR(CreateFSRenderPipeline(R"(
|
||||||
|
[[group(0), binding(0)]] var myTexture: texture_2d<f32>;
|
||||||
|
[[stage(fragment)]] fn main() {
|
||||||
|
textureDimensions(myTexture);
|
||||||
|
})",
|
||||||
|
{bgl}));
|
||||||
|
}
|
||||||
|
|
||||||
class BindingsValidationTest : public BindGroupLayoutCompatibilityTest {
|
class BindingsValidationTest : public BindGroupLayoutCompatibilityTest {
|
||||||
public:
|
public:
|
||||||
void TestRenderPassBindings(const wgpu::BindGroup* bg,
|
void TestRenderPassBindings(const wgpu::BindGroup* bg,
|
||||||
|
@ -14,6 +14,9 @@
|
|||||||
|
|
||||||
#include "tests/unittests/validation/ValidationTest.h"
|
#include "tests/unittests/validation/ValidationTest.h"
|
||||||
|
|
||||||
|
#include "utils/ComboRenderPipelineDescriptor.h"
|
||||||
|
#include "utils/WGPUHelpers.h"
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
class ExternalTextureTest : public ValidationTest {
|
class ExternalTextureTest : public ValidationTest {
|
||||||
public:
|
public:
|
||||||
@ -26,11 +29,41 @@ namespace {
|
|||||||
descriptor.sampleCount = kDefaultSampleCount;
|
descriptor.sampleCount = kDefaultSampleCount;
|
||||||
descriptor.dimension = wgpu::TextureDimension::e2D;
|
descriptor.dimension = wgpu::TextureDimension::e2D;
|
||||||
descriptor.format = kDefaultTextureFormat;
|
descriptor.format = kDefaultTextureFormat;
|
||||||
descriptor.usage = wgpu::TextureUsage::Sampled;
|
descriptor.usage = wgpu::TextureUsage::Sampled | wgpu::TextureUsage::RenderAttachment;
|
||||||
return descriptor;
|
return descriptor;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
void SetUp() override {
|
||||||
|
ValidationTest::SetUp();
|
||||||
|
|
||||||
|
queue = device.GetQueue();
|
||||||
|
}
|
||||||
|
|
||||||
|
wgpu::RenderPipeline CreateBasicRenderPipeline(wgpu::ExternalTexture externalTexture) {
|
||||||
|
wgpu::BindGroupLayout bgl = utils::MakeBindGroupLayout(
|
||||||
|
device, {{0, wgpu::ShaderStage::Fragment, &utils::kExternalTextureBindingLayout}});
|
||||||
|
|
||||||
|
bindGroup = utils::MakeBindGroup(device, bgl, {{0, externalTexture}});
|
||||||
|
|
||||||
|
wgpu::ShaderModule vsModule = utils::CreateShaderModule(device, R"(
|
||||||
|
[[stage(vertex)]] fn main() -> [[builtin(position)]] vec4<f32> {
|
||||||
|
return vec4<f32>();
|
||||||
|
})");
|
||||||
|
wgpu::ShaderModule fsModule = utils::CreateShaderModule(device, R"(
|
||||||
|
[[group(0), binding(0)]] var myExternalTexture: texture_external;
|
||||||
|
[[stage(fragment)]] fn main() {
|
||||||
|
textureDimensions(myExternalTexture);
|
||||||
|
})");
|
||||||
|
|
||||||
|
utils::ComboRenderPipelineDescriptor pipelineDescriptor;
|
||||||
|
pipelineDescriptor.vertex.module = vsModule;
|
||||||
|
pipelineDescriptor.cFragment.module = fsModule;
|
||||||
|
wgpu::PipelineLayout pipelineLayout = utils::MakeBasicPipelineLayout(device, &bgl);
|
||||||
|
pipelineDescriptor.layout = pipelineLayout;
|
||||||
|
return device.CreateRenderPipeline(&pipelineDescriptor);
|
||||||
|
}
|
||||||
|
|
||||||
static constexpr uint32_t kWidth = 32;
|
static constexpr uint32_t kWidth = 32;
|
||||||
static constexpr uint32_t kHeight = 32;
|
static constexpr uint32_t kHeight = 32;
|
||||||
static constexpr uint32_t kDefaultDepth = 1;
|
static constexpr uint32_t kDefaultDepth = 1;
|
||||||
@ -39,6 +72,10 @@ namespace {
|
|||||||
|
|
||||||
static constexpr wgpu::TextureFormat kDefaultTextureFormat =
|
static constexpr wgpu::TextureFormat kDefaultTextureFormat =
|
||||||
wgpu::TextureFormat::RGBA8Unorm;
|
wgpu::TextureFormat::RGBA8Unorm;
|
||||||
|
|
||||||
|
wgpu::Queue queue;
|
||||||
|
wgpu::RenderPipeline renderPipeline;
|
||||||
|
wgpu::BindGroup bindGroup;
|
||||||
};
|
};
|
||||||
|
|
||||||
TEST_F(ExternalTextureTest, CreateExternalTextureValidation) {
|
TEST_F(ExternalTextureTest, CreateExternalTextureValidation) {
|
||||||
@ -112,4 +149,110 @@ namespace {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Test that submitting a command encoder that contains a destroyed external texture results in
|
||||||
|
// an error.
|
||||||
|
TEST_F(ExternalTextureTest, SubmitDestroyedExternalTexture) {
|
||||||
|
wgpu::TextureDescriptor textureDescriptor = CreateDefaultTextureDescriptor();
|
||||||
|
wgpu::Texture texture = device.CreateTexture(&textureDescriptor);
|
||||||
|
|
||||||
|
wgpu::ExternalTextureDescriptor externalDesc;
|
||||||
|
externalDesc.format = kDefaultTextureFormat;
|
||||||
|
externalDesc.plane0 = texture.CreateView();
|
||||||
|
wgpu::ExternalTexture externalTexture = device.CreateExternalTexture(&externalDesc);
|
||||||
|
|
||||||
|
wgpu::RenderPipeline pipeline = CreateBasicRenderPipeline(externalTexture);
|
||||||
|
|
||||||
|
// Create another texture to use as a color attachment.
|
||||||
|
wgpu::TextureDescriptor renderTextureDescriptor = CreateDefaultTextureDescriptor();
|
||||||
|
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.SetPipeline(pipeline);
|
||||||
|
pass.SetBindGroup(0, bindGroup);
|
||||||
|
pass.Draw(1);
|
||||||
|
pass.EndPass();
|
||||||
|
}
|
||||||
|
|
||||||
|
wgpu::CommandBuffer commands = encoder.Finish();
|
||||||
|
|
||||||
|
queue.Submit(1, &commands);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Destroying the external texture should result in an error.
|
||||||
|
{
|
||||||
|
externalTexture.Destroy();
|
||||||
|
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
|
||||||
|
wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass);
|
||||||
|
{
|
||||||
|
pass.SetPipeline(pipeline);
|
||||||
|
pass.SetBindGroup(0, bindGroup);
|
||||||
|
pass.Draw(1);
|
||||||
|
pass.EndPass();
|
||||||
|
}
|
||||||
|
|
||||||
|
wgpu::CommandBuffer commands = encoder.Finish();
|
||||||
|
ASSERT_DEVICE_ERROR(queue.Submit(1, &commands));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test that submitting a command encoder that contains a destroyed external texture plane
|
||||||
|
// results in an error.
|
||||||
|
TEST_F(ExternalTextureTest, SubmitDestroyedExternalTexturePlane) {
|
||||||
|
wgpu::TextureDescriptor textureDescriptor = CreateDefaultTextureDescriptor();
|
||||||
|
wgpu::Texture texture = device.CreateTexture(&textureDescriptor);
|
||||||
|
|
||||||
|
wgpu::ExternalTextureDescriptor externalDesc;
|
||||||
|
externalDesc.format = kDefaultTextureFormat;
|
||||||
|
externalDesc.plane0 = texture.CreateView();
|
||||||
|
wgpu::ExternalTexture externalTexture = device.CreateExternalTexture(&externalDesc);
|
||||||
|
|
||||||
|
wgpu::RenderPipeline pipeline = CreateBasicRenderPipeline(externalTexture);
|
||||||
|
|
||||||
|
// Create another texture to use as a color attachment.
|
||||||
|
wgpu::TextureDescriptor renderTextureDescriptor = CreateDefaultTextureDescriptor();
|
||||||
|
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.SetPipeline(pipeline);
|
||||||
|
pass.SetBindGroup(0, bindGroup);
|
||||||
|
pass.Draw(1);
|
||||||
|
pass.EndPass();
|
||||||
|
}
|
||||||
|
|
||||||
|
wgpu::CommandBuffer commands = encoder.Finish();
|
||||||
|
|
||||||
|
queue.Submit(1, &commands);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Destroying an external texture underlying plane should result in an error.
|
||||||
|
{
|
||||||
|
texture.Destroy();
|
||||||
|
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
|
||||||
|
wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass);
|
||||||
|
{
|
||||||
|
pass.SetPipeline(pipeline);
|
||||||
|
pass.SetBindGroup(0, bindGroup);
|
||||||
|
pass.Draw(1);
|
||||||
|
pass.EndPass();
|
||||||
|
}
|
||||||
|
|
||||||
|
wgpu::CommandBuffer commands = encoder.Finish();
|
||||||
|
ASSERT_DEVICE_ERROR(queue.Submit(1, &commands));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
@ -274,6 +274,33 @@ TEST_F(GetBindGroupLayoutTests, BindingType) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Test that an external texture binding type matches a shader using texture_external.
|
||||||
|
// TODO(dawn:728) Enable this test once Dawn no longer relies on SPIRV-Cross to extract shader info.
|
||||||
|
// Consider combining with the similar test above.
|
||||||
|
TEST_F(GetBindGroupLayoutTests, DISABLED_ExternalTextureBindingType) {
|
||||||
|
// This test works assuming Dawn Native's object deduplication.
|
||||||
|
// Getting the same pointer to equivalent bind group layouts is an implementation detail of Dawn
|
||||||
|
// Native.
|
||||||
|
DAWN_SKIP_TEST_IF(UsesWire());
|
||||||
|
|
||||||
|
wgpu::BindGroupLayoutEntry binding = {};
|
||||||
|
binding.binding = 0;
|
||||||
|
binding.visibility = wgpu::ShaderStage::Fragment;
|
||||||
|
|
||||||
|
wgpu::BindGroupLayoutDescriptor desc = {};
|
||||||
|
desc.entryCount = 1;
|
||||||
|
desc.entries = &binding;
|
||||||
|
|
||||||
|
binding.nextInChain = &utils::kExternalTextureBindingLayout;
|
||||||
|
wgpu::RenderPipeline pipeline = RenderPipelineFromFragmentShader(R"(
|
||||||
|
[[group(0), binding(0)]] var myExternalTexture: texture_external;
|
||||||
|
|
||||||
|
[[stage(fragment)]] fn main() {
|
||||||
|
textureDimensions(myExternalTexture);
|
||||||
|
})");
|
||||||
|
EXPECT_EQ(device.CreateBindGroupLayout(&desc).Get(), pipeline.GetBindGroupLayout(0).Get());
|
||||||
|
}
|
||||||
|
|
||||||
// Test that texture view dimension matches the shader.
|
// Test that texture view dimension matches the shader.
|
||||||
TEST_F(GetBindGroupLayoutTests, ViewDimension) {
|
TEST_F(GetBindGroupLayoutTests, ViewDimension) {
|
||||||
// This test works assuming Dawn Native's object deduplication.
|
// This test works assuming Dawn Native's object deduplication.
|
||||||
|
@ -40,6 +40,7 @@ TEST_F(WireOptionalTests, OptionalObjectValue) {
|
|||||||
entry.sampler = nullptr;
|
entry.sampler = nullptr;
|
||||||
entry.textureView = nullptr;
|
entry.textureView = nullptr;
|
||||||
entry.buffer = nullptr;
|
entry.buffer = nullptr;
|
||||||
|
entry.nextInChain = nullptr;
|
||||||
|
|
||||||
WGPUBindGroupDescriptor bgDesc = {};
|
WGPUBindGroupDescriptor bgDesc = {};
|
||||||
bgDesc.layout = bgl;
|
bgDesc.layout = bgl;
|
||||||
|
@ -26,7 +26,6 @@
|
|||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
namespace utils {
|
namespace utils {
|
||||||
|
|
||||||
wgpu::ShaderModule CreateShaderModuleFromASM(const wgpu::Device& device, const char* source) {
|
wgpu::ShaderModule CreateShaderModuleFromASM(const wgpu::Device& device, const char* source) {
|
||||||
// Use SPIRV-Tools's C API to assemble the SPIR-V assembly text to binary. Because the types
|
// Use SPIRV-Tools's C API to assemble the SPIR-V assembly text to binary. Because the types
|
||||||
// aren't RAII, we don't return directly on success and instead always go through the code
|
// aren't RAII, we don't return directly on success and instead always go through the code
|
||||||
@ -296,6 +295,19 @@ namespace utils {
|
|||||||
storageTexture.viewDimension = textureViewDimension;
|
storageTexture.viewDimension = textureViewDimension;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ExternalTextureBindingLayout never contains data, so just make one that can be reused instead
|
||||||
|
// of declaring a new one every time it's needed.
|
||||||
|
wgpu::ExternalTextureBindingLayout kExternalTextureBindingLayout = {};
|
||||||
|
|
||||||
|
BindingLayoutEntryInitializationHelper::BindingLayoutEntryInitializationHelper(
|
||||||
|
uint32_t entryBinding,
|
||||||
|
wgpu::ShaderStage entryVisibility,
|
||||||
|
wgpu::ExternalTextureBindingLayout* bindingLayout) {
|
||||||
|
binding = entryBinding;
|
||||||
|
visibility = entryVisibility;
|
||||||
|
nextInChain = bindingLayout;
|
||||||
|
}
|
||||||
|
|
||||||
BindingLayoutEntryInitializationHelper::BindingLayoutEntryInitializationHelper(
|
BindingLayoutEntryInitializationHelper::BindingLayoutEntryInitializationHelper(
|
||||||
const wgpu::BindGroupLayoutEntry& entry)
|
const wgpu::BindGroupLayoutEntry& entry)
|
||||||
: wgpu::BindGroupLayoutEntry(entry) {
|
: wgpu::BindGroupLayoutEntry(entry) {
|
||||||
@ -311,6 +323,13 @@ namespace utils {
|
|||||||
: binding(binding), textureView(textureView) {
|
: binding(binding), textureView(textureView) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BindingInitializationHelper::BindingInitializationHelper(
|
||||||
|
uint32_t binding,
|
||||||
|
const wgpu::ExternalTexture& externalTexture)
|
||||||
|
: binding(binding) {
|
||||||
|
externalTextureBindingEntry.externalTexture = externalTexture;
|
||||||
|
}
|
||||||
|
|
||||||
BindingInitializationHelper::BindingInitializationHelper(uint32_t binding,
|
BindingInitializationHelper::BindingInitializationHelper(uint32_t binding,
|
||||||
const wgpu::Buffer& buffer,
|
const wgpu::Buffer& buffer,
|
||||||
uint64_t offset,
|
uint64_t offset,
|
||||||
@ -327,6 +346,9 @@ namespace utils {
|
|||||||
result.buffer = buffer;
|
result.buffer = buffer;
|
||||||
result.offset = offset;
|
result.offset = offset;
|
||||||
result.size = size;
|
result.size = size;
|
||||||
|
if (externalTextureBindingEntry.externalTexture != nullptr) {
|
||||||
|
result.nextInChain = &externalTextureBindingEntry;
|
||||||
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -97,6 +97,8 @@ namespace utils {
|
|||||||
wgpu::PipelineLayout MakePipelineLayout(const wgpu::Device& device,
|
wgpu::PipelineLayout MakePipelineLayout(const wgpu::Device& device,
|
||||||
std::vector<wgpu::BindGroupLayout> bgls);
|
std::vector<wgpu::BindGroupLayout> bgls);
|
||||||
|
|
||||||
|
extern wgpu::ExternalTextureBindingLayout kExternalTextureBindingLayout;
|
||||||
|
|
||||||
// Helpers to make creating bind group layouts look nicer:
|
// Helpers to make creating bind group layouts look nicer:
|
||||||
//
|
//
|
||||||
// utils::MakeBindGroupLayout(device, {
|
// utils::MakeBindGroupLayout(device, {
|
||||||
@ -126,6 +128,9 @@ namespace utils {
|
|||||||
wgpu::StorageTextureAccess storageTextureAccess,
|
wgpu::StorageTextureAccess storageTextureAccess,
|
||||||
wgpu::TextureFormat format,
|
wgpu::TextureFormat format,
|
||||||
wgpu::TextureViewDimension viewDimension = wgpu::TextureViewDimension::e2D);
|
wgpu::TextureViewDimension viewDimension = wgpu::TextureViewDimension::e2D);
|
||||||
|
BindingLayoutEntryInitializationHelper(uint32_t entryBinding,
|
||||||
|
wgpu::ShaderStage entryVisibility,
|
||||||
|
wgpu::ExternalTextureBindingLayout* bindingLayout);
|
||||||
|
|
||||||
BindingLayoutEntryInitializationHelper(const wgpu::BindGroupLayoutEntry& entry);
|
BindingLayoutEntryInitializationHelper(const wgpu::BindGroupLayoutEntry& entry);
|
||||||
};
|
};
|
||||||
@ -147,6 +152,7 @@ namespace utils {
|
|||||||
struct BindingInitializationHelper {
|
struct BindingInitializationHelper {
|
||||||
BindingInitializationHelper(uint32_t binding, const wgpu::Sampler& sampler);
|
BindingInitializationHelper(uint32_t binding, const wgpu::Sampler& sampler);
|
||||||
BindingInitializationHelper(uint32_t binding, const wgpu::TextureView& textureView);
|
BindingInitializationHelper(uint32_t binding, const wgpu::TextureView& textureView);
|
||||||
|
BindingInitializationHelper(uint32_t binding, const wgpu::ExternalTexture& externalTexture);
|
||||||
BindingInitializationHelper(uint32_t binding,
|
BindingInitializationHelper(uint32_t binding,
|
||||||
const wgpu::Buffer& buffer,
|
const wgpu::Buffer& buffer,
|
||||||
uint64_t offset = 0,
|
uint64_t offset = 0,
|
||||||
@ -158,6 +164,7 @@ namespace utils {
|
|||||||
wgpu::Sampler sampler;
|
wgpu::Sampler sampler;
|
||||||
wgpu::TextureView textureView;
|
wgpu::TextureView textureView;
|
||||||
wgpu::Buffer buffer;
|
wgpu::Buffer buffer;
|
||||||
|
wgpu::ExternalTextureBindingEntry externalTextureBindingEntry;
|
||||||
uint64_t offset = 0;
|
uint64_t offset = 0;
|
||||||
uint64_t size = 0;
|
uint64_t size = 0;
|
||||||
};
|
};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user