Flutter Engine
The Flutter Engine
AHardwareBufferVk.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2023 Google LLC
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
9
10#if defined(SK_BUILD_FOR_ANDROID) && __ANDROID_API__ >= 26
11
21
23
24#define VK_CALL(X) gpu->vkInterface()->fFunctions.f##X
25
26namespace GrAHardwareBufferUtils {
27
28GrBackendFormat GetVulkanBackendFormat(GrDirectContext* dContext, AHardwareBuffer* hardwareBuffer,
29 uint32_t bufferFormat, bool requireKnownFormat) {
30 GrBackendApi backend = dContext->backend();
32 return GrBackendFormat();
33 }
34
35 VkFormat bufferVkFormat = VK_FORMAT_UNDEFINED;
36 switch (bufferFormat) {
37 case AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM: {
38 bufferVkFormat = VK_FORMAT_R8G8B8A8_UNORM;
39 break;
40 }
41 case AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT: {
42 bufferVkFormat = VK_FORMAT_R16G16B16A16_SFLOAT;
43 break;
44 }
45 case AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM: {
46 bufferVkFormat = VK_FORMAT_R5G6B5_UNORM_PACK16;
47 break;
48 }
49 case AHARDWAREBUFFER_FORMAT_R10G10B10A2_UNORM: {
51 break;
52 }
53 case AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM: {
54 bufferVkFormat = VK_FORMAT_R8G8B8A8_UNORM;
55 break;
56 }
57 case AHARDWAREBUFFER_FORMAT_R8G8B8_UNORM: {
58 bufferVkFormat = VK_FORMAT_R8G8B8_UNORM;
59 break;
60 }
61#if __ANDROID_API__ >= 33
62 case AHARDWAREBUFFER_FORMAT_R8_UNORM: {
63 bufferVkFormat = VK_FORMAT_R8_UNORM;
64 break;
65 }
66#endif
67 default: {
68 if (requireKnownFormat) {
69 return GrBackendFormat();
70 }
71 break;
72 }
73 }
74
75 GrVkGpu* gpu = static_cast<GrVkGpu*>(dContext->priv().getGpu());
76 SkASSERT(gpu);
77
78 if (bufferVkFormat != VK_FORMAT_UNDEFINED) {
79 // Check to make sure the associated VkFormat has the necessary format features. If not,
80 // default to using an external format (set the VkFormat as undefined).
81 // TODO: When creating a GrBackendFormat with a VkFormat that is not VK_FORMAT_UNDEFINED, we
82 // currently assume that the VkFormat's VkFormatFeatureFlags contain
83 // VK_FORMAT_FEATURE_TRANSFER_SRC_BIT and VK_FORMAT_FEATURE_TRANSFER_DST_BIT.
84 if (gpu->vkCaps().isVkFormatTexturable(bufferVkFormat)) {
85 return GrBackendFormats::MakeVk(bufferVkFormat);
86 }
87 bufferVkFormat = VK_FORMAT_UNDEFINED;
88 }
89 // If there is no associated VkFormat (or it does not support the necessary features) and
90 // requireKnownFormat = false, then import using an external format.
91 VkDevice device = gpu->device();
92
94 return GrBackendFormat();
95 }
96
99 if (!GetAHardwareBufferProperties(
100 &hwbFormatProps, &hwbProps, gpu->vkInterface(), hardwareBuffer, device)) {
101 return GrBackendFormat();
102 }
103
104 skgpu::VulkanYcbcrConversionInfo ycbcrConversion;
105 GetYcbcrConversionInfoFromFormatProps(&ycbcrConversion, hwbFormatProps);
106
107 return GrBackendFormats::MakeVk(ycbcrConversion);
108}
109
110class VulkanCleanupHelper {
111public:
112 VulkanCleanupHelper(GrVkGpu* gpu, VkImage image, VkDeviceMemory memory)
113 : fDevice(gpu->device())
114 , fImage(image)
115 , fMemory(memory)
116 , fDestroyImage(gpu->vkInterface()->fFunctions.fDestroyImage)
117 , fFreeMemory(gpu->vkInterface()->fFunctions.fFreeMemory) {}
118 ~VulkanCleanupHelper() {
119 fDestroyImage(fDevice, fImage, nullptr);
120 fFreeMemory(fDevice, fMemory, nullptr);
121 }
122private:
123 VkDevice fDevice;
124 VkImage fImage;
125 VkDeviceMemory fMemory;
126 PFN_vkDestroyImage fDestroyImage;
127 PFN_vkFreeMemory fFreeMemory;
128};
129
130void delete_vk_image(void* context) {
131 VulkanCleanupHelper* cleanupHelper = static_cast<VulkanCleanupHelper*>(context);
132 delete cleanupHelper;
133}
134
135void update_vk_image(void* context, GrDirectContext* dContext) {
136 // no op
137}
138
139static GrBackendTexture make_vk_backend_texture(
140 GrDirectContext* dContext, AHardwareBuffer* hardwareBuffer,
141 int width, int height,
142 DeleteImageProc* deleteProc,
143 UpdateImageProc* updateProc,
144 TexImageCtx* imageCtx,
145 bool isProtectedContent,
146 const GrBackendFormat& grBackendFormat,
147 bool isRenderable,
148 bool fromAndroidWindow) {
149 SkASSERT(dContext->backend() == GrBackendApi::kVulkan);
150
151 GrVkGpu* gpu = static_cast<GrVkGpu*>(dContext->priv().getGpu());
152 SkASSERT(gpu);
153 SkASSERT(!isProtectedContent || gpu->protectedContext());
154
155 VkPhysicalDevice physicalDevice = gpu->physicalDevice();
156 VkDevice device = gpu->device();
157
159 return GrBackendTexture();
160 }
161
162 VkFormat grBackendVkFormat;
163 if (!GrBackendFormats::AsVkFormat(grBackendFormat, &grBackendVkFormat)) {
164 SkDebugf("AsVkFormat failed (valid: %d, backend: %u)",
165 grBackendFormat.isValid(),
166 (unsigned)grBackendFormat.backend());
167 return GrBackendTexture();
168 }
169 bool importAsExternalFormat = grBackendVkFormat == VK_FORMAT_UNDEFINED;
170
173 if (!skgpu::GetAHardwareBufferProperties(
174 &hwbFormatProps, &hwbProps, gpu->vkInterface(), hardwareBuffer, device)) {
175 return GrBackendTexture();
176 }
177 VkFormat hwbVkFormat = hwbFormatProps.format;
178
179 // We normally expect the hardware buffer format (hwbVkFormat) to be equivalent to ganesh's
180 // GrBackendFormat VkFormat (grBackendVkFormat). However, even if the hwbVkFormat is a defined
181 // format, we may choose to ignore that and instead import the AHardwareBuffer using an
182 // external format. For example, we would attempt to do this if the VkFormat doesn't support the
183 // necessary features. Thus, it is acceptable for hwbVkFormat to differ from grBackendVkFormat
184 // iff we are importing the AHardwareBuffer using an external format.
185 if (!importAsExternalFormat && hwbVkFormat != grBackendVkFormat) {
186 SkDebugf("Queried format not consistent with expected format; got: %d, expected: %d",
187 hwbVkFormat,
188 grBackendVkFormat);
189 return GrBackendTexture();
190 }
191
192 VkExternalFormatANDROID externalFormat;
194 externalFormat.pNext = nullptr;
195 externalFormat.externalFormat = 0; // If this is zero it is as if we aren't using this struct.
196
197 const skgpu::VulkanYcbcrConversionInfo* ycbcrConversion =
199 if (!ycbcrConversion) {
200 return GrBackendTexture();
201 }
202
203 // TODO: Check the supported tilings vkGetPhysicalDeviceImageFormatProperties2 to see if we have
204 // to use linear. Add better linear support throughout Ganesh.
206
207 if (isRenderable && (importAsExternalFormat || // cannot render to external formats
208 !gpu->vkCaps().isFormatRenderable(grBackendVkFormat, tiling))) {
209 SkDebugf("Renderable texture requested from an AHardwareBuffer which uses a "
210 "VkFormat that Skia cannot render to (VkFormat: %d).\n", grBackendVkFormat);
211 return GrBackendTexture();
212 }
213
214 if (importAsExternalFormat) {
215 if (!ycbcrConversion->isValid()) {
216 SkDebugf("YCbCr conversion must be valid when importing an AHardwareBuffer with an "
217 "external format");
218 return GrBackendTexture();
219 }
221 SkASSERT(hwbFormatProps.externalFormat == ycbcrConversion->fExternalFormat);
222 externalFormat.externalFormat = hwbFormatProps.externalFormat;
223 } else {
224 SkASSERT(!ycbcrConversion->isValid());
225 // Non-external formats are subject to format caps from VkPhysicalDeviceFormatProperties.
226 SkASSERT(gpu->vkCaps().isVkFormatTexturable(grBackendVkFormat));
227 // TODO: We currently assume that the provided VkFormat has transfer features
228 // (VK_FORMAT_FEATURE_TRANSFER_[SRC/DST]_BIT). Instead, we should have a way for Ganesh's
229 // tracking of intenral images to report whether or not they support transfers.
230 }
231
232 const VkExternalMemoryImageCreateInfo externalMemoryImageInfo{
234 &externalFormat, // pNext
236 };
237
239 if (!importAsExternalFormat) {
240 usageFlags = usageFlags |
243 if (isRenderable) {
244 usageFlags = usageFlags | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
245 }
246 }
247
248 VkImageCreateFlags flags = isProtectedContent ? VK_IMAGE_CREATE_PROTECTED_BIT : 0;
249
250 const VkImageCreateInfo imageCreateInfo = {
252 &externalMemoryImageInfo, // pNext
253 flags, // VkImageCreateFlags
254 VK_IMAGE_TYPE_2D, // VkImageType
255 grBackendVkFormat, // VkFormat
256 { (uint32_t)width, (uint32_t)height, 1 }, // VkExtent3D
257 1, // mipLevels
258 1, // arrayLayers
259 VK_SAMPLE_COUNT_1_BIT, // samples
260 tiling, // VkImageTiling
261 usageFlags, // VkImageUsageFlags
262 VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode
263 0, // queueFamilyCount
264 nullptr, // pQueueFamilyIndices
265 VK_IMAGE_LAYOUT_UNDEFINED, // initialLayout
266 };
267
268 VkImage image;
269 VkResult err;
270 err = VK_CALL(CreateImage(device, &imageCreateInfo, nullptr, &image));
271 if (VK_SUCCESS != err) {
272 return GrBackendTexture();
273 }
274
277 phyDevMemProps.pNext = nullptr;
278 VK_CALL(GetPhysicalDeviceMemoryProperties2(physicalDevice, &phyDevMemProps));
279
280 skgpu::VulkanAlloc alloc;
281 if (!skgpu::AllocateAndBindImageMemory(&alloc, image, phyDevMemProps, hwbProps, hardwareBuffer,
282 gpu->vkInterface(), device)) {
283 VK_CALL(DestroyImage(device, image, nullptr));
284 return GrBackendTexture();
285 }
286
287 GrVkImageInfo imageInfo;
288 imageInfo.fImage = image;
289 imageInfo.fAlloc = alloc;
290 imageInfo.fImageTiling = tiling;
292 imageInfo.fFormat = grBackendVkFormat;
293 imageInfo.fLevelCount = 1;
294 // TODO: This should possibly be VK_QUEUE_FAMILY_FOREIGN_EXT but current Adreno devices do not
295 // support that extension. Or if we know the source of the AHardwareBuffer is not from a
296 // "foreign" device we can leave them as external.
298 imageInfo.fProtected = isProtectedContent ? GrProtected::kYes : GrProtected::kNo;
299 imageInfo.fYcbcrConversionInfo = *ycbcrConversion;
300 imageInfo.fSharingMode = imageCreateInfo.sharingMode;
301#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
302 imageInfo.fPartOfSwapchainOrAndroidWindow = fromAndroidWindow;
303#endif
304
305 *deleteProc = delete_vk_image;
306 *updateProc = update_vk_image;
307 *imageCtx = new VulkanCleanupHelper(gpu, image, alloc.fMemory);
308
309 return GrBackendTextures::MakeVk(width, height, imageInfo);
310}
311
312static bool can_import_protected_content(GrDirectContext* dContext) {
313 SkASSERT(GrBackendApi::kVulkan == dContext->backend());
314 return static_cast<GrVkGpu*>(dContext->priv().getGpu())->protectedContext();
315}
316
317GrBackendTexture MakeVulkanBackendTexture(GrDirectContext* dContext,
318 AHardwareBuffer* hardwareBuffer,
319 int width, int height,
320 DeleteImageProc* deleteProc,
321 UpdateImageProc* updateProc,
322 TexImageCtx* imageCtx,
323 bool isProtectedContent,
324 const GrBackendFormat& backendFormat,
325 bool isRenderable,
326 bool fromAndroidWindow) {
327 SkASSERT(dContext);
328 if (!dContext || dContext->abandoned()) {
329 return GrBackendTexture();
330 }
331
332 if (GrBackendApi::kVulkan != dContext->backend()) {
333 return GrBackendTexture();
334 }
335
336 if (isProtectedContent && !can_import_protected_content(dContext)) {
337 return GrBackendTexture();
338 }
339
340 return make_vk_backend_texture(dContext, hardwareBuffer, width, height, deleteProc,
341 updateProc, imageCtx, isProtectedContent, backendFormat,
342 isRenderable, fromAndroidWindow);
343}
344
345} // namespace GrAHardwareBufferUtils
346
347#endif
const char * backend
struct AHardwareBuffer AHardwareBuffer
GrBackendApi
Definition: GrTypes.h:95
#define VK_CALL(GPU, X)
Definition: GrVkBuffer.cpp:19
#define SkASSERT(cond)
Definition: SkAssert.h:116
void SK_SPI SkDebugf(const char format[],...) SK_PRINTF_LIKE(1
static constexpr bool SkToBool(const T &x)
Definition: SkTo.h:35
GrBackendApi backend() const
bool isValid() const
SK_API GrBackendApi backend() const
bool abandoned() override
GrDirectContextPriv priv()
bool isVkFormatTexturable(VkFormat) const
Definition: GrVkCaps.cpp:1566
bool isFormatRenderable(const GrBackendFormat &format, int sampleCount) const override
Definition: GrVkCaps.cpp:1587
bool supportsAndroidHWBExternalMemory() const
Definition: GrVkCaps.h:150
const GrVkCaps & vkCaps() const
Definition: GrVkGpu.h:61
const skgpu::VulkanInterface * vkInterface() const
Definition: GrVkGpu.h:60
VkDevice device() const
Definition: GrVkGpu.h:71
VkPhysicalDevice physicalDevice() const
Definition: GrVkGpu.h:70
bool protectedContext() const
Definition: GrVkGpu.h:81
VkDevice device
Definition: main.cc:53
FlutterSemanticsFlag flags
SK_API const skgpu::VulkanYcbcrConversionInfo * GetVkYcbcrConversionInfo(const GrBackendFormat &)
SK_API bool AsVkFormat(const GrBackendFormat &, VkFormat *)
SK_API GrBackendFormat MakeVk(VkFormat format, bool willUseDRMFormatModifiers=false)
SK_API GrBackendTexture MakeVk(int width, int height, const GrVkImageInfo &, std::string_view label={})
sk_sp< const SkImage > image
Definition: SkRecords.h:269
int32_t height
int32_t width
VkImage fImage
Definition: GrVkTypes.h:26
VkSharingMode fSharingMode
Definition: GrVkTypes.h:37
skgpu::VulkanAlloc fAlloc
Definition: GrVkTypes.h:27
uint32_t fCurrentQueueFamily
Definition: GrVkTypes.h:34
VkFormat fFormat
Definition: GrVkTypes.h:30
skgpu::Protected fProtected
Definition: GrVkTypes.h:35
uint32_t fLevelCount
Definition: GrVkTypes.h:33
skgpu::VulkanYcbcrConversionInfo fYcbcrConversionInfo
Definition: GrVkTypes.h:36
VkImageLayout fImageLayout
Definition: GrVkTypes.h:29
VkImageTiling fImageTiling
Definition: GrVkTypes.h:28
VkStructureType sType
VkSharingMode sharingMode
Definition: vulkan_core.h:3445
VkDeviceMemory fMemory
Definition: VulkanTypes.h:39
@ VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT
Definition: vulkan_core.h:2259
@ VK_IMAGE_LAYOUT_UNDEFINED
Definition: vulkan_core.h:1331
void(VKAPI_PTR * PFN_vkFreeMemory)(VkDevice device, VkDeviceMemory memory, const VkAllocationCallbacks *pAllocator)
Definition: vulkan_core.h:4002
@ VK_SHARING_MODE_EXCLUSIVE
Definition: vulkan_core.h:1813
VkFlags VkImageUsageFlags
Definition: vulkan_core.h:2382
@ VK_IMAGE_CREATE_PROTECTED_BIT
Definition: vulkan_core.h:2320
VkImageTiling
Definition: vulkan_core.h:1766
@ VK_IMAGE_TILING_OPTIMAL
Definition: vulkan_core.h:1767
void(VKAPI_PTR * PFN_vkDestroyImage)(VkDevice device, VkImage image, const VkAllocationCallbacks *pAllocator)
Definition: vulkan_core.h:4035
@ VK_IMAGE_USAGE_TRANSFER_DST_BIT
Definition: vulkan_core.h:2353
@ VK_IMAGE_USAGE_SAMPLED_BIT
Definition: vulkan_core.h:2354
@ VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT
Definition: vulkan_core.h:2356
@ VK_IMAGE_USAGE_TRANSFER_SRC_BIT
Definition: vulkan_core.h:2352
@ VK_SAMPLE_COUNT_1_BIT
Definition: vulkan_core.h:2340
@ VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID
Definition: vulkan_core.h:5031
@ VK_IMAGE_TYPE_2D
Definition: vulkan_core.h:1775
VkFlags VkImageCreateFlags
Definition: vulkan_core.h:2337
VkResult
Definition: vulkan_core.h:140
@ VK_SUCCESS
Definition: vulkan_core.h:141
#define VK_QUEUE_FAMILY_EXTERNAL
Definition: vulkan_core.h:4927
VkFormat
Definition: vulkan_core.h:1458
@ VK_FORMAT_R8G8B8_UNORM
Definition: vulkan_core.h:1482
@ VK_FORMAT_R8_UNORM
Definition: vulkan_core.h:1468
@ VK_FORMAT_R5G6B5_UNORM_PACK16
Definition: vulkan_core.h:1463
@ VK_FORMAT_A2B10G10R10_UNORM_PACK32
Definition: vulkan_core.h:1523
@ VK_FORMAT_R8G8B8A8_UNORM
Definition: vulkan_core.h:1496
@ VK_FORMAT_UNDEFINED
Definition: vulkan_core.h:1459
@ VK_FORMAT_R16G16B16A16_SFLOAT
Definition: vulkan_core.h:1556
@ VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO
Definition: vulkan_core.h:216
@ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PROPERTIES_2
Definition: vulkan_core.h:277
@ VK_STRUCTURE_TYPE_EXTERNAL_FORMAT_ANDROID
Definition: vulkan_core.h:647
@ VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO
Definition: vulkan_core.h:305