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