• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2013 The Flutter Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "flutter/shell/platform/embedder/embedder_external_view_embedder.h"
6 
7 #include <algorithm>
8 
9 #include "flutter/shell/platform/embedder/embedder_render_target.h"
10 
11 namespace flutter {
12 
EmbedderExternalViewEmbedder(CreateRenderTargetCallback create_render_target_callback,PresentCallback present_callback)13 EmbedderExternalViewEmbedder::EmbedderExternalViewEmbedder(
14     CreateRenderTargetCallback create_render_target_callback,
15     PresentCallback present_callback)
16     : create_render_target_callback_(create_render_target_callback),
17       present_callback_(present_callback) {
18   FML_DCHECK(create_render_target_callback_);
19   FML_DCHECK(present_callback_);
20 }
21 
22 EmbedderExternalViewEmbedder::~EmbedderExternalViewEmbedder() = default;
23 
Reset()24 void EmbedderExternalViewEmbedder::Reset() {
25   pending_recorders_.clear();
26   pending_params_.clear();
27   composition_order_.clear();
28 }
29 
30 // |ExternalViewEmbedder|
CancelFrame()31 void EmbedderExternalViewEmbedder::CancelFrame() {
32   Reset();
33 }
34 
MakeBackingStoreConfig(const SkISize & size)35 static FlutterBackingStoreConfig MakeBackingStoreConfig(const SkISize& size) {
36   FlutterBackingStoreConfig config = {};
37 
38   config.struct_size = sizeof(config);
39 
40   config.size.width = size.width();
41   config.size.height = size.height();
42 
43   return config;
44 }
45 
46 // |ExternalViewEmbedder|
BeginFrame(SkISize frame_size,GrContext * context)47 void EmbedderExternalViewEmbedder::BeginFrame(SkISize frame_size,
48                                               GrContext* context) {
49   Reset();
50   pending_frame_size_ = frame_size;
51 
52   // Decide if we want to discard the previous root render target.
53   if (root_render_target_) {
54     auto surface = root_render_target_->GetRenderSurface();
55     // This is unlikely to happen but the embedder could have given the
56     // rasterizer a render target the previous frame that Skia could not
57     // materialize into a renderable surface. Discard the target and try again.
58     if (!surface) {
59       root_render_target_ = nullptr;
60     } else {
61       auto last_surface_size =
62           SkISize::Make(surface->width(), surface->height());
63       if (pending_frame_size_ != last_surface_size) {
64         root_render_target_ = nullptr;
65       }
66     }
67   }
68 
69   // If there is no root render target, create one now. This will be accessed by
70   // the rasterizer before the submit call layer to access the surface surface
71   // canvas.
72   if (!root_render_target_) {
73     root_render_target_ = create_render_target_callback_(
74         context, MakeBackingStoreConfig(pending_frame_size_));
75   }
76 }
77 
78 // |ExternalViewEmbedder|
PrerollCompositeEmbeddedView(int view_id,std::unique_ptr<EmbeddedViewParams> params)79 void EmbedderExternalViewEmbedder::PrerollCompositeEmbeddedView(
80     int view_id,
81     std::unique_ptr<EmbeddedViewParams> params) {
82   FML_DCHECK(pending_recorders_.count(view_id) == 0);
83   FML_DCHECK(pending_params_.count(view_id) == 0);
84   FML_DCHECK(std::find(composition_order_.begin(), composition_order_.end(),
85                        view_id) == composition_order_.end());
86 
87   pending_recorders_[view_id] = std::make_unique<SkPictureRecorder>();
88   pending_params_[view_id] = *params;
89   composition_order_.push_back(view_id);
90 }
91 
92 // |ExternalViewEmbedder|
GetCurrentCanvases()93 std::vector<SkCanvas*> EmbedderExternalViewEmbedder::GetCurrentCanvases() {
94   std::vector<SkCanvas*> canvases;
95   for (const auto& recorder : pending_recorders_) {
96     canvases.push_back(recorder.second->beginRecording(
97         pending_frame_size_.width(), pending_frame_size_.height()));
98   }
99   return canvases;
100 }
101 
102 // |ExternalViewEmbedder|
CompositeEmbeddedView(int view_id)103 SkCanvas* EmbedderExternalViewEmbedder::CompositeEmbeddedView(int view_id) {
104   auto found = pending_recorders_.find(view_id);
105   if (found == pending_recorders_.end()) {
106     FML_DCHECK(false) << "Attempted to composite a view that was not "
107                          "pre-rolled.";
108     return nullptr;
109   }
110   return found->second->getRecordingCanvas();
111 }
112 
MakeLayer(const SkISize & frame_size,const FlutterBackingStore * store)113 static FlutterLayer MakeLayer(const SkISize& frame_size,
114                               const FlutterBackingStore* store) {
115   FlutterLayer layer = {};
116 
117   layer.struct_size = sizeof(layer);
118   layer.type = kFlutterLayerContentTypeBackingStore;
119   layer.backing_store = store;
120 
121   layer.offset.x = 0.0;
122   layer.offset.y = 0.0;
123 
124   layer.size.width = frame_size.width();
125   layer.size.height = frame_size.height();
126 
127   return layer;
128 }
129 
MakePlatformView(FlutterPlatformViewIdentifier identifier)130 static FlutterPlatformView MakePlatformView(
131     FlutterPlatformViewIdentifier identifier) {
132   FlutterPlatformView view = {};
133 
134   view.struct_size = sizeof(view);
135 
136   view.identifier = identifier;
137 
138   return view;
139 }
140 
MakeLayer(const EmbeddedViewParams & params,const FlutterPlatformView & platform_view)141 static FlutterLayer MakeLayer(const EmbeddedViewParams& params,
142                               const FlutterPlatformView& platform_view) {
143   FlutterLayer layer = {};
144 
145   layer.struct_size = sizeof(layer);
146   layer.type = kFlutterLayerContentTypePlatformView;
147   layer.platform_view = &platform_view;
148 
149   layer.offset.x = params.offsetPixels.x();
150   layer.offset.y = params.offsetPixels.y();
151 
152   layer.size.width = params.sizePoints.width();
153   layer.size.height = params.sizePoints.height();
154 
155   return layer;
156 }
157 
158 // |ExternalViewEmbedder|
SubmitFrame(GrContext * context)159 bool EmbedderExternalViewEmbedder::SubmitFrame(GrContext* context) {
160   std::map<FlutterPlatformViewIdentifier, FlutterPlatformView>
161       presented_platform_views;
162   // Layers may contain pointers to platform views in the collection above.
163   std::vector<FlutterLayer> presented_layers;
164   Registry render_targets_used;
165 
166   if (!root_render_target_) {
167     FML_LOG(ERROR)
168         << "Could not acquire the root render target from the embedder.";
169     return false;
170   }
171 
172   {
173     // The root surface is expressed as a layer.
174     EmbeddedViewParams params;
175     params.offsetPixels = SkPoint::Make(0, 0);
176     params.sizePoints = pending_frame_size_;
177     presented_layers.push_back(
178         MakeLayer(pending_frame_size_, root_render_target_->GetBackingStore()));
179   }
180 
181   for (const auto& view_id : composition_order_) {
182     FML_DCHECK(pending_recorders_.count(view_id) == 1);
183     FML_DCHECK(pending_params_.count(view_id) == 1);
184 
185     const auto& params = pending_params_.at(view_id);
186     auto& recorder = pending_recorders_.at(view_id);
187 
188     auto picture = recorder->finishRecordingAsPicture();
189     if (!picture) {
190       FML_LOG(ERROR) << "Could not finish recording into the picture before "
191                         "on-screen composition.";
192       return false;
193     }
194 
195     const auto backing_store_config =
196         MakeBackingStoreConfig(pending_frame_size_);
197 
198     RegistryKey registry_key(view_id, backing_store_config);
199 
200     auto found_render_target = registry_.find(registry_key);
201 
202     // Find a cached render target in the registry. If none exists, ask the
203     // embedder for a new one.
204     std::shared_ptr<EmbedderRenderTarget> render_target;
205     if (found_render_target == registry_.end()) {
206       render_target =
207           create_render_target_callback_(context, backing_store_config);
208     } else {
209       render_target = found_render_target->second;
210     }
211 
212     if (!render_target) {
213       FML_LOG(ERROR) << "Could not acquire external render target for "
214                         "on-screen composition.";
215       return false;
216     }
217 
218     render_targets_used[registry_key] = render_target;
219 
220     auto render_surface = render_target->GetRenderSurface();
221     auto render_canvas = render_surface ? render_surface->getCanvas() : nullptr;
222 
223     if (!render_canvas) {
224       FML_LOG(ERROR)
225           << "Could not acquire render canvas for on-screen rendering.";
226       return false;
227     }
228 
229     render_canvas->clear(SK_ColorTRANSPARENT);
230     render_canvas->drawPicture(picture);
231     render_canvas->flush();
232 
233     // Indicate a layer for the platform view. Add to `presented_platform_views`
234     // in order to keep at allocated just for the scope of the current method.
235     // The layers presented to the embedder will contain a back pointer to this
236     // struct. It is safe to deallocate when the embedder callback is done.
237     presented_platform_views[view_id] = MakePlatformView(view_id);
238     presented_layers.push_back(
239         MakeLayer(params, presented_platform_views.at(view_id)));
240 
241     // Indicate a layer for the backing store containing contents rendered by
242     // Flutter.
243     presented_layers.push_back(
244         MakeLayer(pending_frame_size_, render_target->GetBackingStore()));
245   }
246 
247   {
248     std::vector<const FlutterLayer*> presented_layers_pointers;
249     presented_layers_pointers.reserve(presented_layers.size());
250     for (const auto& layer : presented_layers) {
251       presented_layers_pointers.push_back(&layer);
252     }
253     present_callback_(std::move(presented_layers_pointers));
254   }
255 
256   registry_ = std::move(render_targets_used);
257 
258   return true;
259 }
260 
261 // |ExternalViewEmbedder|
GetRootSurface()262 sk_sp<SkSurface> EmbedderExternalViewEmbedder::GetRootSurface() {
263   return root_render_target_ ? root_render_target_->GetRenderSurface()
264                              : nullptr;
265 }
266 
267 }  // namespace flutter
268