[YCbCr Samplers] Add wgpu::TextureFormat::External
Add wgpu::TextureFormat::External to be used with creating YCbCr
samplers. Also add useExternalFormat bool for picking externalFormat
vs vkFormat when creating vkImage. Add necessary tests and validations.
Change-Id: I2f82d591fccf9786d11d554a0a23cec070653565
Bug: dawn:2476
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/187361
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Commit-Queue: Saifuddin Hitawala <hitawala@chromium.org>
Reviewed-by: Austin Eng <enga@chromium.org>
diff --git a/src/dawn/dawn.json b/src/dawn/dawn.json
index 551eac1..f1cf9a6 100644
--- a/src/dawn/dawn.json
+++ b/src/dawn/dawn.json
@@ -2089,7 +2089,8 @@
"chain roots": ["shared texture memory descriptor"],
"tags": ["dawn", "native"],
"members": [
- {"name": "handle", "type": "void *"}
+ {"name": "handle", "type": "void *"},
+ {"name": "use external format", "type" : "bool"}
]
},
"shared texture memory dma buf plane": {
@@ -4216,7 +4217,8 @@
{"value": 105, "name": "R8 BG8 Biplanar 422 unorm", "tags": ["dawn"]},
{"value": 106, "name": "R8 BG8 Biplanar 444 unorm", "tags": ["dawn"]},
{"value": 107, "name": "R10X6 BG10X6 Biplanar 422 unorm", "tags": ["dawn"]},
- {"value": 108, "name": "R10X6 BG10X6 Biplanar 444 unorm", "tags": ["dawn"]}
+ {"value": 108, "name": "R10X6 BG10X6 Biplanar 444 unorm", "tags": ["dawn"]},
+ {"value": 109, "name": "External", "tags": ["dawn"]}
]
},
"texture usage": {
diff --git a/src/dawn/native/Format.cpp b/src/dawn/native/Format.cpp
index 75c54d9..029f474 100644
--- a/src/dawn/native/Format.cpp
+++ b/src/dawn/native/Format.cpp
@@ -462,6 +462,9 @@
AddColorFormat(wgpu::TextureFormat::RGBA8Uint, Cap::Renderable | Cap::StorageROrW | Cap::Multisample, ByteSize(4), SampleTypeBit::Uint, ComponentCount(4), RenderTargetPixelByteCost(4), RenderTargetComponentAlignment(1));
AddColorFormat(wgpu::TextureFormat::RGBA8Sint, Cap::Renderable | Cap::StorageROrW | Cap::Multisample, ByteSize(4), SampleTypeBit::Sint, ComponentCount(4), RenderTargetPixelByteCost(4), RenderTargetComponentAlignment(1));
+ const UnsupportedReason externalUnsupportedReason = device->HasFeature(Feature::YCbCrVulkanSamplers) ? Format::supported : RequiresFeature{wgpu::FeatureName::YCbCrVulkanSamplers};
+ AddConditionalColorFormat(wgpu::TextureFormat::External, externalUnsupportedReason, Cap::None, ByteSize(1), SampleTypeBit::External, ComponentCount(0));
+
auto BGRA8UnormSupportsStorageUsage = device->HasFeature(Feature::BGRA8UnormStorage) ? Cap::StorageROrW : Cap::None;
AddColorFormat(wgpu::TextureFormat::BGRA8Unorm, Cap::Renderable | BGRA8UnormSupportsStorageUsage | Cap::Multisample | Cap::Resolve, ByteSize(4), kAnyFloat, ComponentCount(4), RenderTargetPixelByteCost(8), RenderTargetComponentAlignment(1));
AddConditionalColorFormat(wgpu::TextureFormat::BGRA8UnormSrgb, device->IsCompatibilityMode() ? UnsupportedReason(CompatibilityMode{}) : Format::supported, Cap::Renderable | Cap::Multisample | Cap::Resolve, ByteSize(4), kAnyFloat, ComponentCount(4), RenderTargetPixelByteCost(8), RenderTargetComponentAlignment(1), wgpu::TextureFormat::BGRA8Unorm);
diff --git a/src/dawn/native/Format.h b/src/dawn/native/Format.h
index ca94056..3efb5b4 100644
--- a/src/dawn/native/Format.h
+++ b/src/dawn/native/Format.h
@@ -67,6 +67,7 @@
// NOTE: SampleTypeBit::External does not have an equivalent TextureSampleType. All future
// additions to SampleTypeBit that have an equivalent TextureSampleType should use
// SampleTypeBit::External's value and update SampleTypeBit::External to a higher value.
+// TODO(crbug.com/dawn/2476): Validate SampleTypeBit::External is compatible with Sampler.
enum class SampleTypeBit : uint8_t {
None = 0x0,
Float = 0x1,
@@ -117,7 +118,7 @@
// The number of formats Dawn knows about. Asserts in BuildFormatTable ensure that this is the
// exact number of known format.
-static constexpr uint32_t kKnownFormatCount = 108;
+static constexpr uint32_t kKnownFormatCount = 109;
using FormatIndex = TypedInteger<struct FormatIndexT, uint32_t>;
diff --git a/src/dawn/native/SharedTextureMemory.cpp b/src/dawn/native/SharedTextureMemory.cpp
index 041b3e5..eafb189 100644
--- a/src/dawn/native/SharedTextureMemory.cpp
+++ b/src/dawn/native/SharedTextureMemory.cpp
@@ -87,16 +87,19 @@
: SharedResourceMemory(device, label), mProperties(properties) {
// Reify properties to ensure we don't expose capabilities not supported by the device.
const Format& internalFormat = device->GetValidInternalFormat(mProperties.format);
- if (!internalFormat.supportsStorageUsage || internalFormat.IsMultiPlanar()) {
- mProperties.usage = mProperties.usage & ~wgpu::TextureUsage::StorageBinding;
- }
- if (!internalFormat.isRenderable || (internalFormat.IsMultiPlanar() &&
- !device->HasFeature(Feature::MultiPlanarRenderTargets))) {
- mProperties.usage = mProperties.usage & ~wgpu::TextureUsage::RenderAttachment;
- }
- if (internalFormat.IsMultiPlanar() &&
- !device->HasFeature(Feature::MultiPlanarFormatExtendedUsages)) {
- mProperties.usage = mProperties.usage & ~wgpu::TextureUsage::CopyDst;
+ if (internalFormat.format != wgpu::TextureFormat::External) {
+ if (!internalFormat.supportsStorageUsage || internalFormat.IsMultiPlanar()) {
+ mProperties.usage = mProperties.usage & ~wgpu::TextureUsage::StorageBinding;
+ }
+ if (!internalFormat.isRenderable ||
+ (internalFormat.IsMultiPlanar() &&
+ !device->HasFeature(Feature::MultiPlanarRenderTargets))) {
+ mProperties.usage = mProperties.usage & ~wgpu::TextureUsage::RenderAttachment;
+ }
+ if (internalFormat.IsMultiPlanar() &&
+ !device->HasFeature(Feature::MultiPlanarFormatExtendedUsages)) {
+ mProperties.usage = mProperties.usage & ~wgpu::TextureUsage::CopyDst;
+ }
}
GetObjectTrackingList()->Track(this);
diff --git a/src/dawn/native/Subresource.cpp b/src/dawn/native/Subresource.cpp
index 2429029..974cde3 100644
--- a/src/dawn/native/Subresource.cpp
+++ b/src/dawn/native/Subresource.cpp
@@ -82,8 +82,6 @@
}
Aspect SelectFormatAspects(const Format& format, wgpu::TextureAspect aspect) {
- // TODO(crbug.com/dawn/2476): Return Aspect::Color for TextureFormat::External if aspect is
- // present else None.
switch (aspect) {
case wgpu::TextureAspect::All:
return format.aspects;
diff --git a/src/dawn/native/Texture.cpp b/src/dawn/native/Texture.cpp
index 405da76..a467029 100644
--- a/src/dawn/native/Texture.cpp
+++ b/src/dawn/native/Texture.cpp
@@ -604,7 +604,6 @@
DAWN_ASSERT(!texture->IsError());
DAWN_TRY(ValidateTextureViewDimension(descriptor->dimension));
- // TODO(crbug.com/dawn/2476): Add necessary validation for TextureFormat::External.
DAWN_TRY(ValidateTextureFormat(descriptor->format));
DAWN_TRY(ValidateTextureAspect(descriptor->aspect));
@@ -635,16 +634,20 @@
"texture's mip level count (%u).",
descriptor->baseMipLevel, descriptor->mipLevelCount, texture->GetNumMipLevels());
- // TODO(crbug.com/dawn/2476): Add necessary validations to CanViewTextureAs for
- // TextureFormat::External.
- DAWN_TRY(ValidateCanViewTextureAs(device, texture, *viewFormat, descriptor->aspect));
- DAWN_TRY(ValidateTextureViewDimensionCompatibility(device, texture, descriptor));
-
if (descriptor.Get<YCbCrVkDescriptor>()) {
DAWN_INVALID_IF(!device->HasFeature(Feature::YCbCrVulkanSamplers), "%s is not enabled.",
wgpu::FeatureName::YCbCrVulkanSamplers);
+ DAWN_INVALID_IF(format.format != wgpu::TextureFormat::External,
+ "Texture format (%s) is not (%s).", format.format,
+ wgpu::TextureFormat::External);
+ } else if (format.format == wgpu::TextureFormat::External) {
+ return DAWN_VALIDATION_ERROR("Invalid TextureViewDescriptor with Texture format (%s).",
+ wgpu::TextureFormat::External);
}
+ DAWN_TRY(ValidateCanViewTextureAs(device, texture, *viewFormat, descriptor->aspect));
+ DAWN_TRY(ValidateTextureViewDimensionCompatibility(device, texture, descriptor));
+
return {};
}
@@ -683,7 +686,6 @@
}
}
- // TODO(crbug.com/dawn/2476): Add TextureFormat::External validation.
if (desc.format == wgpu::TextureFormat::Undefined) {
const Format& format = texture->GetFormat();
diff --git a/src/dawn/native/d3d/UtilsD3D.cpp b/src/dawn/native/d3d/UtilsD3D.cpp
index 52a5c95..9d0123a 100644
--- a/src/dawn/native/d3d/UtilsD3D.cpp
+++ b/src/dawn/native/d3d/UtilsD3D.cpp
@@ -255,6 +255,7 @@
case wgpu::TextureFormat::R10X6BG10X6Biplanar420Unorm:
case wgpu::TextureFormat::R10X6BG10X6Biplanar422Unorm:
case wgpu::TextureFormat::R10X6BG10X6Biplanar444Unorm:
+ case wgpu::TextureFormat::External:
case wgpu::TextureFormat::Undefined:
DAWN_UNREACHABLE();
}
@@ -405,6 +406,7 @@
case wgpu::TextureFormat::R8BG8A8Triplanar420Unorm:
case wgpu::TextureFormat::R10X6BG10X6Biplanar422Unorm:
case wgpu::TextureFormat::R10X6BG10X6Biplanar444Unorm:
+ case wgpu::TextureFormat::External:
case wgpu::TextureFormat::Undefined:
DAWN_UNREACHABLE();
diff --git a/src/dawn/native/metal/UtilsMetal.mm b/src/dawn/native/metal/UtilsMetal.mm
index abefea9..69d6de2 100644
--- a/src/dawn/native/metal/UtilsMetal.mm
+++ b/src/dawn/native/metal/UtilsMetal.mm
@@ -550,6 +550,7 @@
case wgpu::TextureFormat::R10X6BG10X6Biplanar422Unorm:
case wgpu::TextureFormat::R10X6BG10X6Biplanar444Unorm:
case wgpu::TextureFormat::R8BG8A8Triplanar420Unorm:
+ case wgpu::TextureFormat::External:
case wgpu::TextureFormat::Undefined:
DAWN_UNREACHABLE();
}
diff --git a/src/dawn/native/vulkan/SharedTextureMemoryVk.cpp b/src/dawn/native/vulkan/SharedTextureMemoryVk.cpp
index 66b8ef8..6560fad 100644
--- a/src/dawn/native/vulkan/SharedTextureMemoryVk.cpp
+++ b/src/dawn/native/vulkan/SharedTextureMemoryVk.cpp
@@ -492,6 +492,8 @@
auto* aHardwareBuffer = static_cast<struct AHardwareBuffer*>(descriptor->handle);
+ bool useExternalFormat = descriptor->useExternalFormat;
+
const VkExternalMemoryHandleTypeFlagBits handleType =
VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID;
@@ -502,12 +504,19 @@
SharedTextureMemoryProperties properties;
properties.size = {aHardwareBufferDesc.width, aHardwareBufferDesc.height,
aHardwareBufferDesc.layers};
- properties.usage = wgpu::TextureUsage::CopySrc | wgpu::TextureUsage::CopyDst;
- if (aHardwareBufferDesc.usage & AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER) {
- properties.usage |= wgpu::TextureUsage::RenderAttachment;
- }
- if (aHardwareBufferDesc.usage & AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE) {
- properties.usage |= wgpu::TextureUsage::TextureBinding | wgpu::TextureUsage::StorageBinding;
+ if (useExternalFormat) {
+ if (aHardwareBufferDesc.usage & AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE) {
+ properties.usage = wgpu::TextureUsage::TextureBinding;
+ }
+ } else {
+ properties.usage = wgpu::TextureUsage::CopySrc | wgpu::TextureUsage::CopyDst;
+ if (aHardwareBufferDesc.usage & AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER) {
+ properties.usage |= wgpu::TextureUsage::RenderAttachment;
+ }
+ if (aHardwareBufferDesc.usage & AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE) {
+ properties.usage |=
+ wgpu::TextureUsage::TextureBinding | wgpu::TextureUsage::StorageBinding;
+ }
}
VkFormat vkFormat;
@@ -515,6 +524,9 @@
VkAndroidHardwareBufferPropertiesANDROID bufferProperties = {
.sType = VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_PROPERTIES_ANDROID,
};
+ VkExternalFormatANDROID externalFormatAndroid = {
+ .sType = VK_STRUCTURE_TYPE_EXTERNAL_FORMAT_ANDROID,
+ };
// Query the properties to find the appropriate VkFormat and memory type.
{
@@ -528,11 +540,22 @@
vkDevice, aHardwareBuffer, &bufferProperties),
"vkGetAndroidHardwareBufferPropertiesANDROID"));
- vkFormat = bufferFormatProperties.format;
+ // TODO(crbug.com/dawn/2476): Validate more as per
+ // https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkImageCreateInfo.html
+ if (useExternalFormat) {
+ DAWN_ASSERT(bufferFormatProperties.externalFormat != 0);
+ vkFormat = VK_FORMAT_UNDEFINED;
+ externalFormatAndroid.externalFormat = bufferFormatProperties.externalFormat;
+ properties.format = wgpu::TextureFormat::External;
+ } else {
+ vkFormat = bufferFormatProperties.format;
+ externalFormatAndroid.externalFormat = 0;
+ DAWN_TRY_ASSIGN(properties.format, FormatFromVkFormat(device, vkFormat));
+ }
// Populate the YCbCr info.
- yCbCrAHBInfo.externalFormat = bufferFormatProperties.externalFormat;
- yCbCrAHBInfo.vkFormat = bufferFormatProperties.format;
+ yCbCrAHBInfo.externalFormat = externalFormatAndroid.externalFormat;
+ yCbCrAHBInfo.vkFormat = vkFormat;
yCbCrAHBInfo.vkYCbCrModel = bufferFormatProperties.suggestedYcbcrModel;
yCbCrAHBInfo.vkYCbCrRange = bufferFormatProperties.suggestedYcbcrRange;
yCbCrAHBInfo.vkComponentSwizzleRed =
@@ -555,7 +578,6 @@
formatFeatures &
VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_BIT;
}
- DAWN_TRY_ASSIGN(properties.format, FormatFromVkFormat(device, vkFormat));
const Format* internalFormat = nullptr;
DAWN_TRY_ASSIGN(internalFormat, device->GetInternalFormat(properties.format));
@@ -596,53 +618,57 @@
imageFormatInfo.usage = vkUsageFlags;
imageFormatInfo.flags = 0;
- constexpr wgpu::TextureUsage kUsageRequiringView = wgpu::TextureUsage::RenderAttachment |
- wgpu::TextureUsage::TextureBinding |
- wgpu::TextureUsage::StorageBinding;
- const bool mayNeedViewReinterpretation =
- (properties.usage & kUsageRequiringView) != 0 && !compatibleViewFormats.empty();
- const bool needsBGRA8UnormStoragePolyfill =
- properties.format == wgpu::TextureFormat::BGRA8Unorm &&
- (properties.usage & wgpu::TextureUsage::StorageBinding);
- if (mayNeedViewReinterpretation || needsBGRA8UnormStoragePolyfill) {
- // Add the mutable format bit for view reinterpretation.
- imageFormatInfo.flags |= VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT;
+ if (!useExternalFormat) {
+ constexpr wgpu::TextureUsage kUsageRequiringView =
+ wgpu::TextureUsage::RenderAttachment | wgpu::TextureUsage::TextureBinding |
+ wgpu::TextureUsage::StorageBinding;
+ const bool mayNeedViewReinterpretation =
+ (properties.usage & kUsageRequiringView) != 0 && !compatibleViewFormats.empty();
+ const bool needsBGRA8UnormStoragePolyfill =
+ properties.format == wgpu::TextureFormat::BGRA8Unorm &&
+ (properties.usage & wgpu::TextureUsage::StorageBinding);
+ if (mayNeedViewReinterpretation || needsBGRA8UnormStoragePolyfill) {
+ // Add the mutable format bit for view reinterpretation.
+ imageFormatInfo.flags |= VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT;
- if (properties.usage & wgpu::TextureUsage::StorageBinding) {
- // Don't use an image format list because it becomes impossible to make an
- // rgba8unorm storage texture which may be reinterpreted as rgba8unorm-srgb,
- // because the srgb format doesn't support storage. Creation with an explicit
- // format list that includes srgb will fail.
- // This is the same issue seen with the DMA buf import path which has a workaround
- // to bypass the support check.
- // TODO(crbug.com/dawn/2304): If the dma buf import is resolved in a better way,
- // apply the same fix here.
- } else if (device->GetDeviceInfo().HasExt(DeviceExt::ImageFormatList)) {
- // Set the list of view formats the image can be compatible with.
- DAWN_ASSERT(compatibleViewFormats.size() == 1u);
- viewFormats[0] = vkFormat;
- viewFormats[1] = VulkanImageFormat(device, compatibleViewFormats[0]->format);
- imageFormatListInfo.viewFormatCount = 2;
- imageFormatListInfo.pViewFormats = viewFormats.data();
+ if (properties.usage & wgpu::TextureUsage::StorageBinding) {
+ // Don't use an image format list because it becomes impossible to make an
+ // rgba8unorm storage texture which may be reinterpreted as rgba8unorm-srgb,
+ // because the srgb format doesn't support storage. Creation with an explicit
+ // format list that includes srgb will fail.
+ // This is the same issue seen with the DMA buf import path which has a
+ // workaround to bypass the support check.
+ // TODO(crbug.com/dawn/2304): If the dma buf import is resolved in a better way,
+ // apply the same fix here.
+ } else if (device->GetDeviceInfo().HasExt(DeviceExt::ImageFormatList)) {
+ // Set the list of view formats the image can be compatible with.
+ DAWN_ASSERT(compatibleViewFormats.size() == 1u);
+ viewFormats[0] = vkFormat;
+ viewFormats[1] = VulkanImageFormat(device, compatibleViewFormats[0]->format);
+ imageFormatListInfo.viewFormatCount = 2;
+ imageFormatListInfo.pViewFormats = viewFormats.data();
+ }
}
- }
- if (imageFormatListInfo.viewFormatCount > 0) {
- DAWN_TRY_CONTEXT(CheckExternalImageFormatSupport(device, properties, &imageFormatInfo,
- handleType, &imageFormatListInfo),
- "checking import support of AHardwareBuffer");
- } else {
- DAWN_TRY_CONTEXT(
- CheckExternalImageFormatSupport(device, properties, &imageFormatInfo, handleType),
- "checking import support of AHardwareBuffer");
+ if (imageFormatListInfo.viewFormatCount > 0) {
+ DAWN_TRY_CONTEXT(
+ CheckExternalImageFormatSupport(device, properties, &imageFormatInfo,
+ handleType, &imageFormatListInfo),
+ "checking import support of AHardwareBuffer");
+ } else {
+ DAWN_TRY_CONTEXT(CheckExternalImageFormatSupport(device, properties,
+ &imageFormatInfo, handleType),
+ "checking import support of AHardwareBuffer");
+ }
}
}
// Create the VkImage for the import.
{
VkImage vkImage;
- DAWN_TRY_ASSIGN(vkImage, CreateExternalVkImage(device, properties, imageFormatInfo,
- handleType, &imageFormatListInfo));
+ DAWN_TRY_ASSIGN(vkImage,
+ CreateExternalVkImage(device, properties, imageFormatInfo, handleType,
+ &imageFormatListInfo, &externalFormatAndroid));
sharedTextureMemory->mVkImage =
AcquireRef(new RefCountedVkHandle<VkImage>(device, vkImage));
@@ -967,6 +993,7 @@
TextureBase* texture,
const UnpackedPtr<BeginAccessDescriptor>& descriptor) {
// TODO(dawn/2276): support concurrent read access.
+ // TODO(dawn/2476): Validate texture with TextureFormat::External is initialized.
DAWN_INVALID_IF(descriptor->concurrentRead, "Vulkan backend doesn't support concurrent read.");
wgpu::SType type;
diff --git a/src/dawn/native/vulkan/TextureVk.cpp b/src/dawn/native/vulkan/TextureVk.cpp
index 29958df..ff47906 100644
--- a/src/dawn/native/vulkan/TextureVk.cpp
+++ b/src/dawn/native/vulkan/TextureVk.cpp
@@ -524,6 +524,10 @@
return VulkanImageFormat(device, wgpu::TextureFormat::Depth24PlusStencil8);
}
+ case wgpu::TextureFormat::External:
+ // The VkFormat is Undefined when TextureFormat::External is passed for YCbCr samplers.
+ return VK_FORMAT_UNDEFINED;
+
// R8BG8A8Triplanar420Unorm format is only supported on macOS.
case wgpu::TextureFormat::R8BG8A8Triplanar420Unorm:
case wgpu::TextureFormat::Undefined:
@@ -564,6 +568,7 @@
return wgpu::TextureFormat::Depth24PlusStencil8;
}
break;
+
default:
break;
}
@@ -1768,6 +1773,7 @@
if (auto* yCbCrVkDescriptor = descriptor.Get<YCbCrVkDescriptor>()) {
mYCbCrVkDescriptor = *yCbCrVkDescriptor;
mYCbCrVkDescriptor.nextInChain = nullptr;
+
DAWN_TRY_ASSIGN(mSamplerYCbCrConversion,
CreateSamplerYCbCrConversionCreateInfo(mYCbCrVkDescriptor, device));
diff --git a/src/dawn/node/binding/Converter.cpp b/src/dawn/node/binding/Converter.cpp
index a0ed1fe..d562bd7 100644
--- a/src/dawn/node/binding/Converter.cpp
+++ b/src/dawn/node/binding/Converter.cpp
@@ -666,6 +666,7 @@
case wgpu::TextureFormat::RG16Unorm:
case wgpu::TextureFormat::RGBA16Snorm:
case wgpu::TextureFormat::RGBA16Unorm:
+ case wgpu::TextureFormat::External:
case wgpu::TextureFormat::Undefined:
return false;
diff --git a/src/dawn/tests/end2end/YCbCrInfoTests.cpp b/src/dawn/tests/end2end/YCbCrInfoTests.cpp
index 7e8fa4d7..38972ac 100644
--- a/src/dawn/tests/end2end/YCbCrInfoTests.cpp
+++ b/src/dawn/tests/end2end/YCbCrInfoTests.cpp
@@ -37,24 +37,53 @@
namespace dawn {
namespace {
-constexpr uint32_t kWidth = 32u;
-constexpr uint32_t kHeight = 32u;
-constexpr uint32_t kDefaultMipLevels = 6u;
+constexpr uint32_t kDefaultMipLevels = 1u;
constexpr uint32_t kDefaultLayerCount = 1u;
-constexpr uint32_t kDefaultSampleCount = 1u;
-constexpr wgpu::TextureFormat kDefaultTextureFormat = wgpu::TextureFormat::RGBA8Unorm;
+constexpr wgpu::TextureFormat kDefaultTextureFormat = wgpu::TextureFormat::External;
-wgpu::Texture Create2DTexture(wgpu::Device& device) {
+wgpu::Texture Create2DTexture(wgpu::Device& device,
+ wgpu::TextureFormat format = kDefaultTextureFormat) {
+#if DAWN_PLATFORM_IS(ANDROID)
+ constexpr uint32_t kWidth = 32u;
+ constexpr uint32_t kHeight = 32u;
+ AHardwareBuffer_Desc aHardwareBufferDesc = {
+ .width = kWidth,
+ .height = kHeight,
+ .layers = 1,
+ .format = AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM,
+ .usage = AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE,
+ };
+ AHardwareBuffer* aHardwareBuffer;
+ EXPECT_EQ(AHardwareBuffer_allocate(&aHardwareBufferDesc, &aHardwareBuffer), 0);
+
+ // Get actual desc for allocated buffer so we know the stride for cpu data.
+ AHardwareBuffer_describe(aHardwareBuffer, &aHardwareBufferDesc);
+
+ wgpu::SharedTextureMemoryAHardwareBufferDescriptor stmAHardwareBufferDesc;
+ stmAHardwareBufferDesc.handle = aHardwareBuffer;
+ stmAHardwareBufferDesc.useExternalFormat = true;
+
+ wgpu::SharedTextureMemoryDescriptor desc;
+ desc.nextInChain = &stmAHardwareBufferDesc;
+
+ wgpu::SharedTextureMemory memory = device.ImportSharedTextureMemory(&desc);
+
wgpu::TextureDescriptor descriptor;
descriptor.dimension = wgpu::TextureDimension::e2D;
descriptor.size.width = kWidth;
descriptor.size.height = kHeight;
descriptor.size.depthOrArrayLayers = kDefaultLayerCount;
- descriptor.sampleCount = kDefaultSampleCount;
+ descriptor.sampleCount = 1u;
descriptor.format = kDefaultTextureFormat;
descriptor.mipLevelCount = kDefaultMipLevels;
- descriptor.usage = wgpu::TextureUsage::TextureBinding | wgpu::TextureUsage::RenderAttachment;
- return device.CreateTexture(&descriptor);
+ descriptor.usage = wgpu::TextureUsage::TextureBinding;
+
+ auto texture = memory.CreateTexture(&descriptor);
+ AHardwareBuffer_release(aHardwareBuffer);
+ return texture;
+#else
+ return {};
+#endif
}
wgpu::TextureViewDescriptor CreateDefaultViewDescriptor(wgpu::TextureViewDimension dimension) {
@@ -83,8 +112,10 @@
std::vector<wgpu::FeatureName> GetRequiredFeatures() override {
std::vector<wgpu::FeatureName> requiredFeatures = {};
if (SupportsFeatures({wgpu::FeatureName::StaticSamplers}) &&
- SupportsFeatures({wgpu::FeatureName::YCbCrVulkanSamplers})) {
+ SupportsFeatures({wgpu::FeatureName::YCbCrVulkanSamplers}) &&
+ SupportsFeatures({wgpu::FeatureName::SharedTextureMemoryAHardwareBuffer})) {
requiredFeatures.push_back(wgpu::FeatureName::YCbCrVulkanSamplers);
+ requiredFeatures.push_back(wgpu::FeatureName::SharedTextureMemoryAHardwareBuffer);
}
return requiredFeatures;
}
@@ -138,8 +169,25 @@
ASSERT_DEVICE_ERROR(device.CreateSampler(&samplerDesc));
}
+// Test that it is invalid to create texture view with formats other than External.
+TEST_P(YCbCrInfoTest, YCbCrTextureViewInvalidWithoutWgpuFormatExternal) {
+ wgpu::Texture texture = Create2DTexture(device);
+
+ wgpu::TextureViewDescriptor descriptor =
+ CreateDefaultViewDescriptor(wgpu::TextureViewDimension::e2D);
+ // Pass RGBA8Unorm instead of External format.
+ descriptor.format = wgpu::TextureFormat::RGBA8Unorm;
+ descriptor.arrayLayerCount = 1;
+
+ wgpu::YCbCrVkDescriptor yCbCrDesc = {};
+ yCbCrDesc.vkFormat = VK_FORMAT_R8G8B8A8_UNORM;
+ descriptor.nextInChain = &yCbCrDesc;
+
+ ASSERT_DEVICE_ERROR(texture.CreateView(&descriptor));
+}
+
// Test that it is possible to create texture view with ycbcr vulkan descriptor.
-TEST_P(YCbCrInfoTest, YCbCrTextureViewValidWhenFeatureEnabled) {
+TEST_P(YCbCrInfoTest, YCbCrTextureViewValidWithWgpuFormatExternal) {
wgpu::Texture texture = Create2DTexture(device);
wgpu::TextureViewDescriptor descriptor =
@@ -206,6 +254,18 @@
ASSERT_DEVICE_ERROR(texture.CreateView(&descriptor));
}
+// Test that it is NOT possible to create texture view from texture created with
+// TextureFormat::External but NO ycbcr vulkan descriptor passed.
+TEST_P(YCbCrInfoTest, YCbCrTextureViewInvalidWithNoYCbCrDescriptor) {
+ wgpu::Texture texture = Create2DTexture(device);
+
+ wgpu::TextureViewDescriptor descriptor =
+ CreateDefaultViewDescriptor(wgpu::TextureViewDimension::e2D);
+ descriptor.arrayLayerCount = 1;
+
+ ASSERT_DEVICE_ERROR(texture.CreateView(&descriptor));
+}
+
DAWN_INSTANTIATE_TEST(YCbCrInfoTest, VulkanBackend());
} // anonymous namespace
diff --git a/src/dawn/tests/unittests/validation/YCbCrInfoValidationTests.cpp b/src/dawn/tests/unittests/validation/YCbCrInfoValidationTests.cpp
index 8f4ad11..46b6a22 100644
--- a/src/dawn/tests/unittests/validation/YCbCrInfoValidationTests.cpp
+++ b/src/dawn/tests/unittests/validation/YCbCrInfoValidationTests.cpp
@@ -39,18 +39,19 @@
constexpr uint32_t kDefaultMipLevels = 1u;
constexpr uint32_t kDefaultLayerCount = 1u;
constexpr uint32_t kDefaultSampleCount = 1u;
-constexpr wgpu::TextureFormat kDefaultTextureFormat = wgpu::TextureFormat::RGBA8Unorm;
+constexpr wgpu::TextureFormat kDefaultTextureFormat = wgpu::TextureFormat::External;
-wgpu::Texture Create2DTexture(wgpu::Device& device) {
+wgpu::Texture Create2DTexture(wgpu::Device& device,
+ wgpu::TextureFormat format = kDefaultTextureFormat) {
wgpu::TextureDescriptor descriptor;
descriptor.dimension = wgpu::TextureDimension::e2D;
descriptor.size.width = kWidth;
descriptor.size.height = kHeight;
descriptor.size.depthOrArrayLayers = kDefaultLayerCount;
descriptor.sampleCount = kDefaultSampleCount;
- descriptor.format = kDefaultTextureFormat;
+ descriptor.format = format;
descriptor.mipLevelCount = kDefaultMipLevels;
- descriptor.usage = wgpu::TextureUsage::TextureBinding | wgpu::TextureUsage::RenderAttachment;
+ descriptor.usage = wgpu::TextureUsage::TextureBinding;
return device.CreateTexture(&descriptor);
}
@@ -84,10 +85,16 @@
ASSERT_DEVICE_ERROR(device.CreateSampler(&samplerDesc));
}
+// Tests that creating a texture with External format raises an error if the required feature is not
+// enabled.
+TEST_F(YCbCrInfoWithoutFeatureValidationTest, ExternalTextureNotSupported) {
+ ASSERT_DEVICE_ERROR(Create2DTexture(device));
+}
+
// Tests that creating a texture view with a valid ycbcr vulkan descriptor raises an error
// if the required feature is not enabled.
TEST_F(YCbCrInfoWithoutFeatureValidationTest, YCbCrTextureViewNotSupported) {
- wgpu::Texture texture = Create2DTexture(device);
+ wgpu::Texture texture = Create2DTexture(device, wgpu::TextureFormat::RGBA8Unorm);
wgpu::TextureViewDescriptor descriptor =
CreateDefaultViewDescriptor(wgpu::TextureViewDimension::e2D);
diff --git a/src/dawn/tests/white_box/SharedTextureMemoryTests_android.cpp b/src/dawn/tests/white_box/SharedTextureMemoryTests_android.cpp
index 17d3533..6e97075 100644
--- a/src/dawn/tests/white_box/SharedTextureMemoryTests_android.cpp
+++ b/src/dawn/tests/white_box/SharedTextureMemoryTests_android.cpp
@@ -52,7 +52,8 @@
std::vector<wgpu::FeatureName> RequiredFeatures(const wgpu::Adapter&) const override {
return {wgpu::FeatureName::SharedTextureMemoryAHardwareBuffer,
- wgpu::FeatureName::SharedFenceVkSemaphoreSyncFD};
+ wgpu::FeatureName::SharedFenceVkSemaphoreSyncFD,
+ wgpu::FeatureName::YCbCrVulkanSamplers};
}
static std::string MakeLabel(const AHardwareBuffer_Desc& desc) {
@@ -409,8 +410,8 @@
EXPECT_EQ(bufferFormatProperties.externalFormat, yCbCrInfo.externalFormat);
}
-// Test querying YCbCr info from the SharedTextureMemory.
-TEST_P(SharedTextureMemoryTests, QueryYCbCrInfo) {
+// Test querying YCbCr info from the SharedTextureMemory without external format.
+TEST_P(SharedTextureMemoryTests, QueryYCbCrInfoWithoutExternalFormat) {
AHardwareBuffer_Desc aHardwareBufferDesc = {
.width = 4,
.height = 4,
@@ -441,6 +442,7 @@
// AHB.
wgpu::SharedTextureMemoryAHardwareBufferDescriptor stmAHardwareBufferDesc;
stmAHardwareBufferDesc.handle = aHardwareBuffer;
+ stmAHardwareBufferDesc.useExternalFormat = false;
wgpu::SharedTextureMemoryDescriptor desc;
desc.nextInChain = &stmAHardwareBufferDesc;
@@ -478,6 +480,82 @@
formatFeatures &
VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_BIT,
yCbCrInfo.forceExplicitReconstruction);
+ uint64_t expectedExternalFormat = 0u;
+ EXPECT_EQ(expectedExternalFormat, yCbCrInfo.externalFormat);
+}
+
+// Test querying YCbCr info from the SharedTextureMemory with external format.
+TEST_P(SharedTextureMemoryTests, QueryYCbCrInfoWithExternalFormat) {
+ AHardwareBuffer_Desc aHardwareBufferDesc = {
+ .width = 4,
+ .height = 4,
+ .layers = 1,
+ .format = AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM,
+ .usage = AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE,
+ };
+ AHardwareBuffer* aHardwareBuffer;
+ EXPECT_EQ(AHardwareBuffer_allocate(&aHardwareBufferDesc, &aHardwareBuffer), 0);
+
+ // Query the YCbCr properties of the AHardwareBuffer.
+ auto deviceVk = native::vulkan::ToBackend(native::FromAPI(device.Get()));
+
+ VkAndroidHardwareBufferPropertiesANDROID bufferProperties = {
+ .sType = VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_PROPERTIES_ANDROID,
+ };
+
+ VkAndroidHardwareBufferFormatPropertiesANDROID bufferFormatProperties;
+ native::vulkan::PNextChainBuilder bufferPropertiesChain(&bufferProperties);
+ bufferPropertiesChain.Add(&bufferFormatProperties,
+ VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_FORMAT_PROPERTIES_ANDROID);
+
+ VkDevice vkDevice = deviceVk->GetVkDevice();
+ EXPECT_EQ(deviceVk->fn.GetAndroidHardwareBufferPropertiesANDROID(vkDevice, aHardwareBuffer,
+ &bufferProperties),
+ VK_SUCCESS);
+
+ // Query the YCbCr properties of a SharedTextureMemory created from this
+ // AHB.
+ wgpu::SharedTextureMemoryAHardwareBufferDescriptor stmAHardwareBufferDesc;
+ stmAHardwareBufferDesc.handle = aHardwareBuffer;
+ stmAHardwareBufferDesc.useExternalFormat = true;
+
+ wgpu::SharedTextureMemoryDescriptor desc;
+ desc.nextInChain = &stmAHardwareBufferDesc;
+
+ wgpu::SharedTextureMemory memory = device.ImportSharedTextureMemory(&desc);
+
+ wgpu::SharedTextureMemoryProperties properties;
+ wgpu::SharedTextureMemoryAHardwareBufferProperties ahbProperties = {};
+ properties.nextInChain = &ahbProperties;
+ memory.GetProperties(&properties);
+ auto yCbCrInfo = ahbProperties.yCbCrInfo;
+ uint32_t formatFeatures = bufferFormatProperties.formatFeatures;
+
+ // Verify that the YCbCr properties match.
+ VkFormat expectedVkFormat = VK_FORMAT_UNDEFINED;
+ EXPECT_EQ(expectedVkFormat, yCbCrInfo.vkFormat);
+ EXPECT_EQ(bufferFormatProperties.suggestedYcbcrModel, yCbCrInfo.vkYCbCrModel);
+ EXPECT_EQ(bufferFormatProperties.suggestedYcbcrRange, yCbCrInfo.vkYCbCrRange);
+ EXPECT_EQ(bufferFormatProperties.samplerYcbcrConversionComponents.r,
+ yCbCrInfo.vkComponentSwizzleRed);
+ EXPECT_EQ(bufferFormatProperties.samplerYcbcrConversionComponents.g,
+ yCbCrInfo.vkComponentSwizzleGreen);
+ EXPECT_EQ(bufferFormatProperties.samplerYcbcrConversionComponents.b,
+ yCbCrInfo.vkComponentSwizzleBlue);
+ EXPECT_EQ(bufferFormatProperties.samplerYcbcrConversionComponents.a,
+ yCbCrInfo.vkComponentSwizzleAlpha);
+ EXPECT_EQ(bufferFormatProperties.suggestedXChromaOffset, yCbCrInfo.vkXChromaOffset);
+ EXPECT_EQ(bufferFormatProperties.suggestedYChromaOffset, yCbCrInfo.vkYChromaOffset);
+
+ wgpu::FilterMode expectedFilter =
+ (formatFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER_BIT)
+ ? wgpu::FilterMode::Linear
+ : wgpu::FilterMode::Nearest;
+ EXPECT_EQ(expectedFilter, yCbCrInfo.vkChromaFilter);
+ EXPECT_EQ(
+ formatFeatures &
+ VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_BIT,
+ yCbCrInfo.forceExplicitReconstruction);
EXPECT_EQ(bufferFormatProperties.externalFormat, yCbCrInfo.externalFormat);
}
diff --git a/src/dawn/utils/TextureUtils.cpp b/src/dawn/utils/TextureUtils.cpp
index f356afc..7036d32 100644
--- a/src/dawn/utils/TextureUtils.cpp
+++ b/src/dawn/utils/TextureUtils.cpp
@@ -527,6 +527,7 @@
case wgpu::TextureFormat::R10X6BG10X6Biplanar422Unorm:
case wgpu::TextureFormat::R10X6BG10X6Biplanar444Unorm:
case wgpu::TextureFormat::R8BG8A8Triplanar420Unorm:
+ case wgpu::TextureFormat::External:
case wgpu::TextureFormat::Undefined:
break;
@@ -656,6 +657,7 @@
case wgpu::TextureFormat::R10X6BG10X6Biplanar422Unorm:
case wgpu::TextureFormat::R10X6BG10X6Biplanar444Unorm:
case wgpu::TextureFormat::R8BG8A8Triplanar420Unorm:
+ case wgpu::TextureFormat::External:
case wgpu::TextureFormat::Undefined:
break;
@@ -785,6 +787,7 @@
case wgpu::TextureFormat::R10X6BG10X6Biplanar422Unorm:
case wgpu::TextureFormat::R10X6BG10X6Biplanar444Unorm:
case wgpu::TextureFormat::R8BG8A8Triplanar420Unorm:
+ case wgpu::TextureFormat::External:
case wgpu::TextureFormat::Undefined:
break;