1 /*
2 * Copyright 2023 Google LLC
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8 #include "include/android/GrAHardwareBufferUtils.h"
9
10 #if defined(SK_BUILD_FOR_ANDROID) && __ANDROID_API__ >= 26
11
12 #include "include/gpu/ganesh/GrBackendSurface.h"
13 #include "include/gpu/ganesh/GrDirectContext.h"
14 #include "include/gpu/ganesh/GrTypes.h"
15 #include "include/gpu/ganesh/vk/GrVkBackendSurface.h"
16 #include "include/gpu/ganesh/vk/GrVkTypes.h"
17 #include "include/gpu/vk/VulkanTypes.h"
18 #include "include/private/gpu/vk/SkiaVulkan.h"
19 #include "src/gpu/ganesh/GrDirectContextPriv.h"
20 #include "src/gpu/ganesh/vk/GrVkCaps.h"
21 #include "src/gpu/ganesh/vk/GrVkGpu.h"
22 #include "src/gpu/vk/VulkanInterface.h"
23 #include "src/gpu/vk/VulkanUtilsPriv.h"
24
25 #include <android/hardware_buffer.h>
26
27 #ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
28 #include <vndk/hardware_buffer.h>
29 #endif
30
31 #define VK_CALL(X) gpu->vkInterface()->fFunctions.f##X
32
33 namespace GrAHardwareBufferUtils {
34
GetVulkanBackendFormat(GrDirectContext * dContext,AHardwareBuffer * hardwareBuffer,uint32_t bufferFormat,bool requireKnownFormat)35 GrBackendFormat GetVulkanBackendFormat(GrDirectContext* dContext, AHardwareBuffer* hardwareBuffer,
36 uint32_t bufferFormat, bool requireKnownFormat) {
37 GrBackendApi backend = dContext->backend();
38 if (backend != GrBackendApi::kVulkan) {
39 return GrBackendFormat();
40 }
41
42 VkFormat bufferVkFormat = VK_FORMAT_UNDEFINED;
43 switch (bufferFormat) {
44 case AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM: {
45 bufferVkFormat = VK_FORMAT_R8G8B8A8_UNORM;
46 break;
47 }
48 #if __ANDROID_API__ >= 34
49 case AHARDWAREBUFFER_FORMAT_R10G10B10A10_UNORM: {
50 bufferVkFormat = VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16;
51 break;
52 }
53 #endif
54 case AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT: {
55 bufferVkFormat = VK_FORMAT_R16G16B16A16_SFLOAT;
56 break;
57 }
58 case AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM: {
59 bufferVkFormat = VK_FORMAT_R5G6B5_UNORM_PACK16;
60 break;
61 }
62 case AHARDWAREBUFFER_FORMAT_R10G10B10A2_UNORM: {
63 bufferVkFormat = VK_FORMAT_A2B10G10R10_UNORM_PACK32;
64 break;
65 }
66 case AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM: {
67 bufferVkFormat = VK_FORMAT_R8G8B8A8_UNORM;
68 break;
69 }
70 case AHARDWAREBUFFER_FORMAT_R8G8B8_UNORM: {
71 bufferVkFormat = VK_FORMAT_R8G8B8_UNORM;
72 break;
73 }
74 #if __ANDROID_API__ >= 33
75 case AHARDWAREBUFFER_FORMAT_R8_UNORM: {
76 bufferVkFormat = VK_FORMAT_R8_UNORM;
77 break;
78 }
79 #endif
80 #ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
81 case AHARDWAREBUFFER_FORMAT_B8G8R8A8_UNORM: {
82 bufferVkFormat = VK_FORMAT_B8G8R8A8_UNORM;
83 break;
84 }
85 #endif
86 default: {
87 if (requireKnownFormat) {
88 return GrBackendFormat();
89 }
90 break;
91 }
92 }
93
94 GrVkGpu* gpu = static_cast<GrVkGpu*>(dContext->priv().getGpu());
95 SkASSERT(gpu);
96
97 if (bufferVkFormat != VK_FORMAT_UNDEFINED) {
98 // Check to make sure the associated VkFormat has the necessary format features. If not,
99 // default to using an external format (set the VkFormat as undefined).
100 // TODO: When creating a GrBackendFormat with a VkFormat that is not VK_FORMAT_UNDEFINED, we
101 // currently assume that the VkFormat's VkFormatFeatureFlags contain
102 // VK_FORMAT_FEATURE_TRANSFER_SRC_BIT and VK_FORMAT_FEATURE_TRANSFER_DST_BIT.
103 if (gpu->vkCaps().isVkFormatTexturable(bufferVkFormat)) {
104 return GrBackendFormats::MakeVk(bufferVkFormat);
105 }
106 bufferVkFormat = VK_FORMAT_UNDEFINED;
107 }
108 // If there is no associated VkFormat (or it does not support the necessary features) and
109 // requireKnownFormat = false, then import using an external format.
110 VkDevice device = gpu->device();
111
112 if (!gpu->vkCaps().supportsAndroidHWBExternalMemory()) {
113 return GrBackendFormat();
114 }
115
116 VkAndroidHardwareBufferFormatPropertiesANDROID hwbFormatProps;
117 VkAndroidHardwareBufferPropertiesANDROID hwbProps;
118 if (!GetAHardwareBufferProperties(
119 &hwbFormatProps, &hwbProps, gpu->vkInterface(), hardwareBuffer, device)) {
120 return GrBackendFormat();
121 }
122
123 skgpu::VulkanYcbcrConversionInfo ycbcrConversion;
124 GetYcbcrConversionInfoFromFormatProps(&ycbcrConversion, hwbFormatProps);
125
126 return GrBackendFormats::MakeVk(ycbcrConversion);
127 }
128
129 class VulkanCleanupHelper {
130 public:
VulkanCleanupHelper(GrVkGpu * gpu,VkImage image,VkDeviceMemory memory)131 VulkanCleanupHelper(GrVkGpu* gpu, VkImage image, VkDeviceMemory memory)
132 : fDevice(gpu->device())
133 , fImage(image)
134 , fMemory(memory)
135 , fDestroyImage(gpu->vkInterface()->fFunctions.fDestroyImage)
136 , fFreeMemory(gpu->vkInterface()->fFunctions.fFreeMemory) {}
~VulkanCleanupHelper()137 ~VulkanCleanupHelper() {
138 fDestroyImage(fDevice, fImage, nullptr);
139 fFreeMemory(fDevice, fMemory, nullptr);
140 }
141 private:
142 VkDevice fDevice;
143 VkImage fImage;
144 VkDeviceMemory fMemory;
145 PFN_vkDestroyImage fDestroyImage;
146 PFN_vkFreeMemory fFreeMemory;
147 };
148
delete_vk_image(void * context)149 void delete_vk_image(void* context) {
150 VulkanCleanupHelper* cleanupHelper = static_cast<VulkanCleanupHelper*>(context);
151 delete cleanupHelper;
152 }
153
update_vk_image(void * context,GrDirectContext * dContext)154 void update_vk_image(void* context, GrDirectContext* dContext) {
155 // no op
156 }
157
make_vk_backend_texture(GrDirectContext * dContext,AHardwareBuffer * hardwareBuffer,int width,int height,DeleteImageProc * deleteProc,UpdateImageProc * updateProc,TexImageCtx * imageCtx,bool isProtectedContent,const GrBackendFormat & grBackendFormat,bool isRenderable,bool fromAndroidWindow)158 static GrBackendTexture make_vk_backend_texture(
159 GrDirectContext* dContext, AHardwareBuffer* hardwareBuffer,
160 int width, int height,
161 DeleteImageProc* deleteProc,
162 UpdateImageProc* updateProc,
163 TexImageCtx* imageCtx,
164 bool isProtectedContent,
165 const GrBackendFormat& grBackendFormat,
166 bool isRenderable,
167 bool fromAndroidWindow) {
168 SkASSERT(dContext->backend() == GrBackendApi::kVulkan);
169
170 GrVkGpu* gpu = static_cast<GrVkGpu*>(dContext->priv().getGpu());
171 SkASSERT(gpu);
172 SkASSERT(!isProtectedContent || gpu->protectedContext());
173
174 VkPhysicalDevice physicalDevice = gpu->physicalDevice();
175 VkDevice device = gpu->device();
176
177 if (!gpu->vkCaps().supportsAndroidHWBExternalMemory()) {
178 return GrBackendTexture();
179 }
180
181 VkFormat grBackendVkFormat;
182 if (!GrBackendFormats::AsVkFormat(grBackendFormat, &grBackendVkFormat)) {
183 SkDebugf("AsVkFormat failed (valid: %d, backend: %u)",
184 grBackendFormat.isValid(),
185 (unsigned)grBackendFormat.backend());
186 return GrBackendTexture();
187 }
188 bool importAsExternalFormat = grBackendVkFormat == VK_FORMAT_UNDEFINED;
189
190 VkAndroidHardwareBufferFormatPropertiesANDROID hwbFormatProps;
191 VkAndroidHardwareBufferPropertiesANDROID hwbProps;
192 if (!skgpu::GetAHardwareBufferProperties(
193 &hwbFormatProps, &hwbProps, gpu->vkInterface(), hardwareBuffer, device)) {
194 return GrBackendTexture();
195 }
196 VkFormat hwbVkFormat = hwbFormatProps.format;
197
198 // We normally expect the hardware buffer format (hwbVkFormat) to be equivalent to ganesh's
199 // GrBackendFormat VkFormat (grBackendVkFormat). However, even if the hwbVkFormat is a defined
200 // format, we may choose to ignore that and instead import the AHardwareBuffer using an
201 // external format. For example, we would attempt to do this if the VkFormat doesn't support the
202 // necessary features. Thus, it is acceptable for hwbVkFormat to differ from grBackendVkFormat
203 // iff we are importing the AHardwareBuffer using an external format.
204 if (!importAsExternalFormat && hwbVkFormat != grBackendVkFormat) {
205 SkDebugf("Queried format not consistent with expected format; got: %d, expected: %d",
206 hwbVkFormat,
207 grBackendVkFormat);
208 return GrBackendTexture();
209 }
210
211 VkExternalFormatANDROID externalFormat;
212 externalFormat.sType = VK_STRUCTURE_TYPE_EXTERNAL_FORMAT_ANDROID;
213 externalFormat.pNext = nullptr;
214 externalFormat.externalFormat = 0; // If this is zero it is as if we aren't using this struct.
215
216 const skgpu::VulkanYcbcrConversionInfo* ycbcrConversion =
217 GrBackendFormats::GetVkYcbcrConversionInfo(grBackendFormat);
218 if (!ycbcrConversion) {
219 return GrBackendTexture();
220 }
221
222 // TODO: Check the supported tilings vkGetPhysicalDeviceImageFormatProperties2 to see if we have
223 // to use linear. Add better linear support throughout Ganesh.
224 VkImageTiling tiling = VK_IMAGE_TILING_OPTIMAL;
225
226 if (isRenderable && (importAsExternalFormat || // cannot render to external formats
227 !gpu->vkCaps().isFormatRenderable(grBackendVkFormat, tiling))) {
228 SkDebugf("Renderable texture requested from an AHardwareBuffer which uses a "
229 "VkFormat that Skia cannot render to (VkFormat: %d).\n", grBackendVkFormat);
230 return GrBackendTexture();
231 }
232
233 if (importAsExternalFormat) {
234 if (!ycbcrConversion->isValid()) {
235 SkDebugf("YCbCr conversion must be valid when importing an AHardwareBuffer with an "
236 "external format");
237 return GrBackendTexture();
238 }
239 SkASSERT(SkToBool(VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT & hwbFormatProps.formatFeatures));
240 SkASSERT(hwbFormatProps.externalFormat == ycbcrConversion->fExternalFormat);
241 externalFormat.externalFormat = hwbFormatProps.externalFormat;
242 } else {
243 SkASSERT(!ycbcrConversion->isValid());
244 // Non-external formats are subject to format caps from VkPhysicalDeviceFormatProperties.
245 SkASSERT(gpu->vkCaps().isVkFormatTexturable(grBackendVkFormat));
246 // TODO: We currently assume that the provided VkFormat has transfer features
247 // (VK_FORMAT_FEATURE_TRANSFER_[SRC/DST]_BIT). Instead, we should have a way for Ganesh's
248 // tracking of intenral images to report whether or not they support transfers.
249 }
250
251 const VkExternalMemoryImageCreateInfo externalMemoryImageInfo{
252 VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO, // sType
253 &externalFormat, // pNext
254 VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID, // handleTypes
255 };
256
257 VkImageUsageFlags usageFlags = VK_IMAGE_USAGE_SAMPLED_BIT;
258 if (!importAsExternalFormat) {
259 usageFlags = usageFlags |
260 VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
261 VK_IMAGE_USAGE_TRANSFER_DST_BIT;
262 if (isRenderable) {
263 usageFlags = usageFlags | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
264 }
265 }
266
267 VkImageCreateFlags flags = isProtectedContent ? VK_IMAGE_CREATE_PROTECTED_BIT : 0;
268
269 const VkImageCreateInfo imageCreateInfo = {
270 VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // sType
271 &externalMemoryImageInfo, // pNext
272 flags, // VkImageCreateFlags
273 VK_IMAGE_TYPE_2D, // VkImageType
274 grBackendVkFormat, // VkFormat
275 { (uint32_t)width, (uint32_t)height, 1 }, // VkExtent3D
276 1, // mipLevels
277 1, // arrayLayers
278 VK_SAMPLE_COUNT_1_BIT, // samples
279 tiling, // VkImageTiling
280 usageFlags, // VkImageUsageFlags
281 VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode
282 0, // queueFamilyCount
283 nullptr, // pQueueFamilyIndices
284 VK_IMAGE_LAYOUT_UNDEFINED, // initialLayout
285 };
286
287 VkImage image;
288 VkResult err;
289 err = VK_CALL(CreateImage(device, &imageCreateInfo, nullptr, &image));
290 if (VK_SUCCESS != err) {
291 return GrBackendTexture();
292 }
293
294 VkPhysicalDeviceMemoryProperties2 phyDevMemProps;
295 phyDevMemProps.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PROPERTIES_2;
296 phyDevMemProps.pNext = nullptr;
297 VK_CALL(GetPhysicalDeviceMemoryProperties2(physicalDevice, &phyDevMemProps));
298
299 skgpu::VulkanAlloc alloc;
300 if (!skgpu::AllocateAndBindImageMemory(&alloc, image, phyDevMemProps, hwbProps, hardwareBuffer,
301 gpu->vkInterface(), device)) {
302 VK_CALL(DestroyImage(device, image, nullptr));
303 return GrBackendTexture();
304 }
305
306 GrVkImageInfo imageInfo;
307 imageInfo.fImage = image;
308 imageInfo.fAlloc = alloc;
309 imageInfo.fImageTiling = tiling;
310 imageInfo.fImageLayout = VK_IMAGE_LAYOUT_UNDEFINED;
311 imageInfo.fFormat = grBackendVkFormat;
312 imageInfo.fLevelCount = 1;
313 // TODO: This should possibly be VK_QUEUE_FAMILY_FOREIGN_EXT but current Adreno devices do not
314 // support that extension. Or if we know the source of the AHardwareBuffer is not from a
315 // "foreign" device we can leave them as external.
316 imageInfo.fCurrentQueueFamily = VK_QUEUE_FAMILY_EXTERNAL;
317 imageInfo.fProtected = isProtectedContent ? GrProtected::kYes : GrProtected::kNo;
318 imageInfo.fYcbcrConversionInfo = *ycbcrConversion;
319 imageInfo.fSharingMode = imageCreateInfo.sharingMode;
320 #ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
321 imageInfo.fPartOfSwapchainOrAndroidWindow = fromAndroidWindow;
322 #endif
323
324 *deleteProc = delete_vk_image;
325 *updateProc = update_vk_image;
326 *imageCtx = new VulkanCleanupHelper(gpu, image, alloc.fMemory);
327
328 return GrBackendTextures::MakeVk(width, height, imageInfo);
329 }
330
can_import_protected_content(GrDirectContext * dContext)331 static bool can_import_protected_content(GrDirectContext* dContext) {
332 SkASSERT(GrBackendApi::kVulkan == dContext->backend());
333 return static_cast<GrVkGpu*>(dContext->priv().getGpu())->protectedContext();
334 }
335
MakeVulkanBackendTexture(GrDirectContext * dContext,AHardwareBuffer * hardwareBuffer,int width,int height,DeleteImageProc * deleteProc,UpdateImageProc * updateProc,TexImageCtx * imageCtx,bool isProtectedContent,const GrBackendFormat & backendFormat,bool isRenderable,bool fromAndroidWindow)336 GrBackendTexture MakeVulkanBackendTexture(GrDirectContext* dContext,
337 AHardwareBuffer* hardwareBuffer,
338 int width, int height,
339 DeleteImageProc* deleteProc,
340 UpdateImageProc* updateProc,
341 TexImageCtx* imageCtx,
342 bool isProtectedContent,
343 const GrBackendFormat& backendFormat,
344 bool isRenderable,
345 bool fromAndroidWindow) {
346 SkASSERT(dContext);
347 if (!dContext || dContext->abandoned()) {
348 return GrBackendTexture();
349 }
350
351 if (GrBackendApi::kVulkan != dContext->backend()) {
352 return GrBackendTexture();
353 }
354
355 if (isProtectedContent && !can_import_protected_content(dContext)) {
356 return GrBackendTexture();
357 }
358
359 return make_vk_backend_texture(dContext, hardwareBuffer, width, height, deleteProc,
360 updateProc, imageCtx, isProtectedContent, backendFormat,
361 isRenderable, fromAndroidWindow);
362 }
363
364 } // namespace GrAHardwareBufferUtils
365
366 #endif
367