@@ -81,6 +81,9 @@ struct vk_gbm_backing_store {
81
81
* flutter using @ref vk_gbm_backing_store_fill_vulkan. Even when @ref vk_gbm_backing_store_present_kms is called,
82
82
* we don't set this to NULL.
83
83
*
84
+ * This is the framebuffer that will be presented on screen when @ref vk_gbm_backing_store_present_kms or
85
+ * @ref vk_gbm_backing_store_present_fbdev is called.
86
+ *
84
87
*/
85
88
struct locked_fb * front_fb ;
86
89
@@ -104,6 +107,7 @@ static void locked_fb_destroy(struct locked_fb *fb) {
104
107
105
108
store = fb -> store ;
106
109
fb -> store = NULL ;
110
+
107
111
#ifdef DEBUG
108
112
atomic_fetch_sub (& store -> n_locked_fbs , 1 );
109
113
#endif
@@ -137,11 +141,26 @@ static int vk_gbm_backing_store_present_fbdev(struct surface *s, const struct fl
137
141
static int vk_gbm_backing_store_fill (struct backing_store * store , FlutterBackingStore * fl_store );
138
142
static int vk_gbm_backing_store_queue_present (struct backing_store * store , const FlutterBackingStore * fl_store );
139
143
144
+ static bool is_srgb_format (VkFormat vk_format ) {
145
+ return vk_format == VK_FORMAT_R8G8B8A8_SRGB || vk_format == VK_FORMAT_B8G8R8A8_SRGB ;
146
+ }
147
+
148
+ static VkFormat srgb_to_unorm_format (VkFormat vk_format ) {
149
+ if (vk_format == VK_FORMAT_R8G8B8A8_SRGB ) {
150
+ return VK_FORMAT_R8G8B8A8_UNORM ;
151
+ } else if (vk_format == VK_FORMAT_B8G8R8A8_SRGB ) {
152
+ return VK_FORMAT_B8G8R8A8_UNORM ;
153
+ } else {
154
+ UNREACHABLE ();
155
+ }
156
+ }
157
+
140
158
static int fb_init (struct fb * fb , struct gbm_device * gbm_device , struct vk_renderer * renderer , int width , int height , enum pixfmt pixel_format , uint64_t drm_modifier ) {
141
159
PFN_vkGetMemoryFdPropertiesKHR get_memory_fd_props ;
142
160
VkSubresourceLayout layout ;
143
161
VkDeviceMemory img_device_memory ;
144
162
struct gbm_bo * bo ;
163
+ VkFormat vk_format ;
145
164
VkDevice device ;
146
165
VkResult ok ;
147
166
VkImage vkimg ;
@@ -151,19 +170,34 @@ static int fb_init(struct fb *fb, struct gbm_device *gbm_device, struct vk_rende
151
170
152
171
device = vk_renderer_get_device (renderer );
153
172
173
+ /// FIXME: Right now, using any _SRGB format (for example VK_FORMAT_B8G8R8A8_SRGB) will not work because
174
+ /// that'll break some assertions inside flutter / skia. (VK_FORMAT_B8G8R8A8_SRGB maps to GrColorType::kRGBA_8888_SRGB,
175
+ /// but some other part of flutter will use GrColorType::kRGBA_8888 so you'll get a mismatch at some point)
176
+ /// We're just converting the _SRGB to a _UNORM here, but I'm not really sure that's guaranteed to work.
177
+ /// (_UNORM can mean anything basically)
178
+
179
+ vk_format = get_pixfmt_info (pixel_format )-> vk_format ;
180
+ if (is_srgb_format (vk_format )) {
181
+ vk_format = srgb_to_unorm_format (vk_format );
182
+ }
183
+
154
184
ok = vkCreateImage (
155
185
device ,
156
186
& (VkImageCreateInfo ){
157
187
.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO ,
158
188
.flags = 0 ,
159
189
.imageType = VK_IMAGE_TYPE_2D ,
160
- .format = get_pixfmt_info ( pixel_format ) -> vk_format ,
190
+ .format = vk_format ,
161
191
.extent = { .width = width , .height = height , .depth = 1 },
162
192
.mipLevels = 1 ,
163
193
.arrayLayers = 1 ,
164
194
.samples = VK_SAMPLE_COUNT_1_BIT ,
195
+ // Tell vulkan that the tiling we want to use is determined by a DRM format modifier
196
+ // (in our case DRM_FORMAT_MOD_LINEAR, but could be something else as well, using a device-supported
197
+ // modifier is probably faster if that's possible)
165
198
.tiling = VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT ,
166
- .usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT ,
199
+ // These are the usage flags flutter will use too internally
200
+ .usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT ,
167
201
.sharingMode = VK_SHARING_MODE_EXCLUSIVE ,
168
202
.queueFamilyIndexCount = 0 ,
169
203
.pQueueFamilyIndices = 0 ,
@@ -180,6 +214,7 @@ static int fb_init(struct fb *fb, struct gbm_device *gbm_device, struct vk_rende
180
214
.pPlaneLayouts =
181
215
(VkSubresourceLayout [1 ]){
182
216
{
217
+ /// These are just dummy values, but they need to be there AFAIK
183
218
.offset = 0 ,
184
219
.size = 0 ,
185
220
.rowPitch = 0 ,
@@ -198,6 +233,8 @@ static int fb_init(struct fb *fb, struct gbm_device *gbm_device, struct vk_rende
198
233
return EIO ;
199
234
}
200
235
236
+ // We _should_ only have one plane in the linear case.
237
+ // Query the layout of that plane to check if it matches the GBM BOs layout.
201
238
vkGetImageSubresourceLayout (
202
239
device ,
203
240
vkimg ,
@@ -208,7 +245,8 @@ static int fb_init(struct fb *fb, struct gbm_device *gbm_device, struct vk_rende
208
245
},
209
246
& layout
210
247
);
211
-
248
+
249
+ // Create a GBM BO with the actual memory we're going to use
212
250
bo = gbm_bo_create_with_modifiers (
213
251
gbm_device ,
214
252
width ,
@@ -222,6 +260,7 @@ static int fb_init(struct fb *fb, struct gbm_device *gbm_device, struct vk_rende
222
260
goto fail_destroy_image ;
223
261
}
224
262
263
+ // Just some paranoid checks that the layout matches (had some issues with that initially)
225
264
if (gbm_bo_get_offset (bo , 0 ) != layout .offset ) {
226
265
LOG_ERROR ("GBM BO layout doesn't match image layout. This is probably a driver / kernel bug.\n" );
227
266
goto fail_destroy_bo ;
@@ -232,6 +271,8 @@ static int fb_init(struct fb *fb, struct gbm_device *gbm_device, struct vk_rende
232
271
goto fail_destroy_bo ;
233
272
}
234
273
274
+ // gbm_bo_get_fd will dup us a new dmabuf fd.
275
+ // So if we don't use it, we need to close it.
235
276
fd = gbm_bo_get_fd (bo );
236
277
if (fd < 0 ) {
237
278
LOG_ERROR ("Couldn't get dmabuf fd for GBM buffer. gbm_bo_get_fd: %s\n" , strerror (errno ));
@@ -248,7 +289,7 @@ static int fb_init(struct fb *fb, struct gbm_device *gbm_device, struct vk_rende
248
289
get_memory_fd_props = (PFN_vkGetMemoryFdPropertiesKHR ) vkGetDeviceProcAddr (device , "vkGetMemoryFdPropertiesKHR" );
249
290
if (get_memory_fd_props == NULL ) {
250
291
LOG_ERROR ("Couldn't resolve vkGetMemoryFdPropertiesKHR.\n" );
251
- goto fail_destroy_bo ;
292
+ goto fail_close_fd ;
252
293
}
253
294
254
295
ok = get_memory_fd_props (
@@ -259,7 +300,7 @@ static int fb_init(struct fb *fb, struct gbm_device *gbm_device, struct vk_rende
259
300
);
260
301
if (ok != VK_SUCCESS ) {
261
302
LOG_VK_ERROR (ok , "Couldn't get dmabuf memory properties. vkGetMemoryFdPropertiesKHR" );
262
- goto fail_destroy_bo ;
303
+ goto fail_close_fd ;
263
304
}
264
305
265
306
// Find out the memory requirements for our image (the supported memory types for import)
@@ -287,10 +328,12 @@ static int fb_init(struct fb *fb, struct gbm_device *gbm_device, struct vk_rende
287
328
);
288
329
if (mem < 0 ) {
289
330
LOG_ERROR ("Couldn't find a memory type that's both supported by the image and the dmabuffer.\n" );
290
- goto fail_destroy_bo ;
331
+ goto fail_close_fd ;
291
332
}
292
333
293
334
// now, create a VkDeviceMemory instance from our dmabuf.
335
+ // after successful import, the fd is owned by the device memory object
336
+ // and we don't need to close it.
294
337
ok = vkAllocateMemory (
295
338
device ,
296
339
& (VkMemoryAllocateInfo ) {
@@ -314,7 +357,7 @@ static int fb_init(struct fb *fb, struct gbm_device *gbm_device, struct vk_rende
314
357
);
315
358
if (ok != VK_SUCCESS ) {
316
359
LOG_VK_ERROR (ok , "Couldn't import dmabuf as vulkan device memory. vkAllocateMemory" );
317
- goto fail_destroy_bo ;
360
+ goto fail_close_fd ;
318
361
}
319
362
320
363
ok = vkBindImageMemory2 (
@@ -341,14 +384,18 @@ static int fb_init(struct fb *fb, struct gbm_device *gbm_device, struct vk_rende
341
384
fb -> fl_image = (FlutterVulkanImage ) {
342
385
.struct_size = sizeof (FlutterVulkanImage ),
343
386
.image = fb -> image ,
344
- .format = get_pixfmt_info ( pixel_format ) -> vk_format ,
387
+ .format = vk_format ,
345
388
};
346
389
347
390
return 0 ;
348
391
349
392
350
393
fail_free_device_memory :
351
394
vkFreeMemory (device , img_device_memory , NULL );
395
+ goto fail_destroy_bo ;
396
+
397
+ fail_close_fd :
398
+ close (fd );
352
399
353
400
fail_destroy_bo :
354
401
gbm_bo_destroy (bo );
@@ -641,8 +688,6 @@ static int vk_gbm_backing_store_present_kms(struct surface *s, const struct fl_l
641
688
pixel_format = store -> pixel_format ;
642
689
}
643
690
644
- LOG_DEBUG ("presenting fb %d\n" , store -> front_fb - store -> locked_fbs );
645
-
646
691
TRACER_BEGIN (store -> surface .tracer , "kms_req_builder_push_fb_layer" );
647
692
ok = kms_req_builder_push_fb_layer (
648
693
builder ,
@@ -736,9 +781,7 @@ static int vk_gbm_backing_store_fill(struct backing_store *s, FlutterBackingStor
736
781
locked : ;
737
782
/// TODO: Remove this once we're using triple buffering
738
783
#ifdef DEBUG
739
- int before = atomic_fetch_add (& store -> n_locked_fbs , 1 );
740
- LOG_DEBUG ("filling with fb %d\n" , i );
741
- LOG_DEBUG ("locked fbs: before: %d, now: %d\n" , before , before + 1 );
784
+ atomic_fetch_add (& store -> n_locked_fbs , 1 );
742
785
//DEBUG_ASSERT_MSG(before + 1 <= 3, "sanity check failed: too many locked fbs for double-buffered vsync");
743
786
#endif
744
787
store -> locked_fbs [i ].store = CAST_VK_GBM_BACKING_STORE (surface_ref (CAST_SURFACE_UNCHECKED (s )));
@@ -779,7 +822,6 @@ static int vk_gbm_backing_store_queue_present(struct backing_store *s, const Flu
779
822
for (int i = 0 ; i < ARRAY_SIZE (store -> locked_fbs ); i ++ ) {
780
823
if (store -> locked_fbs [i ].fb -> fl_image .image == fl_store -> vulkan .image -> image ) {
781
824
fb = store -> locked_fbs + i ;
782
- LOG_DEBUG ("queueing present fb %d\n" , i );
783
825
break ;
784
826
}
785
827
}
@@ -790,8 +832,13 @@ static int vk_gbm_backing_store_queue_present(struct backing_store *s, const Flu
790
832
return EINVAL ;
791
833
}
792
834
835
+ // Replace the front fb with the new one
836
+ // (will unref the old one if not NULL internally)
793
837
locked_fb_swap_ptrs (& store -> front_fb , fb );
794
838
839
+ // Since flutter no longer uses this fb for rendering, we need to unref it
840
+ locked_fb_unref (fb );
841
+
795
842
surface_unlock (CAST_SURFACE_UNCHECKED (s ));
796
843
return 0 ;
797
844
}
0 commit comments