1 //
2 // Copyright 2019 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 
7 // HardwareBufferImageSiblingVkAndroid.cpp: Implements HardwareBufferImageSiblingVkAndroid.
8 
9 #include "libANGLE/renderer/vulkan/android/HardwareBufferImageSiblingVkAndroid.h"
10 
11 #include "common/android_util.h"
12 
13 #include "libANGLE/Display.h"
14 #include "libANGLE/renderer/vulkan/DisplayVk.h"
15 #include "libANGLE/renderer/vulkan/android/AHBFunctions.h"
16 #include "libANGLE/renderer/vulkan/android/DisplayVkAndroid.h"
17 #include "libANGLE/renderer/vulkan/vk_renderer.h"
18 
19 namespace rx
20 {
21 
22 namespace
23 {
AhbDescUsageToVkImageTiling(const AHardwareBuffer_Desc & ahbDescription)24 VkImageTiling AhbDescUsageToVkImageTiling(const AHardwareBuffer_Desc &ahbDescription)
25 {
26     // A note about the choice of OPTIMAL here.
27 
28     // When running Android on certain GPUs, there are problems creating Vulkan
29     // image siblings of AHardwareBuffers because it's currently assumed that
30     // the underlying driver can create linear tiling images that have input
31     // attachment usage, which isn't supported on NVIDIA for example, resulting
32     // in failure to create the image siblings. Yet, we don't currently take
33     // advantage of linear elsewhere in ANGLE. To maintain maximum
34     // compatibility on Android for such drivers, use optimal tiling for image
35     // siblings.
36     //
37     // Note that while we have switched to optimal unconditionally in this path
38     // versus linear, it's possible that previously compatible linear usages
39     // might become uncompatible after switching to optimal. However, from what
40     // we've seen on Samsung/NVIDIA/Intel/AMD GPUs so far, formats generally
41     // have more possible usages in optimal tiling versus linear tiling:
42     //
43     // http://vulkan.gpuinfo.org/displayreport.php?id=10804#formats_linear
44     // http://vulkan.gpuinfo.org/displayreport.php?id=10804#formats_optimal
45     //
46     // http://vulkan.gpuinfo.org/displayreport.php?id=10807#formats_linear
47     // http://vulkan.gpuinfo.org/displayreport.php?id=10807#formats_optimal
48     //
49     // http://vulkan.gpuinfo.org/displayreport.php?id=10809#formats_linear
50     // http://vulkan.gpuinfo.org/displayreport.php?id=10809#formats_optimal
51     //
52     // http://vulkan.gpuinfo.org/displayreport.php?id=10787#formats_linear
53     // http://vulkan.gpuinfo.org/displayreport.php?id=10787#formats_optimal
54     //
55     // Also, as an aside, in terms of what's generally expected from the Vulkan
56     // ICD in Android when determining AHB compatibility, if the vendor wants
57     // to declare a particular combination of format/tiling/usage/etc as not
58     // supported AHB-wise, it's up to the ICD vendor to zero out bits in
59     // supportedHandleTypes in the vkGetPhysicalDeviceImageFormatProperties2
60     // query:
61     //
62     // ``` *
63     // [VUID-VkImageCreateInfo-pNext-00990](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/html/vkspec.html#VUID-VkImageCreateInfo-pNext-00990)
64     // If the pNext chain includes a VkExternalMemoryImageCreateInfo structure,
65     // its handleTypes member must only contain bits that are also in
66     // VkExternalImageFormatProperties::externalMemoryProperties.compatibleHandleTypes,
67     // as returned by vkGetPhysicalDeviceImageFormatProperties2 with format,
68     // imageType, tiling, usage, and flags equal to those in this structure,
69     // and with a VkPhysicalDeviceExternalImageFormatInfo structure included in
70     // the pNext chain, with a handleType equal to any one of the handle types
71     // specified in VkExternalMemoryImageCreateInfo::handleTypes ```
72 
73     return VK_IMAGE_TILING_OPTIMAL;
74 }
75 
76 // Map AHB usage flags to VkImageUsageFlags using this table from the Vulkan spec
77 // https://www.khronos.org/registry/vulkan/specs/1.2-extensions/html/chap11.html#memory-external-android-hardware-buffer-usage
AhbDescUsageToVkImageUsage(const AHardwareBuffer_Desc & ahbDescription,bool isDepthOrStencilFormat)78 VkImageUsageFlags AhbDescUsageToVkImageUsage(const AHardwareBuffer_Desc &ahbDescription,
79                                              bool isDepthOrStencilFormat)
80 {
81     VkImageUsageFlags usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
82 
83     if ((ahbDescription.usage & AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE) != 0)
84     {
85         usage |= VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
86     }
87 
88     if ((ahbDescription.usage & AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER) != 0)
89     {
90         if (isDepthOrStencilFormat)
91         {
92             usage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
93         }
94         else
95         {
96             usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
97         }
98     }
99 
100     return usage;
101 }
102 
103 // Map AHB usage flags to VkImageCreateFlags using this table from the Vulkan spec
104 // https://www.khronos.org/registry/vulkan/specs/1.2-extensions/html/chap11.html#memory-external-android-hardware-buffer-usage
AhbDescUsageToVkImageCreateFlags(const AHardwareBuffer_Desc & ahbDescription)105 VkImageCreateFlags AhbDescUsageToVkImageCreateFlags(const AHardwareBuffer_Desc &ahbDescription)
106 {
107     VkImageCreateFlags imageCreateFlags = vk::kVkImageCreateFlagsNone;
108 
109     if ((ahbDescription.usage & AHARDWAREBUFFER_USAGE_GPU_CUBE_MAP) != 0)
110     {
111         imageCreateFlags |= VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT;
112     }
113 
114     if ((ahbDescription.usage & AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT) != 0)
115     {
116         imageCreateFlags |= VK_IMAGE_CREATE_PROTECTED_BIT;
117     }
118 
119     return imageCreateFlags;
120 }
121 
122 // Deduce texture type based on AHB usage flags and layer count
AhbDescUsageToTextureType(const AHardwareBuffer_Desc & ahbDescription,const uint32_t layerCount)123 gl::TextureType AhbDescUsageToTextureType(const AHardwareBuffer_Desc &ahbDescription,
124                                           const uint32_t layerCount)
125 {
126     gl::TextureType textureType = layerCount > 1 ? gl::TextureType::_2DArray : gl::TextureType::_2D;
127     if ((ahbDescription.usage & AHARDWAREBUFFER_USAGE_GPU_CUBE_MAP) != 0)
128     {
129         textureType = layerCount > gl::kCubeFaceCount ? gl::TextureType::CubeMapArray
130                                                       : gl::TextureType::CubeMap;
131     }
132     return textureType;
133 }
134 // TODO(anglebug.com/42266422): remove when NDK header is updated to contain FRONT_BUFFER usage flag
135 constexpr uint64_t kAHardwareBufferUsageFrontBuffer = (1ULL << 32);
136 }  // namespace
137 
HardwareBufferImageSiblingVkAndroid(EGLClientBuffer buffer)138 HardwareBufferImageSiblingVkAndroid::HardwareBufferImageSiblingVkAndroid(EGLClientBuffer buffer)
139     : mBuffer(buffer),
140       mFormat(GL_NONE),
141       mRenderable(false),
142       mTextureable(false),
143       mYUV(false),
144       mLevelCount(0),
145       mUsage(0),
146       mSamples(0),
147       mImage(nullptr)
148 {}
149 
~HardwareBufferImageSiblingVkAndroid()150 HardwareBufferImageSiblingVkAndroid::~HardwareBufferImageSiblingVkAndroid() {}
151 
152 // Static
ValidateHardwareBuffer(vk::Renderer * renderer,EGLClientBuffer buffer,const egl::AttributeMap & attribs)153 egl::Error HardwareBufferImageSiblingVkAndroid::ValidateHardwareBuffer(
154     vk::Renderer *renderer,
155     EGLClientBuffer buffer,
156     const egl::AttributeMap &attribs)
157 {
158     struct ANativeWindowBuffer *windowBuffer =
159         angle::android::ClientBufferToANativeWindowBuffer(buffer);
160     struct AHardwareBuffer *hardwareBuffer = nullptr;
161     if (windowBuffer != nullptr)
162     {
163         hardwareBuffer = angle::android::ANativeWindowBufferToAHardwareBuffer(windowBuffer);
164         if (hardwareBuffer == nullptr)
165         {
166             return egl::EglBadParameter()
167                    << "Failed to obtain hardware buffer through given window buffer.";
168         }
169     }
170     else
171     {
172         return egl::EglBadParameter()
173                << "Failed to obtain Window buffer through given client buffer handler.";
174     }
175 
176     VkAndroidHardwareBufferFormatPropertiesANDROID bufferFormatProperties = {};
177     bufferFormatProperties.sType =
178         VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_FORMAT_PROPERTIES_ANDROID;
179     bufferFormatProperties.pNext = nullptr;
180 
181     VkAndroidHardwareBufferPropertiesANDROID bufferProperties = {};
182     bufferProperties.sType = VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_PROPERTIES_ANDROID;
183     bufferProperties.pNext = &bufferFormatProperties;
184 
185     VkDevice device = renderer->getDevice();
186     VkResult result =
187         vkGetAndroidHardwareBufferPropertiesANDROID(device, hardwareBuffer, &bufferProperties);
188     if (result != VK_SUCCESS)
189     {
190         return egl::EglBadParameter() << "Failed to query AHardwareBuffer properties";
191     }
192 
193     int width       = 0;
194     int height      = 0;
195     int depth       = 0;
196     int pixelFormat = 0;
197     uint64_t usage  = 0;
198     angle::android::GetANativeWindowBufferProperties(windowBuffer, &width, &height, &depth,
199                                                      &pixelFormat, &usage);
200 
201     if (bufferFormatProperties.format == VK_FORMAT_UNDEFINED)
202     {
203         ASSERT(bufferFormatProperties.externalFormat != 0);
204         // We must have an external format, check that it supports texture sampling
205         if (!(bufferFormatProperties.formatFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT))
206         {
207             return egl::EglBadParameter()
208                    << "Sampling from AHardwareBuffer externalFormat 0x" << std::hex
209                    << bufferFormatProperties.externalFormat << " is unsupported ";
210         }
211     }
212     else
213     {
214         angle::FormatID formatID = vk::GetFormatIDFromVkFormat(bufferFormatProperties.format);
215         const bool hasNecessaryFormatSupport =
216             (usage & AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER) != 0
217                 ? HasFullTextureFormatSupport(renderer, formatID)
218                 : HasNonRenderableTextureFormatSupport(renderer, formatID);
219         if (!hasNecessaryFormatSupport)
220         {
221             return egl::EglBadParameter()
222                    << "AHardwareBuffer format " << bufferFormatProperties.format
223                    << " does not support enough features to use as a texture.";
224         }
225     }
226 
227     if (attribs.getAsInt(EGL_PROTECTED_CONTENT_EXT, EGL_FALSE) == EGL_TRUE)
228     {
229         if ((usage & AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT) == 0)
230         {
231             return egl::EglBadAccess()
232                    << "EGL_PROTECTED_CONTENT_EXT attribute does not match protected state "
233                       "of EGLClientBuffer.";
234         }
235     }
236 
237     return egl::NoError();
238 }
239 
initialize(const egl::Display * display)240 egl::Error HardwareBufferImageSiblingVkAndroid::initialize(const egl::Display *display)
241 {
242     DisplayVk *displayVk = vk::GetImpl(display);
243     return angle::ToEGL(initImpl(displayVk), EGL_BAD_PARAMETER);
244 }
245 
initImpl(DisplayVk * displayVk)246 angle::Result HardwareBufferImageSiblingVkAndroid::initImpl(DisplayVk *displayVk)
247 {
248     const AHBFunctions &functions = static_cast<DisplayVkAndroid *>(displayVk)->getAHBFunctions();
249     ANGLE_VK_CHECK(displayVk, functions.valid(), VK_ERROR_INITIALIZATION_FAILED);
250 
251     vk::Renderer *renderer = displayVk->getRenderer();
252 
253     struct ANativeWindowBuffer *windowBuffer =
254         angle::android::ClientBufferToANativeWindowBuffer(mBuffer);
255 
256     int pixelFormat = 0;
257     angle::android::GetANativeWindowBufferProperties(windowBuffer, &mSize.width, &mSize.height,
258                                                      &mSize.depth, &pixelFormat, &mUsage);
259 
260     struct AHardwareBuffer *hardwareBuffer =
261         angle::android::ANativeWindowBufferToAHardwareBuffer(windowBuffer);
262 
263     functions.acquire(hardwareBuffer);
264 
265     VkAndroidHardwareBufferPropertiesANDROID bufferProperties = {};
266     bufferProperties.sType = VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_PROPERTIES_ANDROID;
267     bufferProperties.pNext = nullptr;
268 
269     VkAndroidHardwareBufferFormatPropertiesANDROID bufferFormatProperties;
270     bufferFormatProperties.sType =
271         VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_FORMAT_PROPERTIES_ANDROID;
272     bufferFormatProperties.pNext = nullptr;
273     vk::AddToPNextChain(&bufferProperties, &bufferFormatProperties);
274 
275     VkAndroidHardwareBufferFormatResolvePropertiesANDROID bufferFormatResolveProperties = {};
276     if (renderer->getFeatures().supportsExternalFormatResolve.enabled)
277     {
278         bufferFormatResolveProperties.sType =
279             VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_FORMAT_RESOLVE_PROPERTIES_ANDROID;
280         bufferFormatResolveProperties.pNext = nullptr;
281         vk::AddToPNextChain(&bufferFormatProperties, &bufferFormatResolveProperties);
282     }
283 
284     VkDevice device = renderer->getDevice();
285     ANGLE_VK_TRY(displayVk, vkGetAndroidHardwareBufferPropertiesANDROID(device, hardwareBuffer,
286                                                                         &bufferProperties));
287 
288     const bool isExternal = bufferFormatProperties.format == VK_FORMAT_UNDEFINED;
289 
290     VkExternalFormatANDROID externalFormat = {};
291     externalFormat.sType                   = VK_STRUCTURE_TYPE_EXTERNAL_FORMAT_ANDROID;
292     externalFormat.externalFormat          = 0;
293 
294     // Use bufferFormatProperties.format directly when possible.  For RGBX, the spec requires the
295     // corresponding format to be RGB, which is not _technically_ correct.  The Vulkan backend uses
296     // the RGBX8_ANGLE format, so that's overriden.
297     //
298     // Where bufferFormatProperties.format returns UNDEFINED, NativePixelFormatToGLInternalFormat is
299     // used to infer the format.
300     const vk::Format *vkFormat = nullptr;
301     if (pixelFormat == AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM)
302     {
303         vkFormat = &renderer->getFormat(GL_RGBX8_ANGLE);
304     }
305     else if (!isExternal)
306     {
307         vkFormat = &renderer->getFormat(vk::GetFormatIDFromVkFormat(bufferFormatProperties.format));
308     }
309     else
310     {
311         vkFormat =
312             &renderer->getFormat(angle::android::NativePixelFormatToGLInternalFormat(pixelFormat));
313     }
314 
315     const angle::Format &imageFormat = vkFormat->getActualRenderableImageFormat();
316     bool isDepthOrStencilFormat      = imageFormat.hasDepthOrStencilBits();
317     mFormat                          = gl::Format(vkFormat->getIntendedGLFormat());
318 
319     bool externalRenderTargetSupported =
320         renderer->getFeatures().supportsExternalFormatResolve.enabled &&
321         bufferFormatResolveProperties.colorAttachmentFormat != VK_FORMAT_UNDEFINED;
322     // Can assume based on us getting here already. The supportsYUVSamplerConversion
323     // check below should serve as a backup otherwise.
324     bool externalTexturingSupported = true;
325 
326     // Query AHB description and do the following -
327     // 1. Derive VkImageTiling mode based on AHB usage flags
328     // 2. Map AHB usage flags to VkImageUsageFlags
329     AHardwareBuffer_Desc ahbDescription;
330     functions.describe(hardwareBuffer, &ahbDescription);
331     VkImageTiling imageTilingMode = AhbDescUsageToVkImageTiling(ahbDescription);
332     VkImageUsageFlags usage = AhbDescUsageToVkImageUsage(ahbDescription, isDepthOrStencilFormat);
333 
334     if (isExternal)
335     {
336         ANGLE_VK_CHECK(displayVk, bufferFormatProperties.externalFormat != 0, VK_ERROR_UNKNOWN);
337         externalFormat.externalFormat = bufferFormatProperties.externalFormat;
338 
339         // VkImageCreateInfo struct: If the pNext chain includes a VkExternalFormatANDROID structure
340         // whose externalFormat member is not 0, usage must not include any usages except
341         // VK_IMAGE_USAGE_SAMPLED_BIT
342         if (externalFormat.externalFormat != 0 && !externalRenderTargetSupported)
343         {
344             // Clear all other bits except sampled
345             usage &= VK_IMAGE_USAGE_SAMPLED_BIT;
346         }
347 
348         // If the pNext chain includes a VkExternalFormatANDROID structure whose externalFormat
349         // member is not 0, tiling must be VK_IMAGE_TILING_OPTIMAL
350         imageTilingMode = VK_IMAGE_TILING_OPTIMAL;
351     }
352 
353     // If forceSampleUsageForAhbBackedImages feature is enabled force enable
354     // VK_IMAGE_USAGE_SAMPLED_BIT
355     if (renderer->getFeatures().forceSampleUsageForAhbBackedImages.enabled)
356     {
357         usage |= VK_IMAGE_USAGE_SAMPLED_BIT;
358     }
359 
360     VkExternalMemoryImageCreateInfo externalMemoryImageCreateInfo = {};
361     externalMemoryImageCreateInfo.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO;
362     externalMemoryImageCreateInfo.pNext = &externalFormat;
363     externalMemoryImageCreateInfo.handleTypes =
364         VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID;
365 
366     VkExtent3D vkExtents;
367     gl_vk::GetExtent(mSize, &vkExtents);
368 
369     // Setup level count
370     mLevelCount = ((ahbDescription.usage & AHARDWAREBUFFER_USAGE_GPU_MIPMAP_COMPLETE) != 0)
371                       ? static_cast<uint32_t>(log2(std::max(mSize.width, mSize.height))) + 1
372                       : 1;
373 
374     // No support for rendering to external YUV AHB with multiple miplevels
375     ANGLE_VK_CHECK(displayVk, (!externalRenderTargetSupported || mLevelCount == 1),
376                    VK_ERROR_INITIALIZATION_FAILED);
377 
378     // Setup layer count
379     const uint32_t layerCount = mSize.depth;
380     vkExtents.depth           = 1;
381 
382     mImage = new vk::ImageHelper();
383 
384     // disable robust init for this external image.
385     bool robustInitEnabled = false;
386 
387     mImage->setTilingMode(imageTilingMode);
388     VkImageCreateFlags imageCreateFlags = AhbDescUsageToVkImageCreateFlags(ahbDescription);
389     vk::YcbcrConversionDesc conversionDesc{};
390 
391     if (isExternal)
392     {
393         if (externalRenderTargetSupported)
394         {
395             angle::FormatID externalFormatID =
396                 renderer->getExternalFormatTable()->getOrAllocExternalFormatID(
397                     bufferFormatProperties.externalFormat,
398                     bufferFormatResolveProperties.colorAttachmentFormat,
399                     bufferFormatProperties.formatFeatures);
400 
401             vkFormat = &renderer->getFormat(externalFormatID);
402         }
403         else
404         {
405             // If not renderable, don't burn a slot on it.
406             vkFormat = &renderer->getFormat(angle::FormatID::NONE);
407         }
408     }
409 
410     if (isExternal || imageFormat.isYUV)
411     {
412         // Note from Vulkan spec: Since GL_OES_EGL_image_external does not require the same sampling
413         // and conversion calculations as Vulkan does, achieving identical results between APIs may
414         // not be possible on some implementations.
415         ANGLE_VK_CHECK(displayVk, renderer->getFeatures().supportsYUVSamplerConversion.enabled,
416                        VK_ERROR_FEATURE_NOT_PRESENT);
417         ASSERT(externalFormat.pNext == nullptr);
418 
419         // This may not actually mean the format is YUV. But the rest of ANGLE makes this
420         // assumption and needs this member variable.
421         mYUV = true;
422 
423         vk::YcbcrLinearFilterSupport linearFilterSupported =
424             (bufferFormatProperties.formatFeatures &
425              VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER_BIT) != 0
426                 ? vk::YcbcrLinearFilterSupport::Supported
427                 : vk::YcbcrLinearFilterSupport::Unsupported;
428 
429         conversionDesc.update(
430             renderer, isExternal ? bufferFormatProperties.externalFormat : 0,
431             bufferFormatProperties.suggestedYcbcrModel, bufferFormatProperties.suggestedYcbcrRange,
432             bufferFormatProperties.suggestedXChromaOffset,
433             bufferFormatProperties.suggestedYChromaOffset, vk::kDefaultYCbCrChromaFilter,
434             bufferFormatProperties.samplerYcbcrConversionComponents,
435             isExternal ? angle::FormatID::NONE : imageFormat.id, linearFilterSupported);
436     }
437 
438     const gl::TextureType textureType = AhbDescUsageToTextureType(ahbDescription, layerCount);
439 
440     VkImageFormatListCreateInfoKHR imageFormatListInfoStorage;
441     vk::ImageHelper::ImageListFormats imageListFormatsStorage;
442     const void *imageCreateInfoPNext = vk::ImageHelper::DeriveCreateInfoPNext(
443         displayVk, vkFormat->getActualRenderableImageFormatID(), &externalMemoryImageCreateInfo,
444         &imageFormatListInfoStorage, &imageListFormatsStorage, &imageCreateFlags);
445 
446     ANGLE_TRY(
447         mImage->initExternal(displayVk, textureType, vkExtents, vkFormat->getIntendedFormatID(),
448                              vkFormat->getActualRenderableImageFormatID(), 1, usage,
449                              imageCreateFlags, vk::ImageLayout::ExternalPreInitialized,
450                              imageCreateInfoPNext, gl::LevelIndex(0), mLevelCount, layerCount,
451                              robustInitEnabled, hasProtectedContent(), conversionDesc, nullptr));
452 
453     VkImportAndroidHardwareBufferInfoANDROID importHardwareBufferInfo = {};
454     importHardwareBufferInfo.sType  = VK_STRUCTURE_TYPE_IMPORT_ANDROID_HARDWARE_BUFFER_INFO_ANDROID;
455     importHardwareBufferInfo.buffer = hardwareBuffer;
456 
457     VkMemoryDedicatedAllocateInfo dedicatedAllocInfo = {};
458     dedicatedAllocInfo.sType          = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO;
459     dedicatedAllocInfo.pNext          = &importHardwareBufferInfo;
460     dedicatedAllocInfo.image          = mImage->getImage().getHandle();
461     dedicatedAllocInfo.buffer         = VK_NULL_HANDLE;
462     const void *dedicatedAllocInfoPtr = &dedicatedAllocInfo;
463 
464     VkMemoryRequirements externalMemoryRequirements = {};
465     externalMemoryRequirements.size                 = bufferProperties.allocationSize;
466     externalMemoryRequirements.alignment            = 0;
467     externalMemoryRequirements.memoryTypeBits       = bufferProperties.memoryTypeBits;
468 
469     const VkMemoryPropertyFlags flags =
470         VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT |
471         (hasProtectedContent() ? VK_MEMORY_PROPERTY_PROTECTED_BIT : 0);
472 
473     ANGLE_TRY(mImage->initExternalMemory(displayVk, renderer->getMemoryProperties(),
474                                          externalMemoryRequirements, 1, &dedicatedAllocInfoPtr,
475                                          vk::kForeignDeviceQueueIndex, flags));
476 
477     if (isExternal)
478     {
479         // External format means that we are working with VK_FORMAT_UNDEFINED,
480         // so hasImageFormatFeatureBits will assert. Set these based on
481         // presence of extensions or assumption.
482         mRenderable  = externalRenderTargetSupported;
483         mTextureable = externalTexturingSupported;
484     }
485     else
486     {
487         constexpr uint32_t kColorRenderableRequiredBits = VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT;
488         constexpr uint32_t kDepthStencilRenderableRequiredBits =
489             VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT;
490         mRenderable =
491             renderer->hasImageFormatFeatureBits(vkFormat->getActualRenderableImageFormatID(),
492                                                 kColorRenderableRequiredBits) ||
493             renderer->hasImageFormatFeatureBits(vkFormat->getActualRenderableImageFormatID(),
494                                                 kDepthStencilRenderableRequiredBits);
495         constexpr uint32_t kTextureableRequiredBits =
496             VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT | VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT;
497         mTextureable = renderer->hasImageFormatFeatureBits(
498             vkFormat->getActualRenderableImageFormatID(), kTextureableRequiredBits);
499     }
500 
501     return angle::Result::Continue;
502 }
503 
onDestroy(const egl::Display * display)504 void HardwareBufferImageSiblingVkAndroid::onDestroy(const egl::Display *display)
505 {
506     const AHBFunctions &functions = GetImplAs<DisplayVkAndroid>(display)->getAHBFunctions();
507     ASSERT(functions.valid());
508 
509     functions.release(angle::android::ANativeWindowBufferToAHardwareBuffer(
510         angle::android::ClientBufferToANativeWindowBuffer(mBuffer)));
511 
512     ASSERT(mImage == nullptr);
513 }
514 
getFormat() const515 gl::Format HardwareBufferImageSiblingVkAndroid::getFormat() const
516 {
517     return mFormat;
518 }
519 
isRenderable(const gl::Context * context) const520 bool HardwareBufferImageSiblingVkAndroid::isRenderable(const gl::Context *context) const
521 {
522     return mRenderable;
523 }
524 
isTexturable(const gl::Context * context) const525 bool HardwareBufferImageSiblingVkAndroid::isTexturable(const gl::Context *context) const
526 {
527     return mTextureable;
528 }
529 
isYUV() const530 bool HardwareBufferImageSiblingVkAndroid::isYUV() const
531 {
532     return mYUV;
533 }
534 
hasFrontBufferUsage() const535 bool HardwareBufferImageSiblingVkAndroid::hasFrontBufferUsage() const
536 {
537     return (mUsage & kAHardwareBufferUsageFrontBuffer) != 0;
538 }
539 
isCubeMap() const540 bool HardwareBufferImageSiblingVkAndroid::isCubeMap() const
541 {
542     return (mUsage & AHARDWAREBUFFER_USAGE_GPU_CUBE_MAP) != 0;
543 }
544 
hasProtectedContent() const545 bool HardwareBufferImageSiblingVkAndroid::hasProtectedContent() const
546 {
547     return ((mUsage & AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT) != 0);
548 }
549 
getSize() const550 gl::Extents HardwareBufferImageSiblingVkAndroid::getSize() const
551 {
552     return mSize;
553 }
554 
getSamples() const555 size_t HardwareBufferImageSiblingVkAndroid::getSamples() const
556 {
557     return mSamples;
558 }
559 
getLevelCount() const560 uint32_t HardwareBufferImageSiblingVkAndroid::getLevelCount() const
561 {
562     return mLevelCount;
563 }
564 
565 // ExternalImageSiblingVk interface
getImage() const566 vk::ImageHelper *HardwareBufferImageSiblingVkAndroid::getImage() const
567 {
568     return mImage;
569 }
570 
release(vk::Renderer * renderer)571 void HardwareBufferImageSiblingVkAndroid::release(vk::Renderer *renderer)
572 {
573     if (mImage != nullptr)
574     {
575         // TODO: Handle the case where the EGLImage is used in two contexts not in the same share
576         // group.  https://issuetracker.google.com/169868803
577         mImage->releaseImage(renderer);
578         mImage->releaseStagedUpdates(renderer);
579         SafeDelete(mImage);
580     }
581 }
582 
583 }  // namespace rx
584