10
10
11
11
#include < algorithm> // For std::clamp
12
12
13
+ #include " flutter/fml/logging.h"
13
14
#include " flutter/fml/trace_event.h"
14
15
#include " third_party/skia/include/core/SkPicture.h"
15
16
#include " third_party/skia/include/core/SkSurface.h"
@@ -169,8 +170,9 @@ void GfxExternalViewEmbedder::PrerollCompositeEmbeddedView(
169
170
zx_handle_t handle = static_cast <zx_handle_t >(view_id);
170
171
FML_CHECK (frame_layers_.count (handle) == 0 );
171
172
172
- frame_layers_.emplace (std::make_pair (EmbedderLayerId{handle},
173
- EmbedderLayer (frame_size_, *params)));
173
+ frame_layers_.emplace (std::make_pair (
174
+ EmbedderLayerId{handle},
175
+ EmbedderLayer (frame_size_, *params, flutter::RTreeFactory ())));
174
176
frame_composition_order_.push_back (handle);
175
177
}
176
178
@@ -200,8 +202,9 @@ void GfxExternalViewEmbedder::BeginFrame(
200
202
frame_dpr_ = device_pixel_ratio;
201
203
202
204
// Create the root layer.
203
- frame_layers_.emplace (
204
- std::make_pair (kRootLayerId , EmbedderLayer (frame_size, std::nullopt)));
205
+ frame_layers_.emplace (std::make_pair (
206
+ kRootLayerId ,
207
+ EmbedderLayer (frame_size, std::nullopt, flutter::RTreeFactory ())));
205
208
frame_composition_order_.push_back (kRootLayerId );
206
209
207
210
// Set up the input interceptor at the top of the scene, if applicable.
@@ -271,6 +274,19 @@ void GfxExternalViewEmbedder::SubmitFrame(
271
274
}
272
275
}
273
276
277
+ // Finish recording SkPictures.
278
+ {
279
+ TRACE_EVENT0 (" flutter" , " FinishRecordingPictures" );
280
+
281
+ for (const auto & surface_index : frame_surface_indices) {
282
+ const auto & layer = frame_layers_.find (surface_index.first );
283
+ FML_CHECK (layer != frame_layers_.end ());
284
+ layer->second .picture =
285
+ layer->second .recorder ->finishRecordingAsPicture ();
286
+ FML_CHECK (layer->second .picture != nullptr );
287
+ }
288
+ }
289
+
274
290
// Submit layers and platform views to Scenic in composition order.
275
291
{
276
292
TRACE_EVENT0 (" flutter" , " SubmitLayers" );
@@ -437,10 +453,18 @@ void GfxExternalViewEmbedder::SubmitFrame(
437
453
FML_CHECK (scenic_layer_index <= scenic_layers_.size ());
438
454
if (scenic_layer_index == scenic_layers_.size ()) {
439
455
ScenicLayer new_layer{
440
- .shape_node = scenic::ShapeNode (session_->get ()),
441
- .material = scenic::Material (session_->get ()),
456
+ .layer_node = scenic::EntityNode (session_->get ()),
457
+ .image =
458
+ ScenicImage{
459
+ .shape_node = scenic::ShapeNode (session_->get ()),
460
+ .material = scenic::Material (session_->get ()),
461
+ },
462
+ // We'll set hit regions later.
463
+ .hit_regions = {},
442
464
};
443
- new_layer.shape_node .SetMaterial (new_layer.material );
465
+ new_layer.layer_node .SetLabel (" Flutter::Layer" );
466
+ new_layer.layer_node .AddChild (new_layer.image .shape_node );
467
+ new_layer.image .shape_node .SetMaterial (new_layer.image .material );
444
468
scenic_layers_.emplace_back (std::move (new_layer));
445
469
}
446
470
@@ -491,25 +515,50 @@ void GfxExternalViewEmbedder::SubmitFrame(
491
515
embedded_views_height;
492
516
auto & scenic_layer = scenic_layers_[scenic_layer_index];
493
517
auto & scenic_rect = found_rects->second [rect_index];
494
- scenic_layer.shape_node .SetLabel (" Flutter::Layer" );
495
- scenic_layer.shape_node .SetShape (scenic_rect);
496
- scenic_layer.shape_node .SetTranslation (
518
+ auto & image = scenic_layer.image ;
519
+ image.shape_node .SetLabel (" Flutter::Layer::Image" );
520
+ image.shape_node .SetShape (scenic_rect);
521
+ image.shape_node .SetTranslation (
497
522
layer->second .surface_size .width () * 0 .5f ,
498
523
layer->second .surface_size .height () * 0 .5f , -layer_elevation);
499
- scenic_layer.material .SetColor (SK_AlphaOPAQUE, SK_AlphaOPAQUE,
500
- SK_AlphaOPAQUE, layer_opacity);
501
- scenic_layer.material .SetTexture (surface_for_layer->GetImageId ());
502
-
503
- // Only the first (i.e. the bottom-most) layer should receive input.
504
- // TODO: Workaround for invisible overlays stealing input. Remove when
505
- // the underlying bug is fixed.
506
- const fuchsia::ui::gfx::HitTestBehavior layer_hit_test_behavior =
507
- first_layer ? fuchsia::ui::gfx::HitTestBehavior::kDefault
508
- : fuchsia::ui::gfx::HitTestBehavior::kSuppress ;
509
- scenic_layer.shape_node .SetHitTestBehavior (layer_hit_test_behavior);
524
+ image.material .SetColor (SK_AlphaOPAQUE, SK_AlphaOPAQUE, SK_AlphaOPAQUE,
525
+ layer_opacity);
526
+ image.material .SetTexture (surface_for_layer->GetImageId ());
527
+
528
+ // We'll set hit regions expliclty on a separate ShapeNode, so the image
529
+ // itself should be unhittable and semantically invisible.
530
+ image.shape_node .SetHitTestBehavior (
531
+ fuchsia::ui::gfx::HitTestBehavior::kSuppress );
532
+ image.shape_node .SetSemanticVisibility (false );
510
533
511
534
// Attach the ScenicLayer to the main scene graph.
512
- layer_tree_node_.AddChild (scenic_layer.shape_node );
535
+ layer_tree_node_.AddChild (scenic_layer.layer_node );
536
+
537
+ // Compute the set of non-overlapping set of bounding boxes for the
538
+ // painted content in this layer.
539
+ {
540
+ FML_CHECK (layer->second .rtree );
541
+ std::list<SkRect> intersection_rects =
542
+ layer->second .rtree ->searchNonOverlappingDrawnRects (
543
+ SkRect::Make (layer->second .surface_size ));
544
+
545
+ // SkRect joined_rect = SkRect::MakeEmpty();
546
+ for (const SkRect& rect : intersection_rects) {
547
+ auto paint_bounds =
548
+ scenic::Rectangle (session_->get (), rect.width (), rect.height ());
549
+ auto hit_region = scenic::ShapeNode (session_->get ());
550
+ hit_region.SetLabel (" Flutter::Layer::HitRegion" );
551
+ hit_region.SetShape (paint_bounds);
552
+ hit_region.SetTranslation (rect.centerX (), rect.centerY (),
553
+ -layer_elevation);
554
+ hit_region.SetHitTestBehavior (
555
+ fuchsia::ui::gfx::HitTestBehavior::kDefault );
556
+ hit_region.SetSemanticVisibility (true );
557
+
558
+ scenic_layer.layer_node .AddChild (hit_region);
559
+ scenic_layer.hit_regions .push_back (std::move (hit_region));
560
+ }
561
+ }
513
562
}
514
563
515
564
// Reset for the next pass:
@@ -527,7 +576,11 @@ void GfxExternalViewEmbedder::SubmitFrame(
527
576
session_->Present ();
528
577
}
529
578
530
- // Render the recorded SkPictures into the surfaces.
579
+ // Flush pending skia operations.
580
+ // NOTE: This operation MUST occur AFTER the `Present() ` call above. We
581
+ // pipeline the Skia rendering work with scenic IPC, and scenic will delay
582
+ // internally until Skia is finished. So, doing this work before calling
583
+ // `Present()` would adversely affect performance.
531
584
{
532
585
TRACE_EVENT0 (" flutter" , " RasterizeSurfaces" );
533
586
@@ -548,13 +601,10 @@ void GfxExternalViewEmbedder::SubmitFrame(
548
601
549
602
const auto & layer = frame_layers_.find (surface_index.first );
550
603
FML_CHECK (layer != frame_layers_.end ());
551
- sk_sp<SkPicture> picture =
552
- layer->second .recorder ->finishRecordingAsPicture ();
553
- FML_CHECK (picture != nullptr );
554
604
555
605
canvas->setMatrix (SkMatrix::I ());
556
606
canvas->clear (SK_ColorTRANSPARENT);
557
- canvas->drawPicture (picture);
607
+ canvas->drawPicture (layer-> second . picture );
558
608
canvas->flush ();
559
609
}
560
610
}
@@ -636,7 +686,16 @@ void GfxExternalViewEmbedder::Reset() {
636
686
637
687
// Clear images on all layers so they aren't cached unnecessarily.
638
688
for (auto & layer : scenic_layers_) {
639
- layer.material .SetTexture (0 );
689
+ layer.image .material .SetTexture (0 );
690
+
691
+ // Detach hit regions; otherwise, they may persist across frames
692
+ // incorrectly.
693
+ for (auto & hit_region : layer.hit_regions ) {
694
+ hit_region.Detach ();
695
+ }
696
+
697
+ // Remove cached hit regions so that we don't recreate stale ones.
698
+ layer.hit_regions .clear ();
640
699
}
641
700
}
642
701
0 commit comments