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