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