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