Flutter Engine
flutter_runner::FuchsiaExternalViewEmbedder Class Referencefinal

#include <fuchsia_external_view_embedder.h>

Inheritance diagram for flutter_runner::FuchsiaExternalViewEmbedder:
flutter::ExternalViewEmbedder

Public Member Functions

 FuchsiaExternalViewEmbedder (std::string debug_label, fuchsia::ui::views::ViewToken view_token, scenic::ViewRefPair view_ref_pair, SessionConnection &session, VulkanSurfaceProducer &surface_producer)
 
 ~FuchsiaExternalViewEmbedder ()
 
SkCanvas * GetRootCanvas () override
 
std::vector< SkCanvas * > GetCurrentCanvases () override
 
void PrerollCompositeEmbeddedView (int view_id, std::unique_ptr< flutter::EmbeddedViewParams > params) override
 
SkCanvas * CompositeEmbeddedView (int view_id) override
 
flutter::PostPrerollResult PostPrerollAction (fml::RefPtr< fml::RasterThreadMerger > raster_thread_merger) override
 
void BeginFrame (SkISize frame_size, GrDirectContext *context, double device_pixel_ratio, fml::RefPtr< fml::RasterThreadMerger > raster_thread_merger) override
 
void EndFrame (bool should_resubmit_frame, fml::RefPtr< fml::RasterThreadMerger > raster_thread_merger) override
 
void SubmitFrame (GrDirectContext *context, std::unique_ptr< flutter::SurfaceFrame > frame) override
 
void CancelFrame () override
 
bool SupportsDynamicThreadMerging () override
 
void EnableWireframe (bool enable)
 
void CreateView (int64_t view_id)
 
void DestroyView (int64_t view_id)
 
void SetViewProperties (int64_t view_id, bool hit_testable, bool focusable)
 
- Public Member Functions inherited from flutter::ExternalViewEmbedder
 ExternalViewEmbedder ()=default
 
virtual ~ExternalViewEmbedder ()=default
 
 FML_DISALLOW_COPY_AND_ASSIGN (ExternalViewEmbedder)
 

Detailed Description

Definition at line 36 of file fuchsia_external_view_embedder.h.

Constructor & Destructor Documentation

◆ FuchsiaExternalViewEmbedder()

flutter_runner::FuchsiaExternalViewEmbedder::FuchsiaExternalViewEmbedder ( std::string  debug_label,
fuchsia::ui::views::ViewToken  view_token,
scenic::ViewRefPair  view_ref_pair,
SessionConnection session,
VulkanSurfaceProducer surface_producer 
)

Definition at line 27 of file fuchsia_external_view_embedder.cc.

References flutter_runner::SessionConnection::Present(), and ~FuchsiaExternalViewEmbedder().

33  : session_(session),
34  surface_producer_(surface_producer),
35  root_view_(session_.get(),
36  std::move(view_token),
37  std::move(view_ref_pair.control_ref),
38  std::move(view_ref_pair.view_ref),
39  debug_label),
40  metrics_node_(session_.get()),
41  root_node_(session_.get()) {
42  root_view_.AddChild(metrics_node_);
43  metrics_node_.SetEventMask(fuchsia::ui::gfx::kMetricsEventMask);
44  metrics_node_.SetLabel("Flutter::MetricsWatcher");
45  metrics_node_.AddChild(root_node_);
46  root_node_.SetLabel("Flutter::LayerTree");
47 
48  session_.Present();
49 }
scenic::Session * get() override

◆ ~FuchsiaExternalViewEmbedder()

flutter_runner::FuchsiaExternalViewEmbedder::~FuchsiaExternalViewEmbedder ( )
default

Member Function Documentation

◆ BeginFrame()

void flutter_runner::FuchsiaExternalViewEmbedder::BeginFrame ( SkISize  frame_size,
GrDirectContext *  context,
double  device_pixel_ratio,
fml::RefPtr< fml::RasterThreadMerger raster_thread_merger 
)
overridevirtual

Implements flutter::ExternalViewEmbedder.

Definition at line 101 of file fuchsia_external_view_embedder.cc.

References TRACE_EVENT0.

105  {
106  TRACE_EVENT0("flutter", "FuchsiaExternalViewEmbedder::BeginFrame");
107 
108  // Reset for new frame.
109  Reset();
110  frame_size_ = frame_size;
111  frame_dpr_ = device_pixel_ratio;
112 
113  // Create the root layer.
114  frame_layers_.emplace(
115  std::make_pair(kRootLayerId, EmbedderLayer(frame_size, std::nullopt)));
116  frame_composition_order_.push_back(kRootLayerId);
117 }
#define TRACE_EVENT0(category_group, name)
Definition: trace_event.h:75

◆ CancelFrame()

void flutter_runner::FuchsiaExternalViewEmbedder::CancelFrame ( )
inlineoverridevirtual

Implements flutter::ExternalViewEmbedder.

Definition at line 80 of file fuchsia_external_view_embedder.h.

80 { Reset(); }

◆ CompositeEmbeddedView()

SkCanvas * flutter_runner::FuchsiaExternalViewEmbedder::CompositeEmbeddedView ( int  view_id)
overridevirtual

Implements flutter::ExternalViewEmbedder.

Definition at line 88 of file fuchsia_external_view_embedder.cc.

References FML_DCHECK.

88  {
89  zx_handle_t handle = static_cast<zx_handle_t>(view_id);
90  auto found = frame_layers_.find(handle);
91  FML_DCHECK(found != frame_layers_.end());
92 
93  return found->second.canvas_spy->GetSpyingCanvas();
94 }
#define FML_DCHECK(condition)
Definition: logging.h:86

◆ CreateView()

void flutter_runner::FuchsiaExternalViewEmbedder::CreateView ( int64_t  view_id)

Definition at line 389 of file fuchsia_external_view_embedder.cc.

References FML_DCHECK, flutter_runner::SessionConnection::get(), and flutter::kScenicZElevationBetweenLayers.

Referenced by SupportsDynamicThreadMerging().

389  {
390  FML_DCHECK(scenic_views_.find(view_id) == scenic_views_.end());
391 
392  ScenicView new_view = {
393  .opacity_node = scenic::OpacityNodeHACK(session_.get()),
394  .entity_node = scenic::EntityNode(session_.get()),
395  .view_holder = scenic::ViewHolder(
396  session_.get(),
397  scenic::ToViewHolderToken(zx::eventpair((zx_handle_t)view_id)),
398  "Flutter::PlatformView"),
399  };
400 
401  new_view.opacity_node.SetLabel("flutter::PlatformView::OpacityMutator");
402  new_view.entity_node.SetLabel("flutter::PlatformView::TransformMutator");
403  new_view.opacity_node.AddChild(new_view.entity_node);
404  new_view.entity_node.Attach(new_view.view_holder);
405  new_view.entity_node.SetTranslation(0.f, 0.f,
407 
408  scenic_views_.emplace(std::make_pair(view_id, std::move(new_view)));
409 }
#define FML_DCHECK(condition)
Definition: logging.h:86
scenic::Session * get() override
constexpr float kScenicZElevationBetweenLayers

◆ DestroyView()

void flutter_runner::FuchsiaExternalViewEmbedder::DestroyView ( int64_t  view_id)

Definition at line 411 of file fuchsia_external_view_embedder.cc.

References FML_DCHECK.

Referenced by SupportsDynamicThreadMerging().

411  {
412  size_t erased = scenic_views_.erase(view_id);
413  FML_DCHECK(erased == 1);
414 }
#define FML_DCHECK(condition)
Definition: logging.h:86

◆ EnableWireframe()

void flutter_runner::FuchsiaExternalViewEmbedder::EnableWireframe ( bool  enable)

Definition at line 383 of file fuchsia_external_view_embedder.cc.

References flutter_runner::SessionConnection::get(), and flutter_runner::SessionConnection::Present().

Referenced by SupportsDynamicThreadMerging().

383  {
384  session_.get()->Enqueue(
385  scenic::NewSetEnableDebugViewBoundsCmd(root_view_.id(), enable));
386  session_.Present();
387 }
scenic::Session * get() override

◆ EndFrame()

void flutter_runner::FuchsiaExternalViewEmbedder::EndFrame ( bool  should_resubmit_frame,
fml::RefPtr< fml::RasterThreadMerger raster_thread_merger 
)
overridevirtual

Reimplemented from flutter::ExternalViewEmbedder.

Definition at line 119 of file fuchsia_external_view_embedder.cc.

References TRACE_EVENT0.

121  {
122  TRACE_EVENT0("flutter", "FuchsiaExternalViewEmbedder::EndFrame");
123 }
#define TRACE_EVENT0(category_group, name)
Definition: trace_event.h:75

◆ GetCurrentCanvases()

std::vector< SkCanvas * > flutter_runner::FuchsiaExternalViewEmbedder::GetCurrentCanvases ( )
overridevirtual

Implements flutter::ExternalViewEmbedder.

Definition at line 66 of file fuchsia_external_view_embedder.cc.

66  {
67  std::vector<SkCanvas*> canvases;
68  for (const auto& layer : frame_layers_) {
69  // This method (for legacy reasons) expects non-root current canvases.
70  if (layer.first.has_value()) {
71  canvases.push_back(layer.second.canvas_spy->GetSpyingCanvas());
72  }
73  }
74  return canvases;
75 }

◆ GetRootCanvas()

SkCanvas * flutter_runner::FuchsiaExternalViewEmbedder::GetRootCanvas ( )
overridevirtual

Implements flutter::ExternalViewEmbedder.

Definition at line 53 of file fuchsia_external_view_embedder.cc.

References FML_DLOG.

53  {
54  auto found = frame_layers_.find(kRootLayerId);
55  if (found == frame_layers_.end()) {
56  FML_DLOG(WARNING)
57  << "No root canvas could be found. This is extremely unlikely and "
58  "indicates that the external view embedder did not receive the "
59  "notification to begin the frame.";
60  return nullptr;
61  }
62 
63  return found->second.canvas_spy->GetSpyingCanvas();
64 }
#define FML_DLOG(severity)
Definition: logging.h:85

◆ PostPrerollAction()

flutter::PostPrerollResult flutter_runner::FuchsiaExternalViewEmbedder::PostPrerollAction ( fml::RefPtr< fml::RasterThreadMerger raster_thread_merger)
overridevirtual

◆ PrerollCompositeEmbeddedView()

void flutter_runner::FuchsiaExternalViewEmbedder::PrerollCompositeEmbeddedView ( int  view_id,
std::unique_ptr< flutter::EmbeddedViewParams params 
)
overridevirtual

Implements flutter::ExternalViewEmbedder.

Definition at line 77 of file fuchsia_external_view_embedder.cc.

References FML_DCHECK.

79  {
80  zx_handle_t handle = static_cast<zx_handle_t>(view_id);
81  FML_DCHECK(frame_layers_.count(handle) == 0);
82 
83  frame_layers_.emplace(std::make_pair(EmbedderLayerId{handle},
84  EmbedderLayer(frame_size_, *params)));
85  frame_composition_order_.push_back(handle);
86 }
#define FML_DCHECK(condition)
Definition: logging.h:86

◆ SetViewProperties()

void flutter_runner::FuchsiaExternalViewEmbedder::SetViewProperties ( int64_t  view_id,
bool  hit_testable,
bool  focusable 
)

Definition at line 416 of file fuchsia_external_view_embedder.cc.

References FML_DCHECK, and flutter_runner::SessionConnection::get().

Referenced by SupportsDynamicThreadMerging().

418  {
419  auto found = scenic_views_.find(view_id);
420  FML_DCHECK(found != scenic_views_.end());
421  auto& view_holder = found->second;
422 
423  view_holder.pending_hit_testable = hit_testable;
424  view_holder.pending_focusable = focusable;
425 }
#define FML_DCHECK(condition)
Definition: logging.h:86

◆ SubmitFrame()

void flutter_runner::FuchsiaExternalViewEmbedder::SubmitFrame ( GrDirectContext *  context,
std::unique_ptr< flutter::SurfaceFrame frame 
)
overridevirtual

Reimplemented from flutter::ExternalViewEmbedder.

Definition at line 125 of file fuchsia_external_view_embedder.cc.

References FML_DCHECK, flutter_runner::SessionConnection::get(), flutter::kScenicZElevationBetweenLayers, flutter_runner::VulkanSurfaceProducer::OnSurfacesPresented(), flutter::opacity, flutter_runner::SessionConnection::Present(), flutter_runner::VulkanSurfaceProducer::ProduceSurface(), and TRACE_EVENT0.

127  {
128  TRACE_EVENT0("flutter", "FuchsiaExternalViewEmbedder::SubmitFrame");
129 
130  std::vector<std::unique_ptr<SurfaceProducerSurface>> frame_surfaces;
131  std::unordered_map<EmbedderLayerId, size_t> frame_surface_indices;
132 
133  // Create surfaces for the frame and associate them with layer IDs.
134  {
135  TRACE_EVENT0("flutter", "CreateSurfaces");
136 
137  for (const auto& layer : frame_layers_) {
138  if (!layer.second.canvas_spy->DidDrawIntoCanvas()) {
139  continue;
140  }
141 
142  auto surface =
143  surface_producer_.ProduceSurface(layer.second.surface_size);
144  FML_DCHECK(surface)
145  << "Embedder did not return a valid render target of size ("
146  << layer.second.surface_size.width() << ", "
147  << layer.second.surface_size.height() << ")";
148 
149  frame_surface_indices.emplace(
150  std::make_pair(layer.first, frame_surfaces.size()));
151  frame_surfaces.emplace_back(std::move(surface));
152  }
153  }
154 
155  // Submit layers and platform views to Scenic in composition order.
156  {
157  TRACE_EVENT0("flutter", "SubmitLayers");
158 
159  std::unordered_map<uint64_t, size_t> scenic_rect_indices;
160  size_t scenic_layer_index = 0;
161  float embedded_views_height = 0.0f;
162 
163  // First re-scale everything according to the DPR.
164  const float inv_dpr = 1.0f / frame_dpr_;
165  root_node_.SetScale(inv_dpr, inv_dpr, 1.0f);
166 
167  for (const auto& layer_id : frame_composition_order_) {
168  const auto& layer = frame_layers_.find(layer_id);
169  FML_DCHECK(layer != frame_layers_.end());
170 
171  // Draw the PlatformView associated with each layer first.
172  if (layer_id.has_value()) {
173  FML_DCHECK(layer->second.embedded_view_params.has_value());
174  auto& view_params = layer->second.embedded_view_params.value();
175 
176  // Compute offset and size for the platform view.
177  SkPoint view_offset =
178  SkPoint::Make(view_params.finalBoundingRect().left(),
179  view_params.finalBoundingRect().top());
180  SkSize view_size =
181  SkSize::Make(view_params.finalBoundingRect().width(),
182  view_params.finalBoundingRect().height());
183 
184  // Compute opacity for the platform view.
185  float view_opacity = 1.0f;
186  for (auto i = view_params.mutatorsStack().Bottom();
187  i != view_params.mutatorsStack().Top(); ++i) {
188  const auto& mutator = *i;
189  switch (mutator->GetType()) {
191  view_opacity *= std::clamp(mutator->GetAlphaFloat(), 0.0f, 1.0f);
192  } break;
193  default: {
194  break;
195  }
196  }
197  }
198 
199  auto found = scenic_views_.find(layer_id.value());
200  FML_DCHECK(found != scenic_views_.end());
201  auto& view_holder = found->second;
202 
203  // Set opacity.
204  if (view_opacity != view_holder.opacity) {
205  view_holder.opacity_node.SetOpacity(view_opacity);
206  view_holder.opacity = view_opacity;
207  }
208 
209  // Set offset and elevation.
210  const float view_elevation =
211  kScenicZElevationBetweenLayers * scenic_layer_index +
212  embedded_views_height;
213  if (view_offset != view_holder.offset ||
214  view_elevation != view_holder.elevation) {
215  view_holder.entity_node.SetTranslation(view_offset.fX, view_offset.fY,
216  -view_elevation);
217  view_holder.elevation = view_elevation;
218  }
219 
220  // Set HitTestBehavior.
221  if (view_holder.pending_hit_testable != view_holder.hit_testable) {
222  view_holder.entity_node.SetHitTestBehavior(
223  view_holder.pending_hit_testable
224  ? fuchsia::ui::gfx::HitTestBehavior::kDefault
225  : fuchsia::ui::gfx::HitTestBehavior::kSuppress);
226  view_holder.hit_testable = view_holder.pending_hit_testable;
227  }
228 
229  // Set size and focusable.
230  //
231  // Scenic rejects `SetViewProperties` calls with a zero size.
232  if (!view_size.isEmpty() &&
233  (view_size != view_holder.size ||
234  view_holder.pending_focusable != view_holder.focusable)) {
235  view_holder.view_holder.SetViewProperties({
236  .bounding_box =
237  {
238  .min = {.x = 0.f, .y = 0.f, .z = -1000.f},
239  .max = {.x = view_size.width(),
240  .y = view_size.height(),
241  .z = 0.f},
242  },
243  .inset_from_min = {.x = 0.f, .y = 0.f, .z = 0.f},
244  .inset_from_max = {.x = 0.f, .y = 0.f, .z = 0.f},
245  .focus_change = view_holder.pending_focusable,
246  });
247  view_holder.size = view_size;
248  view_holder.focusable = view_holder.pending_focusable;
249  }
250 
251  // Attach the ScenicView to the main scene graph.
252  root_node_.AddChild(view_holder.opacity_node);
253 
254  // Account for the ScenicView's height when positioning the next layer.
255  embedded_views_height += kScenicZElevationForPlatformView;
256  }
257 
258  if (layer->second.canvas_spy->DidDrawIntoCanvas()) {
259  const auto& surface_index = frame_surface_indices.find(layer_id);
260  FML_DCHECK(surface_index != frame_surface_indices.end());
261  scenic::Image* surface_image =
262  frame_surfaces[surface_index->second]->GetImage();
263 
264  // Create a new layer if needed for the surface.
265  FML_DCHECK(scenic_layer_index <= scenic_layers_.size());
266  if (scenic_layer_index == scenic_layers_.size()) {
267  ScenicLayer new_layer{
268  .shape_node = scenic::ShapeNode(session_.get()),
269  .material = scenic::Material(session_.get()),
270  };
271  new_layer.shape_node.SetMaterial(new_layer.material);
272  scenic_layers_.emplace_back(std::move(new_layer));
273  }
274 
275  // Compute a hash and index for the rect.
276  const uint64_t rect_hash =
277  (static_cast<uint64_t>(layer->second.surface_size.width()) << 32) +
278  layer->second.surface_size.height();
279  size_t rect_index = 0;
280  auto found_index = scenic_rect_indices.find(rect_hash);
281  if (found_index == scenic_rect_indices.end()) {
282  scenic_rect_indices.emplace(std::make_pair(rect_hash, 0));
283  } else {
284  rect_index = found_index->second + 1;
285  scenic_rect_indices[rect_hash] = rect_index;
286  }
287 
288  // Create a new rect if needed for the surface.
289  auto found_rects = scenic_rects_.find(rect_hash);
290  if (found_rects == scenic_rects_.end()) {
291  auto [emplaced_rects, success] = scenic_rects_.emplace(
292  std::make_pair(rect_hash, std::vector<scenic::Rectangle>()));
293  FML_DCHECK(success);
294 
295  found_rects = std::move(emplaced_rects);
296  }
297  FML_DCHECK(rect_index <= found_rects->second.size());
298  if (rect_index == found_rects->second.size()) {
299  found_rects->second.emplace_back(scenic::Rectangle(
300  session_.get(), layer->second.surface_size.width(),
301  layer->second.surface_size.height()));
302  }
303 
304  // Set layer shape and texture.
305  // Scenic currently lacks an API to enable rendering of alpha channel;
306  // Flutter Embedder also lacks an API to detect if a layer has alpha or
307  // not. Alpha channels are only rendered if there is a OpacityNode
308  // higher in the tree with opacity != 1. For now, always assume t he
309  // layer has alpha and clamp to a infinitesimally smaller value than 1.
310  //
311  // This does not cause visual problems in practice, but probably has
312  // performance implications.
313  auto& scenic_layer = scenic_layers_[scenic_layer_index];
314  auto& scenic_rect = found_rects->second[rect_index];
315  const float layer_elevation =
316  kScenicZElevationBetweenLayers * scenic_layer_index +
317  embedded_views_height;
318  scenic_layer.shape_node.SetLabel("Flutter::Layer");
319  scenic_layer.shape_node.SetShape(scenic_rect);
320  scenic_layer.shape_node.SetTranslation(
321  layer->second.surface_size.width() * 0.5f,
322  layer->second.surface_size.height() * 0.5f, -layer_elevation);
323  scenic_layer.material.SetColor(SK_AlphaOPAQUE, SK_AlphaOPAQUE,
324  SK_AlphaOPAQUE, SK_AlphaOPAQUE - 1);
325  scenic_layer.material.SetTexture(*surface_image);
326 
327  // Attach the ScenicLayer to the main scene graph.
328  root_node_.AddChild(scenic_layer.shape_node);
329 
330  // Account for the ScenicLayer's height when positioning the next layer.
331  scenic_layer_index++;
332  }
333  }
334  }
335 
336  // Present the session to Scenic, along with surface acquire/release fencess.
337  {
338  TRACE_EVENT0("flutter", "SessionPresent");
339 
340  session_.Present();
341  }
342 
343  // Render the recorded SkPictures into the surfaces.
344  {
345  TRACE_EVENT0("flutter", "RasterizeSurfaces");
346 
347  for (const auto& surface_index : frame_surface_indices) {
348  TRACE_EVENT0("flutter", "RasterizeSurface");
349 
350  const auto& layer = frame_layers_.find(surface_index.first);
351  FML_DCHECK(layer != frame_layers_.end());
352  sk_sp<SkPicture> picture =
353  layer->second.recorder->finishRecordingAsPicture();
354  FML_DCHECK(picture);
355 
356  sk_sp<SkSurface> sk_surface =
357  frame_surfaces[surface_index.second]->GetSkiaSurface();
358  FML_DCHECK(sk_surface);
359  FML_DCHECK(SkISize::Make(sk_surface->width(), sk_surface->height()) ==
360  frame_size_);
361 
362  SkCanvas* canvas = sk_surface->getCanvas();
363  FML_DCHECK(canvas);
364 
365  canvas->setMatrix(SkMatrix::I());
366  canvas->clear(SK_ColorTRANSPARENT);
367  canvas->drawPicture(picture);
368  canvas->flush();
369  }
370  }
371 
372  // Flush deferred Skia work and inform Scenic that render targets are ready.
373  {
374  TRACE_EVENT0("flutter", "PresentSurfaces");
375 
376  surface_producer_.OnSurfacesPresented(std::move(frame_surfaces));
377  }
378 
379  // Submit the underlying render-backend-specific frame for processing.
380  frame->Submit();
381 }
#define TRACE_EVENT0(category_group, name)
Definition: trace_event.h:75
#define FML_DCHECK(condition)
Definition: logging.h:86
CanvasImage Image
Definition: image.cc:15
scenic::Session * get() override
void OnSurfacesPresented(std::vector< std::unique_ptr< SurfaceProducerSurface >> surfaces)
constexpr float kScenicZElevationBetweenLayers
std::unique_ptr< SurfaceProducerSurface > ProduceSurface(const SkISize &size) override

◆ SupportsDynamicThreadMerging()

bool flutter_runner::FuchsiaExternalViewEmbedder::SupportsDynamicThreadMerging ( )
inlineoverridevirtual

The documentation for this class was generated from the following files: