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/GrDirectContext.h"
23#include "include/gpu/gl/GrGLTypes.h"
24#include "src/gpu/GrDirectContextPriv.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(GrDirectContext* dContext, AHardwareBuffer* hardwareBuffer,
64                                 uint32_t bufferFormat, bool requireKnownFormat) {
65    GrBackendApi backend = dContext->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*>(dContext->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(GrDirectContext*);
173
174private:
175    GrGLuint    fTexID;
176    EGLImageKHR fImage;
177    EGLDisplay  fDisplay;
178    GrGLuint    fTexTarget;
179};
180
181void GLTextureHelper::rebind(GrDirectContext* dContext) {
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    dContext->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, GrDirectContext* dContext) {
203    GLTextureHelper* cleanupHelper = static_cast<GLTextureHelper*>(context);
204    cleanupHelper->rebind(dContext);
205}
206
207static GrBackendTexture make_gl_backend_texture(
208        GrDirectContext* dContext, 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    dContext->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, GrDirectContext* dContext) {
298    // no op
299}
300
301static GrBackendTexture make_vk_backend_texture(
302        GrDirectContext* dContext, 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(dContext->backend() == GrBackendApi::kVulkan);
311    GrVkGpu* gpu = static_cast<GrVkGpu*>(dContext->priv().getGpu());
312
313    SkASSERT(!isProtectedContent || gpu->protectedContext());
314
315    VkPhysicalDevice physicalDevice = gpu->physicalDevice();
316    VkDevice device = gpu->device();
317
318    SkASSERT(gpu);
319
320    if (!gpu->vkCaps().supportsAndroidHWBExternalMemory()) {
321        return GrBackendTexture();
322    }
323
324    VkFormat format;
325    SkAssertResult(backendFormat.asVkFormat(&format));
326
327    VkResult err;
328
329    VkAndroidHardwareBufferFormatPropertiesANDROID hwbFormatProps;
330    hwbFormatProps.sType = VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_FORMAT_PROPERTIES_ANDROID;
331    hwbFormatProps.pNext = nullptr;
332
333    VkAndroidHardwareBufferPropertiesANDROID hwbProps;
334    hwbProps.sType = VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_PROPERTIES_ANDROID;
335    hwbProps.pNext = &hwbFormatProps;
336
337    err = VK_CALL(GetAndroidHardwareBufferProperties(device, hardwareBuffer, &hwbProps));
338    if (VK_SUCCESS != err) {
339        return GrBackendTexture();
340    }
341
342    VkExternalFormatANDROID externalFormat;
343    externalFormat.sType = VK_STRUCTURE_TYPE_EXTERNAL_FORMAT_ANDROID;
344    externalFormat.pNext = nullptr;
345    externalFormat.externalFormat = 0;  // If this is zero it is as if we aren't using this struct.
346
347    const GrVkYcbcrConversionInfo* ycbcrConversion = backendFormat.getVkYcbcrConversionInfo();
348    if (!ycbcrConversion) {
349        return GrBackendTexture();
350    }
351
352    if (hwbFormatProps.format != VK_FORMAT_UNDEFINED) {
353        // TODO: We should not assume the transfer features here and instead should have a way for
354        // Ganesh's tracking of intenral images to report whether or not they support transfers.
355        SkASSERT(SkToBool(VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT & hwbFormatProps.formatFeatures) &&
356                 SkToBool(VK_FORMAT_FEATURE_TRANSFER_SRC_BIT & hwbFormatProps.formatFeatures) &&
357                 SkToBool(VK_FORMAT_FEATURE_TRANSFER_DST_BIT & hwbFormatProps.formatFeatures));
358        SkASSERT(!ycbcrConversion->isValid());
359    } else {
360        SkASSERT(ycbcrConversion->isValid());
361        // We have an external only format
362        SkASSERT(SkToBool(VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT & hwbFormatProps.formatFeatures));
363        SkASSERT(format == VK_FORMAT_UNDEFINED);
364        SkASSERT(hwbFormatProps.externalFormat == ycbcrConversion->fExternalFormat);
365        externalFormat.externalFormat = hwbFormatProps.externalFormat;
366    }
367    SkASSERT(format == hwbFormatProps.format);
368
369    const VkExternalMemoryImageCreateInfo externalMemoryImageInfo{
370            VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO,                 // sType
371            &externalFormat,                                                     // pNext
372            VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID,  // handleTypes
373    };
374    VkImageUsageFlags usageFlags = VK_IMAGE_USAGE_SAMPLED_BIT;
375    if (format != VK_FORMAT_UNDEFINED) {
376        usageFlags = usageFlags |
377                VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
378                VK_IMAGE_USAGE_TRANSFER_DST_BIT;
379        if (isRenderable) {
380            usageFlags = usageFlags | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
381        }
382    }
383
384    // TODO: Check the supported tilings vkGetPhysicalDeviceImageFormatProperties2 to see if we have
385    // to use linear. Add better linear support throughout Ganesh.
386    VkImageTiling tiling = VK_IMAGE_TILING_OPTIMAL;
387
388    VkImageCreateFlags flags = isProtectedContent ? VK_IMAGE_CREATE_PROTECTED_BIT : 0;
389
390    const VkImageCreateInfo imageCreateInfo = {
391        VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,         // sType
392        &externalMemoryImageInfo,                    // pNext
393        flags,                                       // VkImageCreateFlags
394        VK_IMAGE_TYPE_2D,                            // VkImageType
395        format,                                      // VkFormat
396        { (uint32_t)width, (uint32_t)height, 1 },    // VkExtent3D
397        1,                                           // mipLevels
398        1,                                           // arrayLayers
399        VK_SAMPLE_COUNT_1_BIT,                       // samples
400        tiling,                                      // VkImageTiling
401        usageFlags,                                  // VkImageUsageFlags
402        VK_SHARING_MODE_EXCLUSIVE,                   // VkSharingMode
403        0,                                           // queueFamilyCount
404        0,                                           // pQueueFamilyIndices
405        VK_IMAGE_LAYOUT_UNDEFINED,                   // initialLayout
406    };
407
408    VkImage image;
409    err = VK_CALL(CreateImage(device, &imageCreateInfo, nullptr, &image));
410    if (VK_SUCCESS != err) {
411        return GrBackendTexture();
412    }
413
414    VkPhysicalDeviceMemoryProperties2 phyDevMemProps;
415    phyDevMemProps.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PROPERTIES_2;
416    phyDevMemProps.pNext = nullptr;
417
418    uint32_t typeIndex = 0;
419    bool foundHeap = false;
420    VK_CALL(GetPhysicalDeviceMemoryProperties2(physicalDevice, &phyDevMemProps));
421    uint32_t memTypeCnt = phyDevMemProps.memoryProperties.memoryTypeCount;
422    for (uint32_t i = 0; i < memTypeCnt && !foundHeap; ++i) {
423        if (hwbProps.memoryTypeBits & (1 << i)) {
424            const VkPhysicalDeviceMemoryProperties& pdmp = phyDevMemProps.memoryProperties;
425            uint32_t supportedFlags = pdmp.memoryTypes[i].propertyFlags &
426                    VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
427            if (supportedFlags == VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) {
428                typeIndex = i;
429                foundHeap = true;
430            }
431        }
432    }
433    if (!foundHeap) {
434        VK_CALL(DestroyImage(device, image, nullptr));
435        return GrBackendTexture();
436    }
437
438    VkImportAndroidHardwareBufferInfoANDROID hwbImportInfo;
439    hwbImportInfo.sType = VK_STRUCTURE_TYPE_IMPORT_ANDROID_HARDWARE_BUFFER_INFO_ANDROID;
440    hwbImportInfo.pNext = nullptr;
441    hwbImportInfo.buffer = hardwareBuffer;
442
443    VkMemoryDedicatedAllocateInfo dedicatedAllocInfo;
444    dedicatedAllocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO;
445    dedicatedAllocInfo.pNext = &hwbImportInfo;
446    dedicatedAllocInfo.image = image;
447    dedicatedAllocInfo.buffer = VK_NULL_HANDLE;
448
449    VkMemoryAllocateInfo allocInfo = {
450        VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,      // sType
451        &dedicatedAllocInfo,                         // pNext
452        hwbProps.allocationSize,                     // allocationSize
453        typeIndex,                                   // memoryTypeIndex
454    };
455
456    VkDeviceMemory memory;
457
458    err = VK_CALL(AllocateMemory(device, &allocInfo, nullptr, &memory));
459    if (VK_SUCCESS != err) {
460        VK_CALL(DestroyImage(device, image, nullptr));
461        return GrBackendTexture();
462    }
463
464    VkBindImageMemoryInfo bindImageInfo;
465    bindImageInfo.sType = VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO;
466    bindImageInfo.pNext = nullptr;
467    bindImageInfo.image = image;
468    bindImageInfo.memory = memory;
469    bindImageInfo.memoryOffset = 0;
470
471    err = VK_CALL(BindImageMemory2(device, 1, &bindImageInfo));
472    if (VK_SUCCESS != err) {
473        VK_CALL(DestroyImage(device, image, nullptr));
474        VK_CALL(FreeMemory(device, memory, nullptr));
475        return GrBackendTexture();
476    }
477
478    GrVkAlloc alloc;
479    alloc.fMemory = memory;
480    alloc.fOffset = 0;
481    alloc.fSize = hwbProps.allocationSize;
482    alloc.fFlags = 0;
483
484    GrVkImageInfo imageInfo;
485    imageInfo.fImage = image;
486    imageInfo.fAlloc = alloc;
487    imageInfo.fImageTiling = tiling;
488    imageInfo.fImageLayout = VK_IMAGE_LAYOUT_UNDEFINED;
489    imageInfo.fFormat = format;
490    imageInfo.fLevelCount = 1;
491    // TODO: This should possibly be VK_QUEUE_FAMILY_FOREIGN_EXT but current Adreno devices do not
492    // support that extension. Or if we know the source of the AHardwareBuffer is not from a
493    // "foreign" device we can leave them as external.
494    imageInfo.fCurrentQueueFamily = VK_QUEUE_FAMILY_EXTERNAL;
495    imageInfo.fProtected = isProtectedContent ? GrProtected::kYes : GrProtected::kNo;
496    imageInfo.fYcbcrConversionInfo = *ycbcrConversion;
497    imageInfo.fSharingMode = imageCreateInfo.sharingMode;
498
499    *deleteProc = delete_vk_image;
500    *updateProc = update_vk_image;
501    *imageCtx = new VulkanCleanupHelper(gpu, image, memory);
502
503    return GrBackendTexture(width, height, imageInfo);
504}
505#endif
506
507static bool can_import_protected_content_eglimpl() {
508    EGLDisplay dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
509    const char* exts = eglQueryString(dpy, EGL_EXTENSIONS);
510    size_t cropExtLen = strlen(PROT_CONTENT_EXT_STR);
511    size_t extsLen = strlen(exts);
512    bool equal = !strcmp(PROT_CONTENT_EXT_STR, exts);
513    bool atStart = !strncmp(PROT_CONTENT_EXT_STR " ", exts, cropExtLen+1);
514    bool atEnd = (cropExtLen+1) < extsLen
515                  && !strcmp(" " PROT_CONTENT_EXT_STR,
516                  exts + extsLen - (cropExtLen+1));
517    bool inMiddle = strstr(exts, " " PROT_CONTENT_EXT_STR " ");
518    return equal || atStart || atEnd || inMiddle;
519}
520
521static bool can_import_protected_content(GrDirectContext* dContext) {
522    if (GrBackendApi::kOpenGL == dContext->backend()) {
523        // Only compute whether the extension is present once the first time this
524        // function is called.
525        static bool hasIt = can_import_protected_content_eglimpl();
526        return hasIt;
527    } else if (GrBackendApi::kVulkan == dContext->backend()) {
528#ifdef SK_VULKAN
529        return static_cast<GrVkGpu*>(dContext->priv().getGpu())->protectedContext();
530#endif
531    }
532    return false;
533}
534
535GrBackendTexture MakeBackendTexture(GrDirectContext* dContext, AHardwareBuffer* hardwareBuffer,
536                                    int width, int height,
537                                    DeleteImageProc* deleteProc,
538                                    UpdateImageProc* updateProc,
539                                    TexImageCtx* imageCtx,
540                                    bool isProtectedContent,
541                                    const GrBackendFormat& backendFormat,
542                                    bool isRenderable) {
543    SkASSERT(dContext);
544    if (!dContext || dContext->abandoned()) {
545        return GrBackendTexture();
546    }
547    bool createProtectedImage = isProtectedContent && can_import_protected_content(dContext);
548
549    if (GrBackendApi::kOpenGL == dContext->backend()) {
550        return make_gl_backend_texture(dContext, hardwareBuffer, width, height, deleteProc,
551                                       updateProc, imageCtx, createProtectedImage, backendFormat,
552                                       isRenderable);
553    } else {
554        SkASSERT(GrBackendApi::kVulkan == dContext->backend());
555#ifdef SK_VULKAN
556        return make_vk_backend_texture(dContext, hardwareBuffer, width, height, deleteProc,
557                                       updateProc, imageCtx, createProtectedImage, backendFormat,
558                                       isRenderable);
559#else
560        return GrBackendTexture();
561#endif
562    }
563}
564
565} // GrAHardwareBufferUtils
566
567#endif
568
569