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
38 namespace GrAHardwareBufferUtils {
39
GetSkColorTypeFromBufferFormat(uint32_t bufferFormat)40 SkColorType 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
GetBackendFormat(GrDirectContext * dContext,AHardwareBuffer * hardwareBuffer,uint32_t bufferFormat,bool requireKnownFormat)63 GrBackendFormat 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
160 class GLTextureHelper {
161 public:
GLTextureHelper(GrGLuint texID,EGLImageKHR image,EGLDisplay display,GrGLuint texTarget)162 GLTextureHelper(GrGLuint texID, EGLImageKHR image, EGLDisplay display, GrGLuint texTarget)
163 : fTexID(texID)
164 , fImage(image)
165 , fDisplay(display)
166 , fTexTarget(texTarget) { }
~GLTextureHelper()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
174 private:
175 GrGLuint fTexID;
176 EGLImageKHR fImage;
177 EGLDisplay fDisplay;
178 GrGLuint fTexTarget;
179 };
180
rebind(GrDirectContext * dContext)181 void 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
delete_gl_texture(void * context)197 void delete_gl_texture(void* context) {
198 GLTextureHelper* cleanupHelper = static_cast<GLTextureHelper*>(context);
199 delete cleanupHelper;
200 }
201
update_gl_texture(void * context,GrDirectContext * dContext)202 void update_gl_texture(void* context, GrDirectContext* dContext) {
203 GLTextureHelper* cleanupHelper = static_cast<GLTextureHelper*>(context);
204 cleanupHelper->rebind(dContext);
205 }
206
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)207 static 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
272 class VulkanCleanupHelper {
273 public:
VulkanCleanupHelper(GrVkGpu * gpu,VkImage image,VkDeviceMemory memory)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) {}
~VulkanCleanupHelper()280 ~VulkanCleanupHelper() {
281 fDestroyImage(fDevice, fImage, nullptr);
282 fFreeMemory(fDevice, fMemory, nullptr);
283 }
284 private:
285 VkDevice fDevice;
286 VkImage fImage;
287 VkDeviceMemory fMemory;
288 PFN_vkDestroyImage fDestroyImage;
289 PFN_vkFreeMemory fFreeMemory;
290 };
291
delete_vk_image(void * context)292 void delete_vk_image(void* context) {
293 VulkanCleanupHelper* cleanupHelper = static_cast<VulkanCleanupHelper*>(context);
294 delete cleanupHelper;
295 }
296
update_vk_image(void * context,GrDirectContext * dContext)297 void update_vk_image(void* context, GrDirectContext* dContext) {
298 // no op
299 }
300
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)301 static 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 uint32_t heapIndex = 0;
420 bool foundHeap = false;
421 VK_CALL(GetPhysicalDeviceMemoryProperties2(physicalDevice, &phyDevMemProps));
422 uint32_t memTypeCnt = phyDevMemProps.memoryProperties.memoryTypeCount;
423 for (uint32_t i = 0; i < memTypeCnt && !foundHeap; ++i) {
424 if (hwbProps.memoryTypeBits & (1 << i)) {
425 const VkPhysicalDeviceMemoryProperties& pdmp = phyDevMemProps.memoryProperties;
426 uint32_t supportedFlags = pdmp.memoryTypes[i].propertyFlags &
427 VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
428 if (supportedFlags == VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) {
429 typeIndex = i;
430 heapIndex = pdmp.memoryTypes[i].heapIndex;
431 foundHeap = true;
432 }
433 }
434 }
435 if (!foundHeap) {
436 VK_CALL(DestroyImage(device, image, nullptr));
437 return GrBackendTexture();
438 }
439
440 VkImportAndroidHardwareBufferInfoANDROID hwbImportInfo;
441 hwbImportInfo.sType = VK_STRUCTURE_TYPE_IMPORT_ANDROID_HARDWARE_BUFFER_INFO_ANDROID;
442 hwbImportInfo.pNext = nullptr;
443 hwbImportInfo.buffer = hardwareBuffer;
444
445 VkMemoryDedicatedAllocateInfo dedicatedAllocInfo;
446 dedicatedAllocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO;
447 dedicatedAllocInfo.pNext = &hwbImportInfo;
448 dedicatedAllocInfo.image = image;
449 dedicatedAllocInfo.buffer = VK_NULL_HANDLE;
450
451 VkMemoryAllocateInfo allocInfo = {
452 VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, // sType
453 &dedicatedAllocInfo, // pNext
454 hwbProps.allocationSize, // allocationSize
455 typeIndex, // memoryTypeIndex
456 };
457
458 VkDeviceMemory memory;
459
460 err = VK_CALL(AllocateMemory(device, &allocInfo, nullptr, &memory));
461 if (VK_SUCCESS != err) {
462 VK_CALL(DestroyImage(device, image, nullptr));
463 return GrBackendTexture();
464 }
465
466 VkBindImageMemoryInfo bindImageInfo;
467 bindImageInfo.sType = VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO;
468 bindImageInfo.pNext = nullptr;
469 bindImageInfo.image = image;
470 bindImageInfo.memory = memory;
471 bindImageInfo.memoryOffset = 0;
472
473 err = VK_CALL(BindImageMemory2(device, 1, &bindImageInfo));
474 if (VK_SUCCESS != err) {
475 VK_CALL(DestroyImage(device, image, nullptr));
476 VK_CALL(FreeMemory(device, memory, nullptr));
477 return GrBackendTexture();
478 }
479
480 GrVkAlloc alloc;
481 alloc.fMemory = memory;
482 alloc.fOffset = 0;
483 alloc.fSize = hwbProps.allocationSize;
484 alloc.fFlags = 0;
485
486 GrVkImageInfo imageInfo;
487 imageInfo.fImage = image;
488 imageInfo.fAlloc = alloc;
489 imageInfo.fImageTiling = tiling;
490 imageInfo.fImageLayout = VK_IMAGE_LAYOUT_UNDEFINED;
491 imageInfo.fFormat = format;
492 imageInfo.fLevelCount = 1;
493 // TODO: This should possibly be VK_QUEUE_FAMILY_FOREIGN_EXT but current Adreno devices do not
494 // support that extension. Or if we know the source of the AHardwareBuffer is not from a
495 // "foreign" device we can leave them as external.
496 imageInfo.fCurrentQueueFamily = VK_QUEUE_FAMILY_EXTERNAL;
497 imageInfo.fProtected = isProtectedContent ? GrProtected::kYes : GrProtected::kNo;
498 imageInfo.fYcbcrConversionInfo = *ycbcrConversion;
499 imageInfo.fSharingMode = imageCreateInfo.sharingMode;
500
501 *deleteProc = delete_vk_image;
502 *updateProc = update_vk_image;
503 *imageCtx = new VulkanCleanupHelper(gpu, image, memory);
504
505 return GrBackendTexture(width, height, imageInfo);
506 }
507 #endif
508
can_import_protected_content_eglimpl()509 static bool can_import_protected_content_eglimpl() {
510 EGLDisplay dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
511 const char* exts = eglQueryString(dpy, EGL_EXTENSIONS);
512 size_t cropExtLen = strlen(PROT_CONTENT_EXT_STR);
513 size_t extsLen = strlen(exts);
514 bool equal = !strcmp(PROT_CONTENT_EXT_STR, exts);
515 bool atStart = !strncmp(PROT_CONTENT_EXT_STR " ", exts, cropExtLen+1);
516 bool atEnd = (cropExtLen+1) < extsLen
517 && !strcmp(" " PROT_CONTENT_EXT_STR,
518 exts + extsLen - (cropExtLen+1));
519 bool inMiddle = strstr(exts, " " PROT_CONTENT_EXT_STR " ");
520 return equal || atStart || atEnd || inMiddle;
521 }
522
can_import_protected_content(GrDirectContext * dContext)523 static bool can_import_protected_content(GrDirectContext* dContext) {
524 if (GrBackendApi::kOpenGL == dContext->backend()) {
525 // Only compute whether the extension is present once the first time this
526 // function is called.
527 static bool hasIt = can_import_protected_content_eglimpl();
528 return hasIt;
529 } else if (GrBackendApi::kVulkan == dContext->backend()) {
530 #ifdef SK_VULKAN
531 return static_cast<GrVkGpu*>(dContext->priv().getGpu())->protectedContext();
532 #endif
533 }
534 return false;
535 }
536
MakeBackendTexture(GrDirectContext * dContext,AHardwareBuffer * hardwareBuffer,int width,int height,DeleteImageProc * deleteProc,UpdateImageProc * updateProc,TexImageCtx * imageCtx,bool isProtectedContent,const GrBackendFormat & backendFormat,bool isRenderable)537 GrBackendTexture MakeBackendTexture(GrDirectContext* dContext, AHardwareBuffer* hardwareBuffer,
538 int width, int height,
539 DeleteImageProc* deleteProc,
540 UpdateImageProc* updateProc,
541 TexImageCtx* imageCtx,
542 bool isProtectedContent,
543 const GrBackendFormat& backendFormat,
544 bool isRenderable) {
545 SkASSERT(dContext);
546 if (!dContext || dContext->abandoned()) {
547 return GrBackendTexture();
548 }
549 bool createProtectedImage = isProtectedContent && can_import_protected_content(dContext);
550
551 if (GrBackendApi::kOpenGL == dContext->backend()) {
552 return make_gl_backend_texture(dContext, hardwareBuffer, width, height, deleteProc,
553 updateProc, imageCtx, createProtectedImage, backendFormat,
554 isRenderable);
555 } else {
556 SkASSERT(GrBackendApi::kVulkan == dContext->backend());
557 #ifdef SK_VULKAN
558 return make_vk_backend_texture(dContext, hardwareBuffer, width, height, deleteProc,
559 updateProc, imageCtx, createProtectedImage, backendFormat,
560 isRenderable);
561 #else
562 return GrBackendTexture();
563 #endif
564 }
565 }
566
567 } // GrAHardwareBufferUtils
568
569 #endif
570
571