16bool RequiresYCBCRConversion(vk::Format format) {
18 case vk::Format::eG8B8R83Plane420Unorm:
19 case vk::Format::eG8B8R82Plane420Unorm:
20 case vk::Format::eG8B8R83Plane422Unorm:
21 case vk::Format::eG8B8R82Plane422Unorm:
22 case vk::Format::eG8B8R83Plane444Unorm:
31using AHBProperties = vk::StructureChain<
33 vk::AndroidHardwareBufferPropertiesANDROID,
35 vk::AndroidHardwareBufferFormatPropertiesANDROID>;
37vk::UniqueImage CreateVKImageWrapperForAndroidHarwareBuffer(
39 const AHBProperties& ahb_props,
40 const AHardwareBuffer_Desc& ahb_desc) {
41 const auto& ahb_format =
42 ahb_props.get<vk::AndroidHardwareBufferFormatPropertiesANDROID>();
44 vk::StructureChain<vk::ImageCreateInfo,
46 vk::ExternalMemoryImageCreateInfo,
48 vk::ExternalFormatANDROID>
51 auto& image_info = image_chain.get<vk::ImageCreateInfo>();
53 vk::ImageUsageFlags image_usage_flags;
54 if (ahb_desc.usage & AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE) {
55 image_usage_flags |= vk::ImageUsageFlagBits::eSampled;
57 if (ahb_desc.usage & AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER) {
58 image_usage_flags |= vk::ImageUsageFlagBits::eColorAttachment;
59 image_usage_flags |= vk::ImageUsageFlagBits::eInputAttachment;
62 vk::ImageCreateFlags image_create_flags;
63 if (ahb_desc.usage & AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT) {
64 image_create_flags |= vk::ImageCreateFlagBits::eProtected;
66 if (ahb_desc.usage & AHARDWAREBUFFER_USAGE_GPU_CUBE_MAP) {
67 image_create_flags |= vk::ImageCreateFlagBits::eCubeCompatible;
70 image_info.imageType = vk::ImageType::e2D;
71 image_info.format = ahb_format.format;
72 image_info.extent.width = ahb_desc.width;
73 image_info.extent.height = ahb_desc.height;
74 image_info.extent.depth = 1;
75 image_info.mipLevels =
76 (ahb_desc.usage & AHARDWAREBUFFER_USAGE_GPU_MIPMAP_COMPLETE)
77 ?
ISize{ahb_desc.
width, ahb_desc.height}.MipCount()
79 image_info.arrayLayers = ahb_desc.layers;
80 image_info.samples = vk::SampleCountFlagBits::e1;
81 image_info.tiling = vk::ImageTiling::eOptimal;
82 image_info.usage = image_usage_flags;
83 image_info.flags = image_create_flags;
84 image_info.sharingMode = vk::SharingMode::eExclusive;
85 image_info.initialLayout = vk::ImageLayout::eUndefined;
87 image_chain.get<vk::ExternalMemoryImageCreateInfo>().handleTypes =
88 vk::ExternalMemoryHandleTypeFlagBits::eAndroidHardwareBufferANDROID;
93 if (ahb_format.format == vk::Format::eUndefined) {
94 image_chain.get<vk::ExternalFormatANDROID>().externalFormat =
95 ahb_format.externalFormat;
97 image_chain.unlink<vk::ExternalFormatANDROID>();
100 auto image =
device.createImageUnique(image_chain.get());
101 if (
image.result != vk::Result::eSuccess) {
103 << vk::to_string(
image.result);
107 return std::move(
image.value);
110vk::UniqueDeviceMemory ImportVKDeviceMemoryFromAndroidHarwareBuffer(
113 const vk::Image&
image,
114 struct AHardwareBuffer* hardware_buffer,
115 const AHBProperties& ahb_props) {
116 vk::PhysicalDeviceMemoryProperties memory_properties;
119 ahb_props.get().memoryTypeBits, memory_properties);
120 if (memory_type_index < 0) {
121 VALIDATION_LOG <<
"Could not find memory type of external image.";
125 vk::StructureChain<vk::MemoryAllocateInfo,
127 vk::MemoryDedicatedAllocateInfo,
129 vk::ImportAndroidHardwareBufferInfoANDROID>
132 auto& mem_alloc_info = memory_chain.get<vk::MemoryAllocateInfo>();
133 mem_alloc_info.allocationSize = ahb_props.get().allocationSize;
134 mem_alloc_info.memoryTypeIndex = memory_type_index;
136 auto& dedicated_alloc_info =
137 memory_chain.get<vk::MemoryDedicatedAllocateInfo>();
138 dedicated_alloc_info.image =
image;
140 auto& ahb_import_info =
141 memory_chain.get<vk::ImportAndroidHardwareBufferInfoANDROID>();
142 ahb_import_info.buffer = hardware_buffer;
144 auto device_memory =
device.allocateMemoryUnique(memory_chain.get());
145 if (device_memory.result != vk::Result::eSuccess) {
146 VALIDATION_LOG <<
"Could not allocate device memory for external image : "
147 << vk::to_string(device_memory.result);
151 return std::move(device_memory.value);
154std::shared_ptr<YUVConversionVK> CreateYUVConversion(
155 const ContextVK& context,
156 const AHBProperties& ahb_props) {
159 const auto& ahb_format =
160 ahb_props.get<vk::AndroidHardwareBufferFormatPropertiesANDROID>();
164 const bool supports_linear_filtering =
165 !!(ahb_format.formatFeatures &
166 vk::FormatFeatureFlagBits::eSampledImageYcbcrConversionLinearFilter) &&
167 !!(ahb_format.formatFeatures &
168 vk::FormatFeatureFlagBits::eSampledImageFilterLinear);
169 auto& conversion_info = conversion_chain.get();
171 conversion_info.format = ahb_format.format;
172 conversion_info.ycbcrModel = ahb_format.suggestedYcbcrModel;
173 conversion_info.ycbcrRange = ahb_format.suggestedYcbcrRange;
174 conversion_info.components = ahb_format.samplerYcbcrConversionComponents;
175 conversion_info.xChromaOffset = ahb_format.suggestedXChromaOffset;
176 conversion_info.yChromaOffset = ahb_format.suggestedYChromaOffset;
177 conversion_info.chromaFilter =
178 supports_linear_filtering ? vk::Filter::eLinear : vk::Filter::eNearest;
180 conversion_info.forceExplicitReconstruction =
false;
182 if (conversion_info.format == vk::Format::eUndefined) {
183 auto&
external_format = conversion_chain.get<vk::ExternalFormatANDROID>();
186 conversion_chain.unlink<vk::ExternalFormatANDROID>();
189 return context.GetYUVConversionLibrary()->GetConversion(conversion_chain);
192vk::UniqueImageView CreateVKImageView(
194 const vk::Image&
image,
195 const std::shared_ptr<YUVConversionVK>& yuv_conversion_wrapper,
196 const AHBProperties& ahb_props,
197 const AHardwareBuffer_Desc& ahb_desc) {
198 const auto& ahb_format =
199 ahb_props.get<vk::AndroidHardwareBufferFormatPropertiesANDROID>();
201 vk::StructureChain<vk::ImageViewCreateInfo,
203 vk::SamplerYcbcrConversionInfo>
206 auto& view_info = view_chain.get();
208 view_info.image =
image;
209 view_info.viewType = vk::ImageViewType::e2D;
210 view_info.
format = ahb_format.format;
211 view_info.subresourceRange.aspectMask = vk::ImageAspectFlagBits::eColor;
212 view_info.subresourceRange.baseMipLevel = 0u;
213 view_info.subresourceRange.baseArrayLayer = 0u;
214 view_info.subresourceRange.levelCount =
215 (ahb_desc.usage & AHARDWAREBUFFER_USAGE_GPU_MIPMAP_COMPLETE)
216 ?
ISize{ahb_desc.
width, ahb_desc.height}.MipCount()
218 view_info.subresourceRange.layerCount = ahb_desc.layers;
221 if (view_info.format == vk::Format::eUndefined ||
222 RequiresYCBCRConversion(view_info.format)) {
223 view_chain.get<vk::SamplerYcbcrConversionInfo>().conversion =
224 yuv_conversion_wrapper->GetConversion();
226 view_chain.unlink<vk::SamplerYcbcrConversionInfo>();
229 auto image_view =
device.createImageViewUnique(view_info);
230 if (image_view.result != vk::Result::eSuccess) {
232 << vk::to_string(image_view.result);
236 return std::move(image_view.value);
241 case AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM:
243 case AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT:
245 case AHARDWAREBUFFER_FORMAT_D24_UNORM_S8_UINT:
247 case AHARDWAREBUFFER_FORMAT_D32_FLOAT_S8_UINT:
249 case AHARDWAREBUFFER_FORMAT_S8_UINT:
251 case AHARDWAREBUFFER_FORMAT_R8_UNORM:
253 case AHARDWAREBUFFER_FORMAT_R10G10B10A10_UNORM:
254 case AHARDWAREBUFFER_FORMAT_R16G16_UINT:
255 case AHARDWAREBUFFER_FORMAT_D32_FLOAT:
256 case AHARDWAREBUFFER_FORMAT_R16_UINT:
257 case AHARDWAREBUFFER_FORMAT_D24_UNORM:
258 case AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_420:
259 case AHARDWAREBUFFER_FORMAT_YCbCr_P010:
260 case AHARDWAREBUFFER_FORMAT_BLOB:
261 case AHARDWAREBUFFER_FORMAT_R10G10B10A2_UNORM:
262 case AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM:
263 case AHARDWAREBUFFER_FORMAT_R8G8B8_UNORM:
264 case AHARDWAREBUFFER_FORMAT_D16_UNORM:
265 case AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM:
266 case AHARDWAREBUFFER_FORMAT_YCbCr_P210:
275 if (ahb_desc.layers == 1u) {
278 if (ahb_desc.layers % 6u == 0 &&
279 (ahb_desc.usage & AHARDWAREBUFFER_USAGE_GPU_CUBE_MAP)) {
287TextureDescriptor ToTextureDescriptor(
const AHardwareBuffer_Desc& ahb_desc) {
288 const auto ahb_size =
ISize{ahb_desc.
width, ahb_desc.height};
289 TextureDescriptor desc;
294 ToPixelFormat(
static_cast<AHardwareBuffer_Format
>(ahb_desc.format));
295 desc.size = ahb_size;
299 desc.mip_count = (ahb_desc.usage & AHARDWAREBUFFER_USAGE_GPU_MIPMAP_COMPLETE)
300 ? ahb_size.MipCount()
302 if (ahb_desc.usage & AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER) {
310 const std::shared_ptr<Context>& p_context,
311 struct AHardwareBuffer* ahb,
312 const AHardwareBuffer_Desc& ahb_desc)
319 const auto&
device = context.GetDevice();
322 AHBProperties ahb_props;
324 if (
device.getAndroidHardwareBufferPropertiesANDROID(ahb, &ahb_props.get()) !=
325 vk::Result::eSuccess) {
326 VALIDATION_LOG <<
"Could not determine properties of the Android hardware "
331 const auto& ahb_format =
332 ahb_props.get<vk::AndroidHardwareBufferFormatPropertiesANDROID>();
336 CreateVKImageWrapperForAndroidHarwareBuffer(
device, ahb_props, ahb_desc);
342 auto device_memory = ImportVKDeviceMemoryFromAndroidHarwareBuffer(
344 if (!device_memory) {
349 if (
auto result =
device.bindImageMemory(
image.get(), device_memory.get(), 0);
350 result != vk::Result::eSuccess) {
351 VALIDATION_LOG <<
"Could not bind external device memory to image : "
352 << vk::to_string(result);
357 needs_yuv_conversion_ = ahb_format.format == vk::Format::eUndefined ||
358 RequiresYCBCRConversion(ahb_format.format);
359 std::shared_ptr<YUVConversionVK> yuv_conversion;
360 if (needs_yuv_conversion_) {
361 yuv_conversion = CreateYUVConversion(context, ahb_props);
362 if (!yuv_conversion || !yuv_conversion->IsValid()) {
368 auto image_view = CreateVKImageView(
device,
378 device_memory_ = std::move(device_memory);
379 image_ = std::move(
image);
380 yuv_conversion_ = std::move(yuv_conversion);
381 image_view_ = std::move(image_view);
384 context.SetDebugName(device_memory_.get(),
"AHB Device Memory");
385 context.SetDebugName(image_.get(),
"AHB Image");
386 if (yuv_conversion_) {
387 context.SetDebugName(yuv_conversion_->GetConversion(),
388 "AHB YUV Conversion");
390 context.SetDebugName(image_view_.get(),
"AHB ImageView");
397 const std::shared_ptr<Context>& context,
398 std::unique_ptr<android::HardwareBuffer> backing_store,
399 bool is_swapchain_image)
401 backing_store->GetHandle(),
402 backing_store->GetAndroidDescriptor()) {
403 backing_store_ = std::move(backing_store);
404 is_swapchain_image_ = is_swapchain_image;
421 return image_view_.get();
426 return image_view_.get();
431 return is_swapchain_image_;
436 return needs_yuv_conversion_ ? yuv_conversion_ :
nullptr;
440 return backing_store_.get();
A texture source that wraps an instance of AHardwareBuffer.
bool IsSwapchainImage() const override
Determines if swapchain image. That is, an image used as the root render target.
vk::Image GetImage() const override
Get the image handle for this texture source.
const android::HardwareBuffer * GetBackingStore() const
std::shared_ptr< YUVConversionVK > GetYUVConversion() const override
When sampling from textures whose formats are not known to Vulkan, a custom conversion is necessary t...
AHBTextureSourceVK(const std::shared_ptr< Context > &context, struct AHardwareBuffer *hardware_buffer, const AHardwareBuffer_Desc &hardware_buffer_desc)
~AHBTextureSourceVK() override
vk::ImageView GetImageView() const override
Retrieve the image view used for sampling/blitting/compute with this texture source.
vk::ImageView GetRenderTargetView() const override
Retrieve the image view used for render target attachments with this texture source.
static int32_t FindMemoryTypeIndex(uint32_t memory_type_bits_requirement, vk::PhysicalDeviceMemoryProperties &memory_properties)
Select a matching memory type for the given [memory_type_bits_requirement], or -1 if none is found.
static ContextVK & Cast(Context &base)
Abstract base class that represents a vkImage and an vkImageView.
A wrapper for AHardwareBuffer https://developer.android.com/ndk/reference/group/a-hardware-buffer.
FlutterVulkanImage * image
VkPhysicalDevice physical_device
constexpr PixelFormat ToPixelFormat(vk::Format format)
PixelFormat
The Pixel formats supported by Impeller. The naming convention denotes the usage of the component,...
constexpr GLenum ToTextureType(TextureType type)
vk::StructureChain< vk::SamplerYcbcrConversionCreateInfo > YUVConversionDescriptorVK
uint32_t format
The VkFormat of the image (for example: VK_FORMAT_R8G8B8A8_UNORM).