[Vulkan] Populate YCbCr info in SharedTextureMemory::GetProperties()
This CL populates YCbCr info when it is passed into
SharedTextureMemory::GetProperties() on Android/Vulkan. The populated
information comes from the AHB backing the SharedTextureMemory. We also
add a test verifying that the populated info matches that of the AHB
backing the STM instance, as well as validation that the passed-in
YCbCr info does not have anything chained onto it.
Bug: dawn:2476
Change-Id: Ie9536d42d59bc4e1a49d4bc3b4cf98464c89bd33
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/188240
Reviewed-by: Austin Eng <enga@chromium.org>
Commit-Queue: Colin Blundell <blundell@chromium.org>
diff --git a/docs/dawn/features/y_cb_cr_vulkan_samplers.md b/docs/dawn/features/y_cb_cr_vulkan_samplers.md
index d18d3b1..6234d5c 100644
--- a/docs/dawn/features/y_cb_cr_vulkan_samplers.md
+++ b/docs/dawn/features/y_cb_cr_vulkan_samplers.md
@@ -5,11 +5,16 @@
can supply `YCbCrVkDescriptor` instances when creating samplers and
texture views. Clients can also obtain the YCbCr info for a
SharedTextureMemory instance that was created from an AHardwareBuffer by
-querying its properties. When obtaining this info, note that some of the
-info *must* be populated while other info *may* be populated, corresponding
-to which fields of the underlying `VkSamplerYcbcrConversionCreateInfo` are
-mandatory vs. optional.
+querying its properties. Most properties will be created directly from the
+corresponding buffer format properties on the underlying AHardwareBuffer. The
+two exceptions are as follows:
+* `vkChromaFilter`: Will be set to VK_FILTER_LINEAR iff
+ `VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER_BIT` is
+ present in the AHB format features and VK_FILTER_NEAREST otherwise
+* `forceExplicitReconstruction`: will be set to true iff
+ `VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_BIT`
+ is present in the AHB format features
TODO(crbug.com/dawn/2476): Expand this documentation with examples and
description of semantics (including constraints/validations) as we build out
support
diff --git a/src/dawn/native/SharedTextureMemory.cpp b/src/dawn/native/SharedTextureMemory.cpp
index 3c715bd..f37a65b 100644
--- a/src/dawn/native/SharedTextureMemory.cpp
+++ b/src/dawn/native/SharedTextureMemory.cpp
@@ -128,6 +128,8 @@
this, ToAPI(Feature::SharedTextureMemoryAHardwareBuffer));
}
+ DAWN_TRY(GetChainedProperties(unpacked));
+
return {};
}
diff --git a/src/dawn/native/SharedTextureMemory.h b/src/dawn/native/SharedTextureMemory.h
index 0455e01..1fb8b14 100644
--- a/src/dawn/native/SharedTextureMemory.h
+++ b/src/dawn/native/SharedTextureMemory.h
@@ -75,6 +75,11 @@
virtual ResultOrError<Ref<TextureBase>> CreateTextureImpl(
const UnpackedPtr<TextureDescriptor>& descriptor) = 0;
+ virtual MaybeError GetChainedProperties(
+ UnpackedPtr<SharedTextureMemoryProperties>& properties) const {
+ return {};
+ }
+
SharedTextureMemoryProperties mProperties;
};
diff --git a/src/dawn/native/vulkan/SharedTextureMemoryVk.cpp b/src/dawn/native/vulkan/SharedTextureMemoryVk.cpp
index fb817c8..5a592c0 100644
--- a/src/dawn/native/vulkan/SharedTextureMemoryVk.cpp
+++ b/src/dawn/native/vulkan/SharedTextureMemoryVk.cpp
@@ -511,6 +511,7 @@
}
VkFormat vkFormat;
+ YCbCrVkDescriptor yCbCrAHBInfo;
VkAndroidHardwareBufferPropertiesANDROID bufferProperties = {
.sType = VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_PROPERTIES_ANDROID,
};
@@ -529,13 +530,30 @@
vkFormat = bufferFormatProperties.format;
- // TODO(dawn:1745): Support external formats.
- // https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#memory-external-android-hardware-buffer-external-formats
- DAWN_INVALID_IF(vkFormat == VK_FORMAT_UNDEFINED,
- "AHardwareBuffer did not have a supported format. External format (%u) "
- "requires YCbCr conversion and is "
- "not supported yet.",
- bufferFormatProperties.externalFormat);
+ // Populate the YCbCr info.
+ yCbCrAHBInfo.externalFormat = bufferFormatProperties.externalFormat;
+ yCbCrAHBInfo.vkFormat = bufferFormatProperties.format;
+ yCbCrAHBInfo.vkYCbCrModel = bufferFormatProperties.suggestedYcbcrModel;
+ yCbCrAHBInfo.vkYCbCrRange = bufferFormatProperties.suggestedYcbcrRange;
+ yCbCrAHBInfo.vkComponentSwizzleRed =
+ bufferFormatProperties.samplerYcbcrConversionComponents.r;
+ yCbCrAHBInfo.vkComponentSwizzleGreen =
+ bufferFormatProperties.samplerYcbcrConversionComponents.g;
+ yCbCrAHBInfo.vkComponentSwizzleBlue =
+ bufferFormatProperties.samplerYcbcrConversionComponents.b;
+ yCbCrAHBInfo.vkComponentSwizzleAlpha =
+ bufferFormatProperties.samplerYcbcrConversionComponents.a;
+ yCbCrAHBInfo.vkXChromaOffset = bufferFormatProperties.suggestedXChromaOffset;
+ yCbCrAHBInfo.vkYChromaOffset = bufferFormatProperties.suggestedYChromaOffset;
+
+ uint32_t formatFeatures = bufferFormatProperties.formatFeatures;
+ yCbCrAHBInfo.vkChromaFilter =
+ (formatFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER_BIT)
+ ? VK_FILTER_LINEAR
+ : VK_FILTER_NEAREST;
+ yCbCrAHBInfo.forceExplicitReconstruction =
+ formatFeatures &
+ VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_BIT;
}
DAWN_TRY_ASSIGN(properties.format, FormatFromVkFormat(device, vkFormat));
@@ -549,6 +567,8 @@
Ref<SharedTextureMemory> sharedTextureMemory =
SharedTextureMemory::Create(device, label, properties, VK_QUEUE_FAMILY_FOREIGN_EXT);
+ sharedTextureMemory->mYCbCrAHBInfo = yCbCrAHBInfo;
+
// Reflect properties to reify them.
sharedTextureMemory->APIGetProperties(&properties);
@@ -1050,4 +1070,23 @@
#endif // DAWN_PLATFORM_IS(FUCHSIA) || DAWN_PLATFORM_IS(LINUX)
+MaybeError SharedTextureMemory::GetChainedProperties(
+ UnpackedPtr<SharedTextureMemoryProperties>& properties) const {
+ auto ahbProperties = properties.Get<SharedTextureMemoryAHardwareBufferProperties>();
+
+ if (!ahbProperties) {
+ return {};
+ }
+
+ if (ahbProperties->yCbCrInfo.nextInChain) {
+ return DAWN_VALIDATION_ERROR(
+ "yCBCrInfo field of SharedTextureMemoryAHardwareBufferProperties has a chained "
+ "struct.");
+ }
+
+ ahbProperties->yCbCrInfo = mYCbCrAHBInfo;
+
+ return {};
+}
+
} // namespace dawn::native::vulkan
diff --git a/src/dawn/native/vulkan/SharedTextureMemoryVk.h b/src/dawn/native/vulkan/SharedTextureMemoryVk.h
index 5912f6e..c9e35cf 100644
--- a/src/dawn/native/vulkan/SharedTextureMemoryVk.h
+++ b/src/dawn/native/vulkan/SharedTextureMemoryVk.h
@@ -78,9 +78,15 @@
ExecutionSerial lastUsageSerial,
UnpackedPtr<EndAccessState>& state) override;
+ MaybeError GetChainedProperties(
+ UnpackedPtr<SharedTextureMemoryProperties>& properties) const override;
+
Ref<RefCountedVkHandle<VkImage>> mVkImage;
Ref<RefCountedVkHandle<VkDeviceMemory>> mVkDeviceMemory;
const uint32_t mQueueFamilyIndex;
+
+ // Populated if this instance was created from an AHardwareBuffer.
+ YCbCrVkDescriptor mYCbCrAHBInfo;
};
} // namespace dawn::native::vulkan
diff --git a/src/dawn/tests/white_box/SharedTextureMemoryTests_android.cpp b/src/dawn/tests/white_box/SharedTextureMemoryTests_android.cpp
index 6cbe0c4..3a122e0 100644
--- a/src/dawn/tests/white_box/SharedTextureMemoryTests_android.cpp
+++ b/src/dawn/tests/white_box/SharedTextureMemoryTests_android.cpp
@@ -26,12 +26,14 @@
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <android/hardware_buffer.h>
-#include <vulkan/vulkan.h>
#include <memory>
#include <string>
#include <utility>
#include <vector>
+#include "dawn/native/vulkan/DeviceVk.h"
+#include "dawn/native/vulkan/UtilsVulkan.h"
+#include "dawn/native/vulkan/VulkanError.h"
#include "dawn/tests/white_box/SharedTextureMemoryTests.h"
#include "dawn/utils/WGPUHelpers.h"
#include "dawn/webgpu_cpp.h"
@@ -314,6 +316,110 @@
{aHardwareBufferDesc.width, aHardwareBufferDesc.height});
}
+// Test validation of an incorrectly-configured SharedTextureMemoryAHardwareBufferProperties
+// instance.
+TEST_P(SharedTextureMemoryTests, InvalidSharedTextureMemoryAHardwareBufferProperties) {
+ AHardwareBuffer_Desc aHardwareBufferDesc = {
+ .width = 4,
+ .height = 4,
+ .layers = 1,
+ .format = AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM,
+ };
+ AHardwareBuffer* aHardwareBuffer;
+ EXPECT_EQ(AHardwareBuffer_allocate(&aHardwareBufferDesc, &aHardwareBuffer), 0);
+
+ wgpu::SharedTextureMemoryAHardwareBufferDescriptor stmAHardwareBufferDesc;
+ stmAHardwareBufferDesc.handle = aHardwareBuffer;
+
+ wgpu::SharedTextureMemoryDescriptor desc;
+ desc.nextInChain = &stmAHardwareBufferDesc;
+
+ wgpu::SharedTextureMemory memory = device.ImportSharedTextureMemory(&desc);
+
+ wgpu::SharedTextureMemoryProperties properties;
+ wgpu::SharedTextureMemoryAHardwareBufferProperties ahbProperties = {};
+ wgpu::YCbCrVkDescriptor yCbCrDesc;
+
+ // Chaining anything onto the passed-in YCbCrVkDescriptor is invalid.
+ yCbCrDesc.nextInChain = &stmAHardwareBufferDesc;
+ ahbProperties.yCbCrInfo = yCbCrDesc;
+ properties.nextInChain = &ahbProperties;
+
+ ASSERT_DEVICE_ERROR(memory.GetProperties(&properties));
+}
+
+// Test querying YCbCr info from the SharedTextureMemory.
+TEST_P(SharedTextureMemoryTests, QueryYCbCrInfo) {
+ AHardwareBuffer_Desc aHardwareBufferDesc = {
+ .width = 4,
+ .height = 4,
+ .layers = 1,
+ .format = AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM,
+ };
+ 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;
+
+ 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.
+ EXPECT_EQ(bufferFormatProperties.format, 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);
+
+ uint32_t expectedFilter =
+ (formatFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER_BIT)
+ ? VK_FILTER_LINEAR
+ : VK_FILTER_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);
+}
+
DAWN_INSTANTIATE_PREFIXED_TEST_P(Vulkan,
SharedTextureMemoryNoFeatureTests,
{VulkanBackend()},