• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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