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 | |
38 | namespace GrAHardwareBufferUtils { |
39 | |
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 | |
63 | GrBackendFormat 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 | |
160 | class GLTextureHelper { |
161 | public: |
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 | |
174 | private: |
175 | GrGLuint fTexID; |
176 | EGLImageKHR fImage; |
177 | EGLDisplay fDisplay; |
178 | GrGLuint fTexTarget; |
179 | }; |
180 | |
181 | void 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 | |
197 | void delete_gl_texture(void* context) { |
198 | GLTextureHelper* cleanupHelper = static_cast<GLTextureHelper*>(context); |
199 | delete cleanupHelper; |
200 | } |
201 | |
202 | void update_gl_texture(void* context, GrContext* grContext) { |
203 | GLTextureHelper* cleanupHelper = static_cast<GLTextureHelper*>(context); |
204 | cleanupHelper->rebind(grContext); |
205 | } |
206 | |
207 | static 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 |
272 | class VulkanCleanupHelper { |
273 | public: |
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 | } |
284 | private: |
285 | VkDevice fDevice; |
286 | VkImage fImage; |
287 | VkDeviceMemory fMemory; |
288 | PFN_vkDestroyImage fDestroyImage; |
289 | PFN_vkFreeMemory fFreeMemory; |
290 | }; |
291 | |
292 | void delete_vk_image(void* context) { |
293 | VulkanCleanupHelper* cleanupHelper = static_cast<VulkanCleanupHelper*>(context); |
294 | delete cleanupHelper; |
295 | } |
296 | |
297 | void update_vk_image(void* context, GrContext* grContext) { |
298 | // no op |
299 | } |
300 | |
301 | static 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 | |
498 | static 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 | |
512 | static 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 | |
522 | GrBackendTexture 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 | |