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