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