1 /*
2 * Copyright 2019 Google Inc.
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/core/SkTypes.h"
9
10 #if defined(SK_BUILD_FOR_ANDROID) && __ANDROID_API__ >= 26
11 #define GL_GLEXT_PROTOTYPES
12 #define EGL_EGLEXT_PROTOTYPES
13
14 #include "src/gpu/ganesh/GrAHardwareBufferUtils_impl.h"
15
16 #include <android/hardware_buffer.h>
17 #ifdef SK_GL
18 #include <EGL/egl.h>
19 #include <EGL/eglext.h>
20 #include <GLES/gl.h>
21 #include <GLES/glext.h>
22 #endif
23
24 #include "include/gpu/GrDirectContext.h"
25 #include "src/gpu/ganesh/GrDirectContextPriv.h"
26
27 #ifdef SK_GL
28 #include "include/gpu/gl/GrGLTypes.h"
29 #include "src/gpu/ganesh/gl/GrGLDefines_impl.h"
30 #include "src/gpu/ganesh/gl/GrGLUtil.h"
31 #endif
32
33 #ifdef SK_VULKAN
34 #include "src/gpu/ganesh/vk/GrVkCaps.h"
35 #include "src/gpu/ganesh/vk/GrVkGpu.h"
36 #endif
37
38 #define PROT_CONTENT_EXT_STR "EGL_EXT_protected_content"
39 #define EGL_PROTECTED_CONTENT_EXT 0x32C0
40
41 #define VK_CALL(X) gpu->vkInterface()->fFunctions.f##X
42
43 namespace GrAHardwareBufferUtils {
44
GetSkColorTypeFromBufferFormat(uint32_t bufferFormat)45 SkColorType GetSkColorTypeFromBufferFormat(uint32_t bufferFormat) {
46 switch (bufferFormat) {
47 case AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM:
48 return kRGBA_8888_SkColorType;
49 case AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM:
50 return kRGB_888x_SkColorType;
51 case AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT:
52 return kRGBA_F16_SkColorType;
53 case AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM:
54 return kRGB_565_SkColorType;
55 case AHARDWAREBUFFER_FORMAT_R8G8B8_UNORM:
56 return kRGB_888x_SkColorType;
57 case AHARDWAREBUFFER_FORMAT_R10G10B10A2_UNORM:
58 return kRGBA_1010102_SkColorType;
59 #if __ANDROID_API__ >= 33
60 case AHARDWAREBUFFER_FORMAT_R8_UNORM:
61 return kAlpha_8_SkColorType;
62 #endif
63 default:
64 // Given that we only use this texture as a source, colorType will not impact how Skia
65 // uses the texture. The only potential affect this is anticipated to have is that for
66 // some format types if we are not bound as an OES texture we may get invalid results
67 // for SKP capture if we read back the texture.
68 return kRGBA_8888_SkColorType;
69 }
70 }
71
GetBackendFormat(GrDirectContext * dContext,AHardwareBuffer * hardwareBuffer,uint32_t bufferFormat,bool requireKnownFormat)72 GrBackendFormat GetBackendFormat(GrDirectContext* dContext, AHardwareBuffer* hardwareBuffer,
73 uint32_t bufferFormat, bool requireKnownFormat) {
74 GrBackendApi backend = dContext->backend();
75
76 if (backend == GrBackendApi::kOpenGL) {
77 #ifdef SK_GL
78 switch (bufferFormat) {
79 //TODO: find out if we can detect, which graphic buffers support GR_GL_TEXTURE_2D
80 case AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM:
81 case AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM:
82 return GrBackendFormat::MakeGL(GR_GL_RGBA8, GR_GL_TEXTURE_EXTERNAL);
83 case AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT:
84 return GrBackendFormat::MakeGL(GR_GL_RGBA16F, GR_GL_TEXTURE_EXTERNAL);
85 case AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM:
86 return GrBackendFormat::MakeGL(GR_GL_RGB565, GR_GL_TEXTURE_EXTERNAL);
87 case AHARDWAREBUFFER_FORMAT_R10G10B10A2_UNORM:
88 return GrBackendFormat::MakeGL(GR_GL_RGB10_A2, GR_GL_TEXTURE_EXTERNAL);
89 case AHARDWAREBUFFER_FORMAT_R8G8B8_UNORM:
90 return GrBackendFormat::MakeGL(GR_GL_RGB8, GR_GL_TEXTURE_EXTERNAL);
91 #if __ANDROID_API__ >= 33
92 case AHARDWAREBUFFER_FORMAT_R8_UNORM:
93 return GrBackendFormat::MakeGL(GR_GL_R8, GR_GL_TEXTURE_EXTERNAL);
94 #endif
95 default:
96 if (requireKnownFormat) {
97 return GrBackendFormat();
98 } else {
99 return GrBackendFormat::MakeGL(GR_GL_RGBA8, GR_GL_TEXTURE_EXTERNAL);
100 }
101 }
102 #else // SK_GL
103 return GrBackendFormat();
104 #endif // SK_GL
105 } else if (backend == GrBackendApi::kVulkan) {
106 #ifdef SK_VULKAN
107 switch (bufferFormat) {
108 case AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM:
109 return GrBackendFormat::MakeVk(VK_FORMAT_R8G8B8A8_UNORM);
110 case AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT:
111 return GrBackendFormat::MakeVk(VK_FORMAT_R16G16B16A16_SFLOAT);
112 case AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM:
113 return GrBackendFormat::MakeVk(VK_FORMAT_R5G6B5_UNORM_PACK16);
114 case AHARDWAREBUFFER_FORMAT_R10G10B10A2_UNORM:
115 return GrBackendFormat::MakeVk(VK_FORMAT_A2B10G10R10_UNORM_PACK32);
116 case AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM:
117 return GrBackendFormat::MakeVk(VK_FORMAT_R8G8B8A8_UNORM);
118 case AHARDWAREBUFFER_FORMAT_R8G8B8_UNORM:
119 return GrBackendFormat::MakeVk(VK_FORMAT_R8G8B8_UNORM);
120 #if __ANDROID_API__ >= 33
121 case AHARDWAREBUFFER_FORMAT_R8_UNORM:
122 return GrBackendFormat::MakeVk(VK_FORMAT_R8_UNORM);
123 #endif
124 default: {
125 if (requireKnownFormat) {
126 return GrBackendFormat();
127 } else {
128 GrVkGpu* gpu = static_cast<GrVkGpu*>(dContext->priv().getGpu());
129 SkASSERT(gpu);
130 VkDevice device = gpu->device();
131
132 if (!gpu->vkCaps().supportsAndroidHWBExternalMemory()) {
133 return GrBackendFormat();
134 }
135 VkAndroidHardwareBufferFormatPropertiesANDROID hwbFormatProps;
136 hwbFormatProps.sType =
137 VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_FORMAT_PROPERTIES_ANDROID;
138 hwbFormatProps.pNext = nullptr;
139
140 VkAndroidHardwareBufferPropertiesANDROID hwbProps;
141 hwbProps.sType = VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_PROPERTIES_ANDROID;
142 hwbProps.pNext = &hwbFormatProps;
143
144 VkResult err = VK_CALL(GetAndroidHardwareBufferProperties(device,
145 hardwareBuffer,
146 &hwbProps));
147 if (VK_SUCCESS != err) {
148 return GrBackendFormat();
149 }
150
151 if (hwbFormatProps.format != VK_FORMAT_UNDEFINED) {
152 return GrBackendFormat();
153 }
154
155 GrVkYcbcrConversionInfo ycbcrConversion;
156 ycbcrConversion.fYcbcrModel = hwbFormatProps.suggestedYcbcrModel;
157 ycbcrConversion.fYcbcrRange = hwbFormatProps.suggestedYcbcrRange;
158 ycbcrConversion.fXChromaOffset = hwbFormatProps.suggestedXChromaOffset;
159 ycbcrConversion.fYChromaOffset = hwbFormatProps.suggestedYChromaOffset;
160 ycbcrConversion.fForceExplicitReconstruction = VK_FALSE;
161 ycbcrConversion.fExternalFormat = hwbFormatProps.externalFormat;
162 ycbcrConversion.fFormatFeatures = hwbFormatProps.formatFeatures;
163 if (VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER_BIT &
164 hwbFormatProps.formatFeatures) {
165 ycbcrConversion.fChromaFilter = VK_FILTER_LINEAR;
166 } else {
167 ycbcrConversion.fChromaFilter = VK_FILTER_NEAREST;
168 }
169
170 return GrBackendFormat::MakeVk(ycbcrConversion);
171 }
172 }
173 }
174 #else // SK_VULKAN
175 return GrBackendFormat();
176 #endif // SK_VULKAN
177 }
178 return GrBackendFormat();
179 }
180
181 #ifdef SK_GL
182 class GLTextureHelper {
183 public:
GLTextureHelper(GrGLuint texID,EGLImageKHR image,EGLDisplay display,GrGLuint texTarget)184 GLTextureHelper(GrGLuint texID, EGLImageKHR image, EGLDisplay display, GrGLuint texTarget)
185 : fTexID(texID)
186 , fImage(image)
187 , fDisplay(display)
188 , fTexTarget(texTarget) { }
~GLTextureHelper()189 ~GLTextureHelper() {
190 glDeleteTextures(1, &fTexID);
191 // eglDestroyImageKHR will remove a ref from the AHardwareBuffer
192 eglDestroyImageKHR(fDisplay, fImage);
193 }
194 void rebind(GrDirectContext*);
195
196 private:
197 GrGLuint fTexID;
198 EGLImageKHR fImage;
199 EGLDisplay fDisplay;
200 GrGLuint fTexTarget;
201 };
202
rebind(GrDirectContext * dContext)203 void GLTextureHelper::rebind(GrDirectContext* dContext) {
204 glBindTexture(fTexTarget, fTexID);
205 GLenum status = GL_NO_ERROR;
206 if ((status = glGetError()) != GL_NO_ERROR) {
207 SkDebugf("glBindTexture(%#x, %d) failed (%#x)", (int) fTexTarget,
208 (int) fTexID, (int) status);
209 return;
210 }
211 glEGLImageTargetTexture2DOES(fTexTarget, fImage);
212 if ((status = glGetError()) != GL_NO_ERROR) {
213 SkDebugf("glEGLImageTargetTexture2DOES failed (%#x)", (int) status);
214 return;
215 }
216 dContext->resetContext(kTextureBinding_GrGLBackendState);
217 }
218
delete_gl_texture(void * context)219 void delete_gl_texture(void* context) {
220 GLTextureHelper* cleanupHelper = static_cast<GLTextureHelper*>(context);
221 delete cleanupHelper;
222 }
223
update_gl_texture(void * context,GrDirectContext * dContext)224 void update_gl_texture(void* context, GrDirectContext* dContext) {
225 GLTextureHelper* cleanupHelper = static_cast<GLTextureHelper*>(context);
226 cleanupHelper->rebind(dContext);
227 }
228
make_gl_backend_texture(GrDirectContext * dContext,AHardwareBuffer * hardwareBuffer,int width,int height,DeleteImageProc * deleteProc,UpdateImageProc * updateProc,TexImageCtx * imageCtx,bool isProtectedContent,const GrBackendFormat & backendFormat,bool isRenderable)229 static GrBackendTexture make_gl_backend_texture(
230 GrDirectContext* dContext,
231 AHardwareBuffer* hardwareBuffer,
232 int width, int height,
233 DeleteImageProc* deleteProc,
234 UpdateImageProc* updateProc,
235 TexImageCtx* imageCtx,
236 bool isProtectedContent,
237 const GrBackendFormat& backendFormat,
238 bool isRenderable) {
239 while (GL_NO_ERROR != glGetError()) {} //clear GL errors
240
241 EGLClientBuffer clientBuffer = eglGetNativeClientBufferANDROID(hardwareBuffer);
242 EGLint attribs[] = { EGL_IMAGE_PRESERVED_KHR, EGL_TRUE,
243 isProtectedContent ? EGL_PROTECTED_CONTENT_EXT : EGL_NONE,
244 isProtectedContent ? EGL_TRUE : EGL_NONE,
245 EGL_NONE };
246 EGLDisplay display = eglGetCurrentDisplay();
247 // eglCreateImageKHR will add a ref to the AHardwareBuffer
248 EGLImageKHR image = eglCreateImageKHR(display, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID,
249 clientBuffer, attribs);
250 if (EGL_NO_IMAGE_KHR == image) {
251 SkDebugf("Could not create EGL image, err = (%#x)", (int) eglGetError() );
252 return GrBackendTexture();
253 }
254
255 GrGLuint texID;
256 glGenTextures(1, &texID);
257 if (!texID) {
258 eglDestroyImageKHR(display, image);
259 return GrBackendTexture();
260 }
261
262 GrGLuint target = isRenderable ? GR_GL_TEXTURE_2D : GR_GL_TEXTURE_EXTERNAL;
263
264 glBindTexture(target, texID);
265 GLenum status = GL_NO_ERROR;
266 if ((status = glGetError()) != GL_NO_ERROR) {
267 SkDebugf("glBindTexture failed (%#x)", (int) status);
268 glDeleteTextures(1, &texID);
269 eglDestroyImageKHR(display, image);
270 return GrBackendTexture();
271 }
272 glEGLImageTargetTexture2DOES(target, image);
273 if ((status = glGetError()) != GL_NO_ERROR) {
274 SkDebugf("glEGLImageTargetTexture2DOES failed (%#x)", (int) status);
275 glDeleteTextures(1, &texID);
276 eglDestroyImageKHR(display, image);
277 return GrBackendTexture();
278 }
279 dContext->resetContext(kTextureBinding_GrGLBackendState);
280
281 GrGLTextureInfo textureInfo;
282 textureInfo.fID = texID;
283 SkASSERT(backendFormat.isValid());
284 textureInfo.fTarget = target;
285 textureInfo.fFormat = GrGLFormatToEnum(backendFormat.asGLFormat());
286
287 *deleteProc = delete_gl_texture;
288 *updateProc = update_gl_texture;
289 *imageCtx = new GLTextureHelper(texID, image, display, target);
290
291 return GrBackendTexture(width, height, GrMipmapped::kNo, textureInfo);
292 }
293 #endif // SK_GL
294
295 #ifdef SK_VULKAN
296 class VulkanCleanupHelper {
297 public:
VulkanCleanupHelper(GrVkGpu * gpu,VkImage image,VkDeviceMemory memory)298 VulkanCleanupHelper(GrVkGpu* gpu, VkImage image, VkDeviceMemory memory)
299 : fDevice(gpu->device())
300 , fImage(image)
301 , fMemory(memory)
302 , fDestroyImage(gpu->vkInterface()->fFunctions.fDestroyImage)
303 , fFreeMemory(gpu->vkInterface()->fFunctions.fFreeMemory) {}
~VulkanCleanupHelper()304 ~VulkanCleanupHelper() {
305 fDestroyImage(fDevice, fImage, nullptr);
306 fFreeMemory(fDevice, fMemory, nullptr);
307 }
308 private:
309 VkDevice fDevice;
310 VkImage fImage;
311 VkDeviceMemory fMemory;
312 PFN_vkDestroyImage fDestroyImage;
313 PFN_vkFreeMemory fFreeMemory;
314 };
315
delete_vk_image(void * context)316 void delete_vk_image(void* context) {
317 VulkanCleanupHelper* cleanupHelper = static_cast<VulkanCleanupHelper*>(context);
318 delete cleanupHelper;
319 }
320
update_vk_image(void * context,GrDirectContext * dContext)321 void update_vk_image(void* context, GrDirectContext* dContext) {
322 // no op
323 }
324
make_vk_backend_texture(GrDirectContext * dContext,AHardwareBuffer * hardwareBuffer,int width,int height,DeleteImageProc * deleteProc,UpdateImageProc * updateProc,TexImageCtx * imageCtx,bool isProtectedContent,const GrBackendFormat & backendFormat,bool isRenderable,bool fromAndroidWindow)325 static GrBackendTexture make_vk_backend_texture(
326 GrDirectContext* dContext, AHardwareBuffer* hardwareBuffer,
327 int width, int height,
328 DeleteImageProc* deleteProc,
329 UpdateImageProc* updateProc,
330 TexImageCtx* imageCtx,
331 bool isProtectedContent,
332 const GrBackendFormat& backendFormat,
333 bool isRenderable,
334 bool fromAndroidWindow) {
335 SkASSERT(dContext->backend() == GrBackendApi::kVulkan);
336 GrVkGpu* gpu = static_cast<GrVkGpu*>(dContext->priv().getGpu());
337
338 SkASSERT(!isProtectedContent || gpu->protectedContext());
339
340 VkPhysicalDevice physicalDevice = gpu->physicalDevice();
341 VkDevice device = gpu->device();
342
343 SkASSERT(gpu);
344
345 if (!gpu->vkCaps().supportsAndroidHWBExternalMemory()) {
346 return GrBackendTexture();
347 }
348
349 VkFormat format;
350 SkAssertResult(backendFormat.asVkFormat(&format));
351
352 VkResult err;
353
354 VkAndroidHardwareBufferFormatPropertiesANDROID hwbFormatProps;
355 hwbFormatProps.sType = VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_FORMAT_PROPERTIES_ANDROID;
356 hwbFormatProps.pNext = nullptr;
357
358 VkAndroidHardwareBufferPropertiesANDROID hwbProps;
359 hwbProps.sType = VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_PROPERTIES_ANDROID;
360 hwbProps.pNext = &hwbFormatProps;
361
362 err = VK_CALL(GetAndroidHardwareBufferProperties(device, hardwareBuffer, &hwbProps));
363 if (VK_SUCCESS != err) {
364 return GrBackendTexture();
365 }
366
367 VkExternalFormatANDROID externalFormat;
368 externalFormat.sType = VK_STRUCTURE_TYPE_EXTERNAL_FORMAT_ANDROID;
369 externalFormat.pNext = nullptr;
370 externalFormat.externalFormat = 0; // If this is zero it is as if we aren't using this struct.
371
372 const GrVkYcbcrConversionInfo* ycbcrConversion = backendFormat.getVkYcbcrConversionInfo();
373 if (!ycbcrConversion) {
374 return GrBackendTexture();
375 }
376
377 if (hwbFormatProps.format != VK_FORMAT_UNDEFINED) {
378 // TODO: We should not assume the transfer features here and instead should have a way for
379 // Ganesh's tracking of intenral images to report whether or not they support transfers.
380 SkASSERT(SkToBool(VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT & hwbFormatProps.formatFeatures) &&
381 SkToBool(VK_FORMAT_FEATURE_TRANSFER_SRC_BIT & hwbFormatProps.formatFeatures) &&
382 SkToBool(VK_FORMAT_FEATURE_TRANSFER_DST_BIT & hwbFormatProps.formatFeatures));
383 SkASSERT(!ycbcrConversion->isValid());
384 } else {
385 SkASSERT(ycbcrConversion->isValid());
386 // We have an external only format
387 SkASSERT(SkToBool(VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT & hwbFormatProps.formatFeatures));
388 SkASSERT(format == VK_FORMAT_UNDEFINED);
389 SkASSERT(hwbFormatProps.externalFormat == ycbcrConversion->fExternalFormat);
390 externalFormat.externalFormat = hwbFormatProps.externalFormat;
391 }
392 SkASSERT(format == hwbFormatProps.format);
393
394 const VkExternalMemoryImageCreateInfo externalMemoryImageInfo{
395 VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO, // sType
396 &externalFormat, // pNext
397 VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID, // handleTypes
398 };
399 VkImageUsageFlags usageFlags = VK_IMAGE_USAGE_SAMPLED_BIT;
400 if (format != VK_FORMAT_UNDEFINED) {
401 usageFlags = usageFlags |
402 VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
403 VK_IMAGE_USAGE_TRANSFER_DST_BIT;
404 if (isRenderable) {
405 usageFlags = usageFlags | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
406 }
407 }
408
409 // TODO: Check the supported tilings vkGetPhysicalDeviceImageFormatProperties2 to see if we have
410 // to use linear. Add better linear support throughout Ganesh.
411 VkImageTiling tiling = VK_IMAGE_TILING_OPTIMAL;
412
413 VkImageCreateFlags flags = isProtectedContent ? VK_IMAGE_CREATE_PROTECTED_BIT : 0;
414
415 const VkImageCreateInfo imageCreateInfo = {
416 VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // sType
417 &externalMemoryImageInfo, // pNext
418 flags, // VkImageCreateFlags
419 VK_IMAGE_TYPE_2D, // VkImageType
420 format, // VkFormat
421 { (uint32_t)width, (uint32_t)height, 1 }, // VkExtent3D
422 1, // mipLevels
423 1, // arrayLayers
424 VK_SAMPLE_COUNT_1_BIT, // samples
425 tiling, // VkImageTiling
426 usageFlags, // VkImageUsageFlags
427 VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode
428 0, // queueFamilyCount
429 nullptr, // pQueueFamilyIndices
430 VK_IMAGE_LAYOUT_UNDEFINED, // initialLayout
431 };
432
433 VkImage image;
434 err = VK_CALL(CreateImage(device, &imageCreateInfo, nullptr, &image));
435 if (VK_SUCCESS != err) {
436 return GrBackendTexture();
437 }
438
439 VkPhysicalDeviceMemoryProperties2 phyDevMemProps;
440 phyDevMemProps.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PROPERTIES_2;
441 phyDevMemProps.pNext = nullptr;
442
443 uint32_t typeIndex = 0;
444 bool foundHeap = false;
445 VK_CALL(GetPhysicalDeviceMemoryProperties2(physicalDevice, &phyDevMemProps));
446 uint32_t memTypeCnt = phyDevMemProps.memoryProperties.memoryTypeCount;
447 for (uint32_t i = 0; i < memTypeCnt && !foundHeap; ++i) {
448 if (hwbProps.memoryTypeBits & (1 << i)) {
449 const VkPhysicalDeviceMemoryProperties& pdmp = phyDevMemProps.memoryProperties;
450 uint32_t supportedFlags = pdmp.memoryTypes[i].propertyFlags &
451 VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
452 if (supportedFlags == VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) {
453 typeIndex = i;
454 foundHeap = true;
455 }
456 }
457 }
458 if (!foundHeap) {
459 VK_CALL(DestroyImage(device, image, nullptr));
460 return GrBackendTexture();
461 }
462
463 VkImportAndroidHardwareBufferInfoANDROID hwbImportInfo;
464 hwbImportInfo.sType = VK_STRUCTURE_TYPE_IMPORT_ANDROID_HARDWARE_BUFFER_INFO_ANDROID;
465 hwbImportInfo.pNext = nullptr;
466 hwbImportInfo.buffer = hardwareBuffer;
467
468 VkMemoryDedicatedAllocateInfo dedicatedAllocInfo;
469 dedicatedAllocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO;
470 dedicatedAllocInfo.pNext = &hwbImportInfo;
471 dedicatedAllocInfo.image = image;
472 dedicatedAllocInfo.buffer = VK_NULL_HANDLE;
473
474 VkMemoryAllocateInfo allocInfo = {
475 VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, // sType
476 &dedicatedAllocInfo, // pNext
477 hwbProps.allocationSize, // allocationSize
478 typeIndex, // memoryTypeIndex
479 };
480
481 VkDeviceMemory memory;
482
483 err = VK_CALL(AllocateMemory(device, &allocInfo, nullptr, &memory));
484 if (VK_SUCCESS != err) {
485 VK_CALL(DestroyImage(device, image, nullptr));
486 return GrBackendTexture();
487 }
488
489 VkBindImageMemoryInfo bindImageInfo;
490 bindImageInfo.sType = VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO;
491 bindImageInfo.pNext = nullptr;
492 bindImageInfo.image = image;
493 bindImageInfo.memory = memory;
494 bindImageInfo.memoryOffset = 0;
495
496 err = VK_CALL(BindImageMemory2(device, 1, &bindImageInfo));
497 if (VK_SUCCESS != err) {
498 VK_CALL(DestroyImage(device, image, nullptr));
499 VK_CALL(FreeMemory(device, memory, nullptr));
500 return GrBackendTexture();
501 }
502
503 skgpu::VulkanAlloc alloc;
504 alloc.fMemory = memory;
505 alloc.fOffset = 0;
506 alloc.fSize = hwbProps.allocationSize;
507 alloc.fFlags = 0;
508
509 GrVkImageInfo imageInfo;
510 imageInfo.fImage = image;
511 imageInfo.fAlloc = alloc;
512 imageInfo.fImageTiling = tiling;
513 imageInfo.fImageLayout = VK_IMAGE_LAYOUT_UNDEFINED;
514 imageInfo.fFormat = format;
515 imageInfo.fLevelCount = 1;
516 // TODO: This should possibly be VK_QUEUE_FAMILY_FOREIGN_EXT but current Adreno devices do not
517 // support that extension. Or if we know the source of the AHardwareBuffer is not from a
518 // "foreign" device we can leave them as external.
519 imageInfo.fCurrentQueueFamily = VK_QUEUE_FAMILY_EXTERNAL;
520 imageInfo.fProtected = isProtectedContent ? GrProtected::kYes : GrProtected::kNo;
521 imageInfo.fYcbcrConversionInfo = *ycbcrConversion;
522 imageInfo.fSharingMode = imageCreateInfo.sharingMode;
523 #ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
524 imageInfo.fPartOfSwapchainOrAndroidWindow = fromAndroidWindow;
525 #endif
526
527 *deleteProc = delete_vk_image;
528 *updateProc = update_vk_image;
529 *imageCtx = new VulkanCleanupHelper(gpu, image, memory);
530
531 return GrBackendTexture(width, height, imageInfo);
532 }
533 #endif // SK_VULKAN
534
535 #ifdef SK_GL
can_import_protected_content_eglimpl()536 static bool can_import_protected_content_eglimpl() {
537 EGLDisplay dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
538 const char* exts = eglQueryString(dpy, EGL_EXTENSIONS);
539 size_t cropExtLen = strlen(PROT_CONTENT_EXT_STR);
540 size_t extsLen = strlen(exts);
541 bool equal = !strcmp(PROT_CONTENT_EXT_STR, exts);
542 bool atStart = !strncmp(PROT_CONTENT_EXT_STR " ", exts, cropExtLen+1);
543 bool atEnd = (cropExtLen+1) < extsLen
544 && !strcmp(" " PROT_CONTENT_EXT_STR,
545 exts + extsLen - (cropExtLen+1));
546 bool inMiddle = strstr(exts, " " PROT_CONTENT_EXT_STR " ");
547 return equal || atStart || atEnd || inMiddle;
548 }
549 #endif // SK_GL
550
can_import_protected_content(GrDirectContext * dContext)551 static bool can_import_protected_content(GrDirectContext* dContext) {
552 if (GrBackendApi::kOpenGL == dContext->backend()) {
553 #ifdef SK_GL
554 // Only compute whether the extension is present once the first time this
555 // function is called.
556 static bool hasIt = can_import_protected_content_eglimpl();
557 return hasIt;
558 #endif // SK_GL
559 } else if (GrBackendApi::kVulkan == dContext->backend()) {
560 #ifdef SK_VULKAN
561 return static_cast<GrVkGpu*>(dContext->priv().getGpu())->protectedContext();
562 #endif // SK_VULKAN
563 }
564 return false;
565 }
566
MakeBackendTexture(GrDirectContext * dContext,AHardwareBuffer * hardwareBuffer,int width,int height,DeleteImageProc * deleteProc,UpdateImageProc * updateProc,TexImageCtx * imageCtx,bool isProtectedContent,const GrBackendFormat & backendFormat,bool isRenderable,bool fromAndroidWindow)567 GrBackendTexture MakeBackendTexture(GrDirectContext* dContext,
568 AHardwareBuffer* hardwareBuffer,
569 int width, int height,
570 DeleteImageProc* deleteProc,
571 UpdateImageProc* updateProc,
572 TexImageCtx* imageCtx,
573 bool isProtectedContent,
574 const GrBackendFormat& backendFormat,
575 bool isRenderable,
576 bool fromAndroidWindow) {
577 SkASSERT(dContext);
578 if (!dContext || dContext->abandoned()) {
579 return GrBackendTexture();
580 }
581 bool createProtectedImage = isProtectedContent && can_import_protected_content(dContext);
582
583 if (GrBackendApi::kOpenGL == dContext->backend()) {
584 #ifdef SK_GL
585 return make_gl_backend_texture(dContext, hardwareBuffer, width, height, deleteProc,
586 updateProc, imageCtx, createProtectedImage, backendFormat,
587 isRenderable);
588 #else
589 return GrBackendTexture();
590 #endif // SK_GL
591 } else {
592 SkASSERT(GrBackendApi::kVulkan == dContext->backend());
593 #ifdef SK_VULKAN
594 return make_vk_backend_texture(dContext, hardwareBuffer, width, height, deleteProc,
595 updateProc, imageCtx, createProtectedImage, backendFormat,
596 isRenderable, fromAndroidWindow);
597 #else
598 return GrBackendTexture();
599 #endif // SK_VULKAN
600 }
601 }
602
603 } // GrAHardwareBufferUtils
604
605 #endif
606