@@ -73,6 +73,14 @@ typedef struct {
73
73
74
74
// Framebuffers to render keyed by view ID.
75
75
GHashTable* framebuffers_by_view_id;
76
+
77
+ // Mutex used when blocking the raster thread until a task is completed on
78
+ // platform thread.
79
+ GMutex present_mutex;
80
+
81
+ // Condition to unblock the raster thread after task is completed on platform
82
+ // thread.
83
+ GCond present_condition;
76
84
} FlRendererPrivate;
77
85
78
86
G_DEFINE_TYPE_WITH_PRIVATE (FlRenderer, fl_renderer, G_TYPE_OBJECT)
@@ -301,6 +309,151 @@ static void render(FlRenderer* self,
301
309
}
302
310
}
303
311
312
+ static gboolean present_layers (FlRenderer* self,
313
+ FlutterViewId view_id,
314
+ const FlutterLayer** layers,
315
+ size_t layers_count) {
316
+ FlRendererPrivate* priv = reinterpret_cast <FlRendererPrivate*>(
317
+ fl_renderer_get_instance_private (self));
318
+
319
+ g_return_val_if_fail (FL_IS_RENDERER (self), FALSE );
320
+
321
+ // ignore incoming frame with wrong dimensions in trivial case with just one
322
+ // layer
323
+ if (priv->blocking_main_thread && layers_count == 1 &&
324
+ layers[0 ]->offset .x == 0 && layers[0 ]->offset .y == 0 &&
325
+ (layers[0 ]->size .width != priv->target_width ||
326
+ layers[0 ]->size .height != priv->target_height )) {
327
+ return TRUE ;
328
+ }
329
+
330
+ priv->had_first_frame = true ;
331
+
332
+ fl_renderer_unblock_main_thread (self);
333
+
334
+ g_autoptr (GPtrArray) framebuffers =
335
+ g_ptr_array_new_with_free_func (g_object_unref);
336
+ for (size_t i = 0 ; i < layers_count; ++i) {
337
+ const FlutterLayer* layer = layers[i];
338
+ switch (layer->type ) {
339
+ case kFlutterLayerContentTypeBackingStore : {
340
+ const FlutterBackingStore* backing_store = layer->backing_store ;
341
+ FlFramebuffer* framebuffer =
342
+ FL_FRAMEBUFFER (backing_store->open_gl .framebuffer .user_data );
343
+ g_ptr_array_add (framebuffers, g_object_ref (framebuffer));
344
+ } break ;
345
+ case kFlutterLayerContentTypePlatformView : {
346
+ // TODO(robert-ancell) Not implemented -
347
+ // https://github.com/flutter/flutter/issues/41724
348
+ } break ;
349
+ }
350
+ }
351
+
352
+ GWeakRef* ref = static_cast <GWeakRef*>(
353
+ g_hash_table_lookup (priv->views , GINT_TO_POINTER (view_id)));
354
+ g_autoptr (FlRenderable) renderable =
355
+ ref != nullptr ? FL_RENDERABLE (g_weak_ref_get (ref)) : nullptr ;
356
+ if (renderable == nullptr ) {
357
+ return TRUE ;
358
+ }
359
+
360
+ if (view_id == flutter::kFlutterImplicitViewId ) {
361
+ // Store for rendering later
362
+ g_hash_table_insert (priv->framebuffers_by_view_id , GINT_TO_POINTER (view_id),
363
+ g_ptr_array_ref (framebuffers));
364
+ } else {
365
+ // Composite into a single framebuffer.
366
+ if (framebuffers->len > 1 ) {
367
+ size_t width = 0 , height = 0 ;
368
+
369
+ for (guint i = 0 ; i < framebuffers->len ; i++) {
370
+ FlFramebuffer* framebuffer =
371
+ FL_FRAMEBUFFER (g_ptr_array_index (framebuffers, i));
372
+
373
+ size_t w = fl_framebuffer_get_width (framebuffer);
374
+ size_t h = fl_framebuffer_get_height (framebuffer);
375
+ if (w > width) {
376
+ width = w;
377
+ }
378
+ if (h > height) {
379
+ height = h;
380
+ }
381
+ }
382
+
383
+ FlFramebuffer* view_framebuffer =
384
+ fl_framebuffer_new (priv->general_format , width, height);
385
+ glBindFramebuffer (GL_DRAW_FRAMEBUFFER,
386
+ fl_framebuffer_get_id (view_framebuffer));
387
+ render (self, framebuffers, width, height);
388
+ g_ptr_array_set_size (framebuffers, 0 );
389
+ g_ptr_array_add (framebuffers, view_framebuffer);
390
+ }
391
+
392
+ // Read back pixel values.
393
+ FlFramebuffer* framebuffer =
394
+ FL_FRAMEBUFFER (g_ptr_array_index (framebuffers, 0 ));
395
+ size_t width = fl_framebuffer_get_width (framebuffer);
396
+ size_t height = fl_framebuffer_get_height (framebuffer);
397
+ size_t data_length = width * height * 4 ;
398
+ g_autofree uint8_t * data = static_cast <uint8_t *>(malloc (data_length));
399
+ glBindFramebuffer (GL_READ_FRAMEBUFFER, fl_framebuffer_get_id (framebuffer));
400
+ glReadPixels (0 , 0 , width, height, priv->general_format , GL_UNSIGNED_BYTE,
401
+ data);
402
+
403
+ // Write into a texture in the views context.
404
+ fl_renderable_make_current (renderable);
405
+ FlFramebuffer* view_framebuffer =
406
+ fl_framebuffer_new (priv->general_format , width, height);
407
+ glBindFramebuffer (GL_DRAW_FRAMEBUFFER,
408
+ fl_framebuffer_get_id (view_framebuffer));
409
+ glBindTexture (GL_TEXTURE_2D,
410
+ fl_framebuffer_get_texture_id (view_framebuffer));
411
+ glTexImage2D (GL_TEXTURE_2D, 0 , GL_RGBA, width, height, 0 , GL_RGBA,
412
+ GL_UNSIGNED_BYTE, data);
413
+
414
+ g_autoptr (GPtrArray) secondary_framebuffers =
415
+ g_ptr_array_new_with_free_func (g_object_unref);
416
+ g_ptr_array_add (secondary_framebuffers, g_object_ref (view_framebuffer));
417
+ g_hash_table_insert (priv->framebuffers_by_view_id , GINT_TO_POINTER (view_id),
418
+ g_ptr_array_ref (secondary_framebuffers));
419
+ }
420
+
421
+ fl_renderable_redraw (renderable);
422
+
423
+ return TRUE ;
424
+ }
425
+
426
+ typedef struct {
427
+ FlRenderer* self;
428
+
429
+ FlutterViewId view_id;
430
+
431
+ const FlutterLayer** layers;
432
+ size_t layers_count;
433
+
434
+ gboolean result;
435
+
436
+ gboolean finished;
437
+ } PresentLayersData;
438
+
439
+ // Perform the present on the main thread.
440
+ static void present_layers_task_cb (gpointer user_data) {
441
+ PresentLayersData* data = static_cast <PresentLayersData*>(user_data);
442
+ FlRendererPrivate* priv = reinterpret_cast <FlRendererPrivate*>(
443
+ fl_renderer_get_instance_private (data->self ));
444
+
445
+ // Perform the present.
446
+ fl_renderer_make_current (data->self );
447
+ data->result = present_layers (data->self , data->view_id , data->layers ,
448
+ data->layers_count );
449
+ fl_renderer_clear_current (data->self );
450
+
451
+ // Complete fl_renderer_present_layers().
452
+ g_autoptr (GMutexLocker) locker = g_mutex_locker_new (&priv->present_mutex );
453
+ data->finished = TRUE ;
454
+ g_cond_signal (&priv->present_condition );
455
+ }
456
+
304
457
static void fl_renderer_dispose (GObject* object) {
305
458
FlRenderer* self = FL_RENDERER (object);
306
459
FlRendererPrivate* priv = reinterpret_cast <FlRendererPrivate*>(
@@ -311,6 +464,8 @@ static void fl_renderer_dispose(GObject* object) {
311
464
g_weak_ref_clear (&priv->engine );
312
465
g_clear_pointer (&priv->views , g_hash_table_unref);
313
466
g_clear_pointer (&priv->framebuffers_by_view_id , g_hash_table_unref);
467
+ g_mutex_clear (&priv->present_mutex );
468
+ g_cond_clear (&priv->present_condition );
314
469
315
470
G_OBJECT_CLASS (fl_renderer_parent_class)->dispose (object);
316
471
}
@@ -327,6 +482,8 @@ static void fl_renderer_init(FlRenderer* self) {
327
482
priv->framebuffers_by_view_id = g_hash_table_new_full (
328
483
g_direct_hash, g_direct_equal, nullptr ,
329
484
reinterpret_cast <GDestroyNotify>(g_ptr_array_unref));
485
+ g_mutex_init (&priv->present_mutex );
486
+ g_cond_init (&priv->present_condition );
330
487
}
331
488
332
489
void fl_renderer_set_engine (FlRenderer* self, FlEngine* engine) {
@@ -454,114 +611,37 @@ gboolean fl_renderer_present_layers(FlRenderer* self,
454
611
FlutterViewId view_id,
455
612
const FlutterLayer** layers,
456
613
size_t layers_count) {
614
+ // Detach the context from raster thread. Needed because blitting
615
+ // will be done on the main thread, which will make the context current.
616
+ fl_renderer_clear_current (self);
617
+
457
618
FlRendererPrivate* priv = reinterpret_cast <FlRendererPrivate*>(
458
619
fl_renderer_get_instance_private (self));
620
+ g_autoptr (FlEngine) engine = FL_ENGINE (g_weak_ref_get (&priv->engine ));
621
+
622
+ // Schedule the present to run on the main thread.
623
+ FlTaskRunner* task_runner = fl_engine_get_task_runner (engine);
624
+ PresentLayersData data = {
625
+ .self = self,
626
+ .view_id = view_id,
627
+ .layers = layers,
628
+ .layers_count = layers_count,
629
+ .result = FALSE ,
630
+ .finished = FALSE ,
631
+ };
632
+ fl_task_runner_post_callback (task_runner, present_layers_task_cb, &data);
459
633
460
- g_return_val_if_fail (FL_IS_RENDERER (self), FALSE );
461
-
462
- // ignore incoming frame with wrong dimensions in trivial case with just one
463
- // layer
464
- if (priv->blocking_main_thread && layers_count == 1 &&
465
- layers[0 ]->offset .x == 0 && layers[0 ]->offset .y == 0 &&
466
- (layers[0 ]->size .width != priv->target_width ||
467
- layers[0 ]->size .height != priv->target_height )) {
468
- return TRUE ;
469
- }
470
-
471
- priv->had_first_frame = true ;
472
-
473
- fl_renderer_unblock_main_thread (self);
474
-
475
- g_autoptr (GPtrArray) framebuffers =
476
- g_ptr_array_new_with_free_func (g_object_unref);
477
- for (size_t i = 0 ; i < layers_count; ++i) {
478
- const FlutterLayer* layer = layers[i];
479
- switch (layer->type ) {
480
- case kFlutterLayerContentTypeBackingStore : {
481
- const FlutterBackingStore* backing_store = layer->backing_store ;
482
- FlFramebuffer* framebuffer =
483
- FL_FRAMEBUFFER (backing_store->open_gl .framebuffer .user_data );
484
- g_ptr_array_add (framebuffers, g_object_ref (framebuffer));
485
- } break ;
486
- case kFlutterLayerContentTypePlatformView : {
487
- // TODO(robert-ancell) Not implemented -
488
- // https://github.com/flutter/flutter/issues/41724
489
- } break ;
490
- }
491
- }
492
-
493
- GWeakRef* ref = static_cast <GWeakRef*>(
494
- g_hash_table_lookup (priv->views , GINT_TO_POINTER (view_id)));
495
- g_autoptr (FlRenderable) renderable =
496
- ref != nullptr ? FL_RENDERABLE (g_weak_ref_get (ref)) : nullptr ;
497
- if (renderable == nullptr ) {
498
- return TRUE ;
499
- }
500
-
501
- if (view_id == flutter::kFlutterImplicitViewId ) {
502
- // Store for rendering later
503
- g_hash_table_insert (priv->framebuffers_by_view_id , GINT_TO_POINTER (view_id),
504
- g_ptr_array_ref (framebuffers));
505
- } else {
506
- // Composite into a single framebuffer.
507
- if (framebuffers->len > 1 ) {
508
- size_t width = 0 , height = 0 ;
509
-
510
- for (guint i = 0 ; i < framebuffers->len ; i++) {
511
- FlFramebuffer* framebuffer =
512
- FL_FRAMEBUFFER (g_ptr_array_index (framebuffers, i));
513
-
514
- size_t w = fl_framebuffer_get_width (framebuffer);
515
- size_t h = fl_framebuffer_get_height (framebuffer);
516
- if (w > width) {
517
- width = w;
518
- }
519
- if (h > height) {
520
- height = h;
521
- }
522
- }
523
-
524
- FlFramebuffer* view_framebuffer =
525
- fl_framebuffer_new (priv->general_format , width, height);
526
- glBindFramebuffer (GL_DRAW_FRAMEBUFFER,
527
- fl_framebuffer_get_id (view_framebuffer));
528
- render (self, framebuffers, width, height);
529
- g_ptr_array_set_size (framebuffers, 0 );
530
- g_ptr_array_add (framebuffers, view_framebuffer);
531
- }
532
-
533
- // Read back pixel values.
534
- FlFramebuffer* framebuffer =
535
- FL_FRAMEBUFFER (g_ptr_array_index (framebuffers, 0 ));
536
- size_t width = fl_framebuffer_get_width (framebuffer);
537
- size_t height = fl_framebuffer_get_height (framebuffer);
538
- size_t data_length = width * height * 4 ;
539
- g_autofree uint8_t * data = static_cast <uint8_t *>(malloc (data_length));
540
- glBindFramebuffer (GL_READ_FRAMEBUFFER, fl_framebuffer_get_id (framebuffer));
541
- glReadPixels (0 , 0 , width, height, priv->general_format , GL_UNSIGNED_BYTE,
542
- data);
543
-
544
- // Write into a texture in the views context.
545
- fl_renderable_make_current (renderable);
546
- FlFramebuffer* view_framebuffer =
547
- fl_framebuffer_new (priv->general_format , width, height);
548
- glBindFramebuffer (GL_DRAW_FRAMEBUFFER,
549
- fl_framebuffer_get_id (view_framebuffer));
550
- glBindTexture (GL_TEXTURE_2D,
551
- fl_framebuffer_get_texture_id (view_framebuffer));
552
- glTexImage2D (GL_TEXTURE_2D, 0 , GL_RGBA, width, height, 0 , GL_RGBA,
553
- GL_UNSIGNED_BYTE, data);
554
-
555
- g_autoptr (GPtrArray) secondary_framebuffers =
556
- g_ptr_array_new_with_free_func (g_object_unref);
557
- g_ptr_array_add (secondary_framebuffers, g_object_ref (view_framebuffer));
558
- g_hash_table_insert (priv->framebuffers_by_view_id , GINT_TO_POINTER (view_id),
559
- g_ptr_array_ref (secondary_framebuffers));
634
+ // Block until present completes.
635
+ g_autoptr (GMutexLocker) locker = g_mutex_locker_new (&priv->present_mutex );
636
+ while (!data.finished ) {
637
+ g_cond_wait (&priv->present_condition , &priv->present_mutex );
560
638
}
561
639
562
- fl_renderable_redraw (renderable);
640
+ // Restore the context to the raster thread in case the engine needs it
641
+ // to do some cleanup.
642
+ fl_renderer_make_current (self);
563
643
564
- return TRUE ;
644
+ return data. result ;
565
645
}
566
646
567
647
void fl_renderer_setup (FlRenderer* self) {
0 commit comments