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/RendererVk.h"
16 #include "libANGLE/renderer/vulkan/android/AHBFunctions.h"
17 #include "libANGLE/renderer/vulkan/android/DisplayVkAndroid.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 } // namespace
135
HardwareBufferImageSiblingVkAndroid(EGLClientBuffer buffer)136 HardwareBufferImageSiblingVkAndroid::HardwareBufferImageSiblingVkAndroid(EGLClientBuffer buffer)
137 : mBuffer(buffer),
138 mFormat(GL_NONE),
139 mRenderable(false),
140 mTextureable(false),
141 mYUV(false),
142 mLevelCount(0),
143 mUsage(0),
144 mSamples(0),
145 mImage(nullptr)
146 {}
147
~HardwareBufferImageSiblingVkAndroid()148 HardwareBufferImageSiblingVkAndroid::~HardwareBufferImageSiblingVkAndroid() {}
149
150 // Static
ValidateHardwareBuffer(RendererVk * renderer,EGLClientBuffer buffer,const egl::AttributeMap & attribs)151 egl::Error HardwareBufferImageSiblingVkAndroid::ValidateHardwareBuffer(
152 RendererVk *renderer,
153 EGLClientBuffer buffer,
154 const egl::AttributeMap &attribs)
155 {
156 struct ANativeWindowBuffer *windowBuffer =
157 angle::android::ClientBufferToANativeWindowBuffer(buffer);
158 struct AHardwareBuffer *hardwareBuffer =
159 angle::android::ANativeWindowBufferToAHardwareBuffer(windowBuffer);
160
161 VkAndroidHardwareBufferFormatPropertiesANDROID bufferFormatProperties = {};
162 bufferFormatProperties.sType =
163 VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_FORMAT_PROPERTIES_ANDROID;
164 bufferFormatProperties.pNext = nullptr;
165
166 VkAndroidHardwareBufferPropertiesANDROID bufferProperties = {};
167 bufferProperties.sType = VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_PROPERTIES_ANDROID;
168 bufferProperties.pNext = &bufferFormatProperties;
169
170 VkDevice device = renderer->getDevice();
171 VkResult result =
172 vkGetAndroidHardwareBufferPropertiesANDROID(device, hardwareBuffer, &bufferProperties);
173 if (result != VK_SUCCESS)
174 {
175 return egl::EglBadParameter() << "Failed to query AHardwareBuffer properties";
176 }
177
178 if (bufferFormatProperties.format == VK_FORMAT_UNDEFINED)
179 {
180 ASSERT(bufferFormatProperties.externalFormat != 0);
181 // We must have an external format, check that it supports texture sampling
182 if (!(bufferFormatProperties.formatFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT))
183 {
184 return egl::EglBadParameter()
185 << "Sampling from AHardwareBuffer externalFormat 0x" << std::hex
186 << bufferFormatProperties.externalFormat << " is unsupported ";
187 }
188 }
189 else
190 {
191 angle::FormatID formatID = vk::GetFormatIDFromVkFormat(bufferFormatProperties.format);
192 if (!HasFullTextureFormatSupport(renderer, formatID))
193 {
194 return egl::EglBadParameter()
195 << "AHardwareBuffer format " << bufferFormatProperties.format
196 << " does not support enough features to use as a texture.";
197 }
198 }
199
200 if (attribs.getAsInt(EGL_PROTECTED_CONTENT_EXT, EGL_FALSE) == EGL_TRUE)
201 {
202 int width = 0;
203 int height = 0;
204 int depth = 0;
205 int pixelFormat = 0;
206 uint64_t usage = 0;
207 angle::android::GetANativeWindowBufferProperties(windowBuffer, &width, &height, &depth,
208 &pixelFormat, &usage);
209 if ((usage & AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT) == 0)
210 {
211 return egl::EglBadAccess()
212 << "EGL_PROTECTED_CONTENT_EXT attribute does not match protected state "
213 "of EGLCleintBuffer.";
214 }
215 }
216
217 return egl::NoError();
218 }
219
initialize(const egl::Display * display)220 egl::Error HardwareBufferImageSiblingVkAndroid::initialize(const egl::Display *display)
221 {
222 DisplayVk *displayVk = vk::GetImpl(display);
223 return angle::ToEGL(initImpl(displayVk), displayVk, EGL_BAD_PARAMETER);
224 }
225
initImpl(DisplayVk * displayVk)226 angle::Result HardwareBufferImageSiblingVkAndroid::initImpl(DisplayVk *displayVk)
227 {
228 const AHBFunctions &functions = static_cast<DisplayVkAndroid *>(displayVk)->getAHBFunctions();
229 ANGLE_VK_CHECK(displayVk, functions.valid(), VK_ERROR_INITIALIZATION_FAILED);
230
231 RendererVk *renderer = displayVk->getRenderer();
232
233 struct ANativeWindowBuffer *windowBuffer =
234 angle::android::ClientBufferToANativeWindowBuffer(mBuffer);
235
236 int pixelFormat = 0;
237 angle::android::GetANativeWindowBufferProperties(windowBuffer, &mSize.width, &mSize.height,
238 &mSize.depth, &pixelFormat, &mUsage);
239 GLenum internalFormat = angle::android::NativePixelFormatToGLInternalFormat(pixelFormat);
240 mFormat = gl::Format(internalFormat);
241
242 struct AHardwareBuffer *hardwareBuffer =
243 angle::android::ANativeWindowBufferToAHardwareBuffer(windowBuffer);
244
245 functions.acquire(hardwareBuffer);
246 VkAndroidHardwareBufferFormatPropertiesANDROID bufferFormatProperties;
247 bufferFormatProperties.sType =
248 VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_FORMAT_PROPERTIES_ANDROID;
249 bufferFormatProperties.pNext = nullptr;
250
251 VkAndroidHardwareBufferPropertiesANDROID bufferProperties = {};
252 bufferProperties.sType = VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_PROPERTIES_ANDROID;
253 bufferProperties.pNext = &bufferFormatProperties;
254
255 VkDevice device = renderer->getDevice();
256 ANGLE_VK_TRY(displayVk, vkGetAndroidHardwareBufferPropertiesANDROID(device, hardwareBuffer,
257 &bufferProperties));
258
259 VkExternalFormatANDROID externalFormat = {};
260 externalFormat.sType = VK_STRUCTURE_TYPE_EXTERNAL_FORMAT_ANDROID;
261 externalFormat.externalFormat = 0;
262
263 const vk::Format &vkFormat = renderer->getFormat(internalFormat);
264 const vk::Format &externalVkFormat = renderer->getFormat(angle::FormatID::NONE);
265 const angle::Format &imageFormat = vkFormat.getActualRenderableImageFormat();
266 bool isDepthOrStencilFormat = imageFormat.hasDepthOrStencilBits();
267
268 // Query AHB description and do the following -
269 // 1. Derive VkImageTiling mode based on AHB usage flags
270 // 2. Map AHB usage flags to VkImageUsageFlags
271 AHardwareBuffer_Desc ahbDescription;
272 functions.describe(hardwareBuffer, &ahbDescription);
273 VkImageTiling imageTilingMode = AhbDescUsageToVkImageTiling(ahbDescription);
274 VkImageUsageFlags usage = AhbDescUsageToVkImageUsage(ahbDescription, isDepthOrStencilFormat);
275
276 if (bufferFormatProperties.format == VK_FORMAT_UNDEFINED)
277 {
278 ANGLE_VK_CHECK(displayVk, bufferFormatProperties.externalFormat != 0, VK_ERROR_UNKNOWN);
279 externalFormat.externalFormat = bufferFormatProperties.externalFormat;
280
281 // VkImageCreateInfo struct: If the pNext chain includes a VkExternalFormatANDROID structure
282 // whose externalFormat member is not 0, usage must not include any usages except
283 // VK_IMAGE_USAGE_SAMPLED_BIT
284 usage = VK_IMAGE_USAGE_SAMPLED_BIT;
285
286 // If the pNext chain includes a VkExternalFormatANDROID structure whose externalFormat
287 // member is not 0, tiling must be VK_IMAGE_TILING_OPTIMAL
288 imageTilingMode = VK_IMAGE_TILING_OPTIMAL;
289 }
290
291 VkExternalMemoryImageCreateInfo externalMemoryImageCreateInfo = {};
292 externalMemoryImageCreateInfo.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO;
293 externalMemoryImageCreateInfo.pNext = &externalFormat;
294 externalMemoryImageCreateInfo.handleTypes =
295 VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID;
296
297 VkExtent3D vkExtents;
298 gl_vk::GetExtent(mSize, &vkExtents);
299
300 // Setup level count
301 mLevelCount = ((ahbDescription.usage & AHARDWAREBUFFER_USAGE_GPU_MIPMAP_COMPLETE) != 0)
302 ? static_cast<uint32_t>(log2(std::max(mSize.width, mSize.height))) + 1
303 : 1;
304
305 // Setup layer count
306 const uint32_t layerCount = mSize.depth;
307 vkExtents.depth = 1;
308
309 mImage = new vk::ImageHelper();
310
311 // disable robust init for this external image.
312 bool robustInitEnabled = false;
313
314 mImage->setTilingMode(imageTilingMode);
315 VkImageCreateFlags imageCreateFlags = AhbDescUsageToVkImageCreateFlags(ahbDescription);
316
317 const vk::Format &format =
318 bufferFormatProperties.format == VK_FORMAT_UNDEFINED ? externalVkFormat : vkFormat;
319 const gl::TextureType textureType = AhbDescUsageToTextureType(ahbDescription, layerCount);
320
321 VkImageFormatListCreateInfoKHR imageFormatListInfoStorage;
322 vk::ImageHelper::ImageListFormats imageListFormatsStorage;
323 const void *imageCreateInfoPNext = vk::ImageHelper::DeriveCreateInfoPNext(
324 displayVk, format.getActualRenderableImageFormatID(), &externalMemoryImageCreateInfo,
325 &imageFormatListInfoStorage, &imageListFormatsStorage, &imageCreateFlags);
326
327 ANGLE_TRY(mImage->initExternal(displayVk, textureType, vkExtents, format.getIntendedFormatID(),
328 format.getActualRenderableImageFormatID(), 1, usage,
329 imageCreateFlags, vk::ImageLayout::ExternalPreInitialized,
330 imageCreateInfoPNext, gl::LevelIndex(0), mLevelCount, layerCount,
331 robustInitEnabled, hasProtectedContent()));
332
333 VkImportAndroidHardwareBufferInfoANDROID importHardwareBufferInfo = {};
334 importHardwareBufferInfo.sType = VK_STRUCTURE_TYPE_IMPORT_ANDROID_HARDWARE_BUFFER_INFO_ANDROID;
335 importHardwareBufferInfo.buffer = hardwareBuffer;
336
337 VkMemoryDedicatedAllocateInfo dedicatedAllocInfo = {};
338 dedicatedAllocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO;
339 dedicatedAllocInfo.pNext = &importHardwareBufferInfo;
340 dedicatedAllocInfo.image = mImage->getImage().getHandle();
341 dedicatedAllocInfo.buffer = VK_NULL_HANDLE;
342 const void *dedicatedAllocInfoPtr = &dedicatedAllocInfo;
343
344 VkMemoryRequirements externalMemoryRequirements = {};
345 externalMemoryRequirements.size = bufferProperties.allocationSize;
346 externalMemoryRequirements.alignment = 0;
347 externalMemoryRequirements.memoryTypeBits = bufferProperties.memoryTypeBits;
348
349 const VkMemoryPropertyFlags flags =
350 VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT |
351 (hasProtectedContent() ? VK_MEMORY_PROPERTY_PROTECTED_BIT : 0);
352
353 if (bufferFormatProperties.format == VK_FORMAT_UNDEFINED)
354 {
355 // Note from Vulkan spec: Since GL_OES_EGL_image_external does not require the same sampling
356 // and conversion calculations as Vulkan does, achieving identical results between APIs may
357 // not be possible on some implementations.
358 ANGLE_VK_CHECK(displayVk, renderer->getFeatures().supportsYUVSamplerConversion.enabled,
359 VK_ERROR_FEATURE_NOT_PRESENT);
360 ASSERT(externalFormat.pNext == nullptr);
361
362 // Update the SamplerYcbcrConversionCache key
363 mImage->updateYcbcrConversionDesc(
364 renderer, bufferFormatProperties.externalFormat,
365 bufferFormatProperties.suggestedYcbcrModel, bufferFormatProperties.suggestedYcbcrRange,
366 bufferFormatProperties.suggestedXChromaOffset,
367 bufferFormatProperties.suggestedYChromaOffset, VK_FILTER_NEAREST,
368 bufferFormatProperties.samplerYcbcrConversionComponents, angle::FormatID::NONE);
369 mYUV = true;
370 }
371
372 ANGLE_TRY(mImage->initExternalMemory(displayVk, renderer->getMemoryProperties(),
373 externalMemoryRequirements, 1, &dedicatedAllocInfoPtr,
374 VK_QUEUE_FAMILY_FOREIGN_EXT, flags));
375
376 constexpr uint32_t kColorRenderableRequiredBits = VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT;
377 constexpr uint32_t kDepthStencilRenderableRequiredBits = VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT;
378 mRenderable = renderer->hasImageFormatFeatureBits(vkFormat.getActualRenderableImageFormatID(),
379 kColorRenderableRequiredBits) ||
380 renderer->hasImageFormatFeatureBits(vkFormat.getActualRenderableImageFormatID(),
381 kDepthStencilRenderableRequiredBits);
382
383 constexpr uint32_t kTextureableRequiredBits =
384 VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT | VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT;
385 mTextureable = renderer->hasImageFormatFeatureBits(vkFormat.getActualRenderableImageFormatID(),
386 kTextureableRequiredBits);
387
388 return angle::Result::Continue;
389 }
390
onDestroy(const egl::Display * display)391 void HardwareBufferImageSiblingVkAndroid::onDestroy(const egl::Display *display)
392 {
393 const AHBFunctions &functions = GetImplAs<DisplayVkAndroid>(display)->getAHBFunctions();
394 ASSERT(functions.valid());
395
396 functions.release(angle::android::ANativeWindowBufferToAHardwareBuffer(
397 angle::android::ClientBufferToANativeWindowBuffer(mBuffer)));
398
399 ASSERT(mImage == nullptr);
400 }
401
getFormat() const402 gl::Format HardwareBufferImageSiblingVkAndroid::getFormat() const
403 {
404 return mFormat;
405 }
406
isRenderable(const gl::Context * context) const407 bool HardwareBufferImageSiblingVkAndroid::isRenderable(const gl::Context *context) const
408 {
409 return mRenderable;
410 }
411
isTexturable(const gl::Context * context) const412 bool HardwareBufferImageSiblingVkAndroid::isTexturable(const gl::Context *context) const
413 {
414 return mTextureable;
415 }
416
isYUV() const417 bool HardwareBufferImageSiblingVkAndroid::isYUV() const
418 {
419 return mYUV;
420 }
421
isCubeMap() const422 bool HardwareBufferImageSiblingVkAndroid::isCubeMap() const
423 {
424 return (mUsage & AHARDWAREBUFFER_USAGE_GPU_CUBE_MAP) != 0;
425 }
426
hasProtectedContent() const427 bool HardwareBufferImageSiblingVkAndroid::hasProtectedContent() const
428 {
429 return ((mUsage & AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT) != 0);
430 }
431
getSize() const432 gl::Extents HardwareBufferImageSiblingVkAndroid::getSize() const
433 {
434 return mSize;
435 }
436
getSamples() const437 size_t HardwareBufferImageSiblingVkAndroid::getSamples() const
438 {
439 return mSamples;
440 }
441
getLevelCount() const442 uint32_t HardwareBufferImageSiblingVkAndroid::getLevelCount() const
443 {
444 return mLevelCount;
445 }
446
447 // ExternalImageSiblingVk interface
getImage() const448 vk::ImageHelper *HardwareBufferImageSiblingVkAndroid::getImage() const
449 {
450 return mImage;
451 }
452
release(RendererVk * renderer)453 void HardwareBufferImageSiblingVkAndroid::release(RendererVk *renderer)
454 {
455 if (mImage != nullptr)
456 {
457 // TODO: Handle the case where the EGLImage is used in two contexts not in the same share
458 // group. https://issuetracker.google.com/169868803
459 mImage->releaseImage(renderer);
460 mImage->releaseStagedUpdates(renderer);
461 SafeDelete(mImage);
462 }
463 }
464
465 } // namespace rx
466