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