Flutter Engine
rasterizer.cc
Go to the documentation of this file.
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/common/rasterizer.h"
6 
7 #include <utility>
8 
9 #include "flutter/fml/time/time_delta.h"
10 #include "flutter/fml/time/time_point.h"
11 #include "flutter/shell/common/persistent_cache.h"
12 #include "flutter/shell/common/serialization_callbacks.h"
13 #include "third_party/skia/include/core/SkEncodedImageFormat.h"
14 #include "third_party/skia/include/core/SkImageEncoder.h"
15 #include "third_party/skia/include/core/SkPictureRecorder.h"
16 #include "third_party/skia/include/core/SkSerialProcs.h"
17 #include "third_party/skia/include/core/SkSurface.h"
18 #include "third_party/skia/include/core/SkSurfaceCharacterization.h"
19 #include "third_party/skia/include/utils/SkBase64.h"
20 
21 // When screenshotting we want to ensure we call the base method for
22 // CompositorContext::AcquireFrame instead of the platform-specific method.
23 // Specifically, Fuchsia's CompositorContext handles the rendering surface
24 // itself which means that we will still continue to render to the onscreen
25 // surface if we don't call the base method.
26 // TODO(arbreng: fxb/55805)
27 #if defined(LEGACY_FUCHSIA_EMBEDDER)
28 #define ACQUIRE_FRAME flutter::CompositorContext::AcquireFrame
29 #else
30 #define ACQUIRE_FRAME AcquireFrame
31 #endif
32 
33 namespace flutter {
34 
35 // The rasterizer will tell Skia to purge cached resources that have not been
36 // used within this interval.
37 static constexpr std::chrono::milliseconds kSkiaCleanupExpiration(15000);
38 
40  : delegate_(delegate),
41  compositor_context_(std::make_unique<flutter::CompositorContext>(
42  delegate.GetFrameBudget())),
43  user_override_resource_cache_bytes_(false),
44  weak_factory_(this) {
45  FML_DCHECK(compositor_context_);
46 }
47 
48 #if defined(LEGACY_FUCHSIA_EMBEDDER)
49 // TODO(arbreng: fxb/55805)
51  Delegate& delegate,
52  std::unique_ptr<flutter::CompositorContext> compositor_context)
53  : delegate_(delegate),
54  compositor_context_(std::move(compositor_context)),
55  user_override_resource_cache_bytes_(false),
56  weak_factory_(this) {
57  FML_DCHECK(compositor_context_);
58 }
59 #endif
60 
61 Rasterizer::~Rasterizer() = default;
62 
64  return weak_factory_.GetWeakPtr();
65 }
66 
68  const {
69  return weak_factory_.GetWeakPtr();
70 }
71 
72 void Rasterizer::Setup(std::unique_ptr<Surface> surface) {
73  surface_ = std::move(surface);
74  if (max_cache_bytes_.has_value()) {
75  SetResourceCacheMaxBytes(max_cache_bytes_.value(),
76  user_override_resource_cache_bytes_);
77  }
78  compositor_context_->OnGrContextCreated();
79  if (surface_->GetExternalViewEmbedder() &&
80  surface_->GetExternalViewEmbedder()->SupportsDynamicThreadMerging() &&
81  !raster_thread_merger_) {
82  const auto platform_id =
84  const auto gpu_id =
86  raster_thread_merger_ =
87  fml::MakeRefCounted<fml::RasterThreadMerger>(platform_id, gpu_id);
88  }
89  if (raster_thread_merger_) {
90  raster_thread_merger_->SetMergeUnmergeCallback([=]() {
91  // Clear the GL context after the thread configuration has changed.
92  if (surface_) {
93  surface_->ClearRenderContext();
94  }
95  });
96  }
97 }
98 
100  compositor_context_->OnGrContextDestroyed();
101  surface_.reset();
102  last_layer_tree_.reset();
103 
104  if (raster_thread_merger_.get() != nullptr &&
105  raster_thread_merger_.get()->IsMerged()) {
106  FML_DCHECK(raster_thread_merger_->IsEnabled());
107  raster_thread_merger_->UnMergeNow();
108  raster_thread_merger_->SetMergeUnmergeCallback(nullptr);
109  }
110 }
111 
113  if (raster_thread_merger_) {
114  raster_thread_merger_->Enable();
115  }
116 }
117 
119  if (raster_thread_merger_) {
120  raster_thread_merger_->Disable();
121  }
122 }
123 
125  if (!surface_) {
126  FML_DLOG(INFO)
127  << "Rasterizer::NotifyLowMemoryWarning called with no surface.";
128  return;
129  }
130  auto context = surface_->GetContext();
131  if (!context) {
132  FML_DLOG(INFO)
133  << "Rasterizer::NotifyLowMemoryWarning called with no GrContext.";
134  return;
135  }
136  context->performDeferredCleanup(std::chrono::milliseconds(0));
137 }
138 
140  return &compositor_context_->texture_registry();
141 }
142 
144  return last_layer_tree_.get();
145 }
146 
148  if (!last_layer_tree_ || !surface_) {
149  return;
150  }
151  DrawToSurface(*last_layer_tree_);
152 }
153 
155  LayerTreeDiscardCallback discardCallback) {
156  TRACE_EVENT0("flutter", "GPURasterizer::Draw");
157  if (raster_thread_merger_ &&
158  !raster_thread_merger_->IsOnRasterizingThread()) {
159  // we yield and let this frame be serviced on the right thread.
160  return;
161  }
162  FML_DCHECK(delegate_.GetTaskRunners()
165 
166  RasterStatus raster_status = RasterStatus::kFailed;
168  [&](std::unique_ptr<LayerTree> layer_tree) {
169  if (discardCallback(*layer_tree.get())) {
170  raster_status = RasterStatus::kDiscarded;
171  } else {
172  raster_status = DoDraw(std::move(layer_tree));
173  }
174  };
175 
176  PipelineConsumeResult consume_result = pipeline->Consume(consumer);
177  // if the raster status is to resubmit the frame, we push the frame to the
178  // front of the queue and also change the consume status to more available.
179 
180  auto should_resubmit_frame = raster_status == RasterStatus::kResubmit ||
181  raster_status == RasterStatus::kSkipAndRetry;
182  if (should_resubmit_frame) {
183  auto front_continuation = pipeline->ProduceIfEmpty();
184  bool result =
185  front_continuation.Complete(std::move(resubmitted_layer_tree_));
186  if (result) {
187  consume_result = PipelineConsumeResult::MoreAvailable;
188  }
189  } else if (raster_status == RasterStatus::kEnqueuePipeline) {
190  consume_result = PipelineConsumeResult::MoreAvailable;
191  }
192 
193  // Merging the thread as we know the next `Draw` should be run on the platform
194  // thread.
195  if (surface_ != nullptr && surface_->GetExternalViewEmbedder() != nullptr) {
196  surface_->GetExternalViewEmbedder()->EndFrame(should_resubmit_frame,
197  raster_thread_merger_);
198  }
199 
200  // Consume as many pipeline items as possible. But yield the event loop
201  // between successive tries.
202  switch (consume_result) {
205  [weak_this = weak_factory_.GetWeakPtr(), pipeline]() {
206  if (weak_this) {
207  weak_this->Draw(pipeline);
208  }
209  });
210  break;
211  }
212  default:
213  break;
214  }
215 }
216 
217 namespace {
218 sk_sp<SkImage> DrawSnapshot(
219  sk_sp<SkSurface> surface,
220  const std::function<void(SkCanvas*)>& draw_callback) {
221  if (surface == nullptr || surface->getCanvas() == nullptr) {
222  return nullptr;
223  }
224 
225  draw_callback(surface->getCanvas());
226  surface->getCanvas()->flush();
227 
228  sk_sp<SkImage> device_snapshot;
229  {
230  TRACE_EVENT0("flutter", "MakeDeviceSnpashot");
231  device_snapshot = surface->makeImageSnapshot();
232  }
233 
234  if (device_snapshot == nullptr) {
235  return nullptr;
236  }
237 
238  {
239  TRACE_EVENT0("flutter", "DeviceHostTransfer");
240  if (auto raster_image = device_snapshot->makeRasterImage()) {
241  return raster_image;
242  }
243  }
244 
245  return nullptr;
246 }
247 } // namespace
248 
249 sk_sp<SkImage> Rasterizer::DoMakeRasterSnapshot(
250  SkISize size,
251  std::function<void(SkCanvas*)> draw_callback) {
252  TRACE_EVENT0("flutter", __FUNCTION__);
253  sk_sp<SkImage> result;
254  SkImageInfo image_info = SkImageInfo::MakeN32Premul(
255  size.width(), size.height(), SkColorSpace::MakeSRGB());
256  if (surface_ == nullptr || surface_->GetContext() == nullptr) {
257  // Raster surface is fine if there is no on screen surface. This might
258  // happen in case of software rendering.
259  sk_sp<SkSurface> surface = SkSurface::MakeRaster(image_info);
260  result = DrawSnapshot(surface, draw_callback);
261  } else {
262  delegate_.GetIsGpuDisabledSyncSwitch()->Execute(
264  .SetIfTrue([&] {
265  sk_sp<SkSurface> surface = SkSurface::MakeRaster(image_info);
266  result = DrawSnapshot(surface, draw_callback);
267  })
268  .SetIfFalse([&] {
269  auto context_switch = surface_->MakeRenderContextCurrent();
270  if (!context_switch->GetResult()) {
271  return;
272  }
273 
274  // When there is an on screen surface, we need a render target
275  // SkSurface because we want to access texture backed images.
276  sk_sp<SkSurface> surface = SkSurface::MakeRenderTarget(
277  surface_->GetContext(), // context
278  SkBudgeted::kNo, // budgeted
279  image_info // image info
280  );
281  result = DrawSnapshot(surface, draw_callback);
282  }));
283  }
284 
285  return result;
286 }
287 
288 sk_sp<SkImage> Rasterizer::MakeRasterSnapshot(sk_sp<SkPicture> picture,
289  SkISize picture_size) {
290  return DoMakeRasterSnapshot(picture_size,
291  [picture = std::move(picture)](SkCanvas* canvas) {
292  canvas->drawPicture(picture);
293  });
294 }
295 
296 sk_sp<SkImage> Rasterizer::ConvertToRasterImage(sk_sp<SkImage> image) {
297  TRACE_EVENT0("flutter", __FUNCTION__);
298 
299  // If the rasterizer does not have a surface with a GrContext, then it will
300  // be unable to render a cross-context SkImage. The caller will need to
301  // create the raster image on the IO thread.
302  if (surface_ == nullptr || surface_->GetContext() == nullptr) {
303  return nullptr;
304  }
305 
306  if (image == nullptr) {
307  return nullptr;
308  }
309 
310  return DoMakeRasterSnapshot(image->dimensions(),
311  [image = std::move(image)](SkCanvas* canvas) {
312  canvas->drawImage(image, 0, 0);
313  });
314 }
315 
316 RasterStatus Rasterizer::DoDraw(
317  std::unique_ptr<flutter::LayerTree> layer_tree) {
318  FML_DCHECK(delegate_.GetTaskRunners()
321 
322  if (!layer_tree || !surface_) {
323  return RasterStatus::kFailed;
324  }
325 
326  FrameTiming timing;
327 #if !defined(OS_FUCHSIA)
328  const fml::TimePoint frame_target_time = layer_tree->target_time();
329 #endif
330  timing.Set(FrameTiming::kVsyncStart, layer_tree->vsync_start());
331  timing.Set(FrameTiming::kBuildStart, layer_tree->build_start());
332  timing.Set(FrameTiming::kBuildFinish, layer_tree->build_finish());
334 
336  persistent_cache->ResetStoredNewShaders();
337 
338  RasterStatus raster_status = DrawToSurface(*layer_tree);
339  if (raster_status == RasterStatus::kSuccess) {
340  last_layer_tree_ = std::move(layer_tree);
341  } else if (raster_status == RasterStatus::kResubmit ||
342  raster_status == RasterStatus::kSkipAndRetry) {
343  resubmitted_layer_tree_ = std::move(layer_tree);
344  return raster_status;
345  }
346 
347  if (persistent_cache->IsDumpingSkp() &&
348  persistent_cache->StoredNewShaders()) {
349  auto screenshot =
351  persistent_cache->DumpSkp(*screenshot.data);
352  }
353 
354  // TODO(liyuqian): in Fuchsia, the rasterization doesn't finish when
355  // Rasterizer::DoDraw finishes. Future work is needed to adapt the timestamp
356  // for Fuchsia to capture SceneUpdateContext::ExecutePaintTasks.
357  const auto raster_finish_time = fml::TimePoint::Now();
358  timing.Set(FrameTiming::kRasterFinish, raster_finish_time);
359  delegate_.OnFrameRasterized(timing);
360 
361 // SceneDisplayLag events are disabled on Fuchsia.
362 // see: https://github.com/flutter/flutter/issues/56598
363 #if !defined(OS_FUCHSIA)
364  if (raster_finish_time > frame_target_time) {
365  fml::TimePoint latest_frame_target_time =
366  delegate_.GetLatestFrameTargetTime();
367  const auto frame_budget_millis = delegate_.GetFrameBudget().count();
368  if (latest_frame_target_time < raster_finish_time) {
369  latest_frame_target_time =
370  latest_frame_target_time +
371  fml::TimeDelta::FromMillisecondsF(frame_budget_millis);
372  }
373  const auto frame_lag =
374  (latest_frame_target_time - frame_target_time).ToMillisecondsF();
375  const int vsync_transitions_missed = round(frame_lag / frame_budget_millis);
377  "flutter", // category
378  "SceneDisplayLag", // name
379  raster_finish_time, // begin_time
380  latest_frame_target_time, // end_time
381  "frame_target_time", // arg_key_1
382  frame_target_time, // arg_val_1
383  "current_frame_target_time", // arg_key_2
384  latest_frame_target_time, // arg_val_2
385  "vsync_transitions_missed", // arg_key_3
386  vsync_transitions_missed // arg_val_3
387  );
388  }
389 #endif
390 
391  // Pipeline pressure is applied from a couple of places:
392  // rasterizer: When there are more items as of the time of Consume.
393  // animator (via shell): Frame gets produces every vsync.
394  // Enqueing here is to account for the following scenario:
395  // T = 1
396  // - one item (A) in the pipeline
397  // - rasterizer starts (and merges the threads)
398  // - pipeline consume result says no items to process
399  // T = 2
400  // - animator produces (B) to the pipeline
401  // - applies pipeline pressure via platform thread.
402  // T = 3
403  // - rasterizes finished (and un-merges the threads)
404  // - |Draw| for B yields as its on the wrong thread.
405  // This enqueue ensures that we attempt to consume from the right
406  // thread one more time after un-merge.
407  if (raster_thread_merger_) {
408  if (raster_thread_merger_->DecrementLease() ==
411  }
412  }
413 
414  return raster_status;
415 }
416 
417 RasterStatus Rasterizer::DrawToSurface(flutter::LayerTree& layer_tree) {
418  TRACE_EVENT0("flutter", "Rasterizer::DrawToSurface");
419  FML_DCHECK(surface_);
420 
421  // There is no way for the compositor to know how long the layer tree
422  // construction took. Fortunately, the layer tree does. Grab that time
423  // for instrumentation.
424  compositor_context_->ui_time().SetLapTime(layer_tree.build_time());
425 
426  auto* external_view_embedder = surface_->GetExternalViewEmbedder();
427 
428  SkCanvas* embedder_root_canvas = nullptr;
429  if (external_view_embedder != nullptr) {
430  external_view_embedder->BeginFrame(
431  layer_tree.frame_size(), surface_->GetContext(),
432  layer_tree.device_pixel_ratio(), raster_thread_merger_);
433  embedder_root_canvas = external_view_embedder->GetRootCanvas();
434  }
435 
436  // On Android, the external view embedder deletes surfaces in `BeginFrame`.
437  //
438  // Deleting a surface also clears the GL context. Therefore, acquire the
439  // frame after calling `BeginFrame` as this operation resets the GL context.
440  auto frame = surface_->AcquireFrame(layer_tree.frame_size());
441 
442  if (frame == nullptr) {
443  return RasterStatus::kFailed;
444  }
445 
446  // If the external view embedder has specified an optional root surface, the
447  // root surface transformation is set by the embedder instead of
448  // having to apply it here.
449  SkMatrix root_surface_transformation =
450  embedder_root_canvas ? SkMatrix{} : surface_->GetRootTransformation();
451 
452  auto root_surface_canvas =
453  embedder_root_canvas ? embedder_root_canvas : frame->SkiaCanvas();
454 
455  auto compositor_frame = compositor_context_->AcquireFrame(
456  surface_->GetContext(), // skia GrContext
457  root_surface_canvas, // root surface canvas
458  external_view_embedder, // external view embedder
459  root_surface_transformation, // root surface transformation
460  true, // instrumentation enabled
461  frame->supports_readback(), // surface supports pixel reads
462  raster_thread_merger_ // thread merger
463  );
464 
465  if (compositor_frame) {
466  RasterStatus raster_status = compositor_frame->Raster(layer_tree, false);
467  if (raster_status == RasterStatus::kFailed ||
468  raster_status == RasterStatus::kSkipAndRetry) {
469  return raster_status;
470  }
471  if (external_view_embedder != nullptr) {
472  FML_DCHECK(!frame->IsSubmitted());
473  external_view_embedder->SubmitFrame(surface_->GetContext(),
474  std::move(frame));
475  } else {
476  frame->Submit();
477  }
478 
479  FireNextFrameCallbackIfPresent();
480 
481  if (surface_->GetContext()) {
482  TRACE_EVENT0("flutter", "PerformDeferredSkiaCleanup");
483  surface_->GetContext()->performDeferredCleanup(kSkiaCleanupExpiration);
484  }
485 
486  return raster_status;
487  }
488 
489  return RasterStatus::kFailed;
490 }
491 
492 static sk_sp<SkData> ScreenshotLayerTreeAsPicture(
493  flutter::LayerTree* tree,
494  flutter::CompositorContext& compositor_context) {
495  FML_DCHECK(tree != nullptr);
496  SkPictureRecorder recorder;
497  recorder.beginRecording(
498  SkRect::MakeWH(tree->frame_size().width(), tree->frame_size().height()));
499 
500  SkMatrix root_surface_transformation;
501  root_surface_transformation.reset();
502 
503  // TODO(amirh): figure out how to take a screenshot with embedded UIView.
504  // https://github.com/flutter/flutter/issues/23435
505  auto frame = compositor_context.ACQUIRE_FRAME(
506  nullptr, recorder.getRecordingCanvas(), nullptr,
507  root_surface_transformation, false, true, nullptr);
508  frame->Raster(*tree, true);
509 
510 #if defined(OS_FUCHSIA)
511  SkSerialProcs procs = {0};
512  procs.fImageProc = SerializeImageWithoutData;
513 #else
514  SkSerialProcs procs = {0};
515  procs.fTypefaceProc = SerializeTypefaceWithData;
516 #endif
517 
518  return recorder.finishRecordingAsPicture()->serialize(&procs);
519 }
520 
521 static sk_sp<SkSurface> CreateSnapshotSurface(GrDirectContext* surface_context,
522  const SkISize& size) {
523  const auto image_info = SkImageInfo::MakeN32Premul(
524  size.width(), size.height(), SkColorSpace::MakeSRGB());
525  if (surface_context) {
526  // There is a rendering surface that may contain textures that are going to
527  // be referenced in the layer tree about to be drawn.
528  return SkSurface::MakeRenderTarget(surface_context, //
529  SkBudgeted::kNo, //
530  image_info //
531  );
532  }
533 
534  // There is no rendering surface, assume no GPU textures are present and
535  // create a raster surface.
536  return SkSurface::MakeRaster(image_info);
537 }
538 
539 sk_sp<SkData> Rasterizer::ScreenshotLayerTreeAsImage(
540  flutter::LayerTree* tree,
541  flutter::CompositorContext& compositor_context,
542  GrDirectContext* surface_context,
543  bool compressed) {
544  // Attempt to create a snapshot surface depending on whether we have access to
545  // a valid GPU rendering context.
546  auto snapshot_surface =
547  CreateSnapshotSurface(surface_context, tree->frame_size());
548  if (snapshot_surface == nullptr) {
549  FML_LOG(ERROR) << "Screenshot: unable to create snapshot surface";
550  return nullptr;
551  }
552 
553  // Draw the current layer tree into the snapshot surface.
554  auto* canvas = snapshot_surface->getCanvas();
555 
556  // There is no root surface transformation for the screenshot layer. Reset the
557  // matrix to identity.
558  SkMatrix root_surface_transformation;
559  root_surface_transformation.reset();
560 
561  // snapshot_surface->makeImageSnapshot needs the GL context to be set if the
562  // render context is GL. frame->Raster() pops the gl context in platforms that
563  // gl context switching are used. (For example, older iOS that uses GL) We
564  // reset the GL context using the context switch.
565  auto context_switch = surface_->MakeRenderContextCurrent();
566  if (!context_switch->GetResult()) {
567  FML_LOG(ERROR) << "Screenshot: unable to make image screenshot";
568  return nullptr;
569  }
570 
571  auto frame = compositor_context.ACQUIRE_FRAME(
572  surface_context, canvas, nullptr, root_surface_transformation, false,
573  true, nullptr);
574  canvas->clear(SK_ColorTRANSPARENT);
575  frame->Raster(*tree, true);
576  canvas->flush();
577 
578  // Prepare an image from the surface, this image may potentially be on th GPU.
579  auto potentially_gpu_snapshot = snapshot_surface->makeImageSnapshot();
580  if (!potentially_gpu_snapshot) {
581  FML_LOG(ERROR) << "Screenshot: unable to make image screenshot";
582  return nullptr;
583  }
584 
585  // Copy the GPU image snapshot into CPU memory.
586  auto cpu_snapshot = potentially_gpu_snapshot->makeRasterImage();
587  if (!cpu_snapshot) {
588  FML_LOG(ERROR) << "Screenshot: unable to make raster image";
589  return nullptr;
590  }
591 
592  // If the caller want the pixels to be compressed, there is a Skia utility to
593  // compress to PNG. Use that.
594  if (compressed) {
595  return cpu_snapshot->encodeToData();
596  }
597 
598  // Copy it into a bitmap and return the same.
599  SkPixmap pixmap;
600  if (!cpu_snapshot->peekPixels(&pixmap)) {
601  FML_LOG(ERROR) << "Screenshot: unable to obtain bitmap pixels";
602  return nullptr;
603  }
604  return SkData::MakeWithCopy(pixmap.addr32(), pixmap.computeByteSize());
605 }
606 
609  bool base64_encode) {
610  auto* layer_tree = GetLastLayerTree();
611  if (layer_tree == nullptr) {
612  FML_LOG(ERROR) << "Last layer tree was null when screenshotting.";
613  return {};
614  }
615 
616  sk_sp<SkData> data = nullptr;
617 
618  GrDirectContext* surface_context =
619  surface_ ? surface_->GetContext() : nullptr;
620 
621  switch (type) {
623  data = ScreenshotLayerTreeAsPicture(layer_tree, *compositor_context_);
624  break;
626  data = ScreenshotLayerTreeAsImage(layer_tree, *compositor_context_,
627  surface_context, false);
628  break;
630  data = ScreenshotLayerTreeAsImage(layer_tree, *compositor_context_,
631  surface_context, true);
632  break;
633  }
634 
635  if (data == nullptr) {
636  FML_LOG(ERROR) << "Screenshot data was null.";
637  return {};
638  }
639 
640  if (base64_encode) {
641  size_t b64_size = SkBase64::Encode(data->data(), data->size(), nullptr);
642  auto b64_data = SkData::MakeUninitialized(b64_size);
643  SkBase64::Encode(data->data(), data->size(), b64_data->writable_data());
644  return Rasterizer::Screenshot{b64_data, layer_tree->frame_size()};
645  }
646 
647  return Rasterizer::Screenshot{data, layer_tree->frame_size()};
648 }
649 
651  next_frame_callback_ = callback;
652 }
653 
654 void Rasterizer::FireNextFrameCallbackIfPresent() {
655  if (!next_frame_callback_) {
656  return;
657  }
658  // It is safe for the callback to set a new callback.
659  auto callback = next_frame_callback_;
660  next_frame_callback_ = nullptr;
661  callback();
662 }
663 
664 void Rasterizer::SetResourceCacheMaxBytes(size_t max_bytes, bool from_user) {
665  user_override_resource_cache_bytes_ |= from_user;
666 
667  if (!from_user && user_override_resource_cache_bytes_) {
668  // We should not update the setting here if a user has explicitly set a
669  // value for this over the flutter/skia channel.
670  return;
671  }
672 
673  max_cache_bytes_ = max_bytes;
674  if (!surface_) {
675  return;
676  }
677 
678  GrDirectContext* context = surface_->GetContext();
679  if (context) {
680  int max_resources;
681  context->getResourceCacheLimits(&max_resources, nullptr);
682  context->setResourceCacheLimits(max_resources, max_bytes);
683  }
684 }
685 
686 std::optional<size_t> Rasterizer::GetResourceCacheMaxBytes() const {
687  if (!surface_) {
688  return std::nullopt;
689  }
690  GrDirectContext* context = surface_->GetContext();
691  if (context) {
692  size_t max_bytes;
693  context->getResourceCacheLimits(nullptr, &max_bytes);
694  return max_bytes;
695  }
696  return std::nullopt;
697 }
698 
700 
701 Rasterizer::Screenshot::Screenshot(sk_sp<SkData> p_data, SkISize p_size)
702  : data(std::move(p_data)), frame_size(p_size) {}
703 
704 Rasterizer::Screenshot::Screenshot(const Screenshot& other) = default;
705 
707 
708 } // namespace flutter
PipelineConsumeResult
Definition: pipeline.h:19
std::optional< size_t > GetResourceCacheMaxBytes() const
The current value of Skia&#39;s resource cache size, if a surface is present.
Definition: rasterizer.cc:686
virtual TaskQueueId GetTaskQueueId()
Definition: task_runner.cc:38
void Setup(std::unique_ptr< Surface > surface)
Rasterizers may be created well before an on-screen surface is available for rendering. Shells usually create a rasterizer in their constructors. Once an on-screen surface is available however, one may be provided to the rasterizer using this call. No rendering may occur before this call. The surface is held till the balancing call to Rasterizer::Teardown is made. Calling a setup before tearing down the previous surface (if this is not the first time the surface has been setup) is user error.
Definition: rasterizer.cc:72
virtual std::shared_ptr< fml::SyncSwitch > GetIsGpuDisabledSyncSwitch() const =0
#define TRACE_EVENT0(category_group, name)
Definition: trace_event.h:75
void DumpSkp(const SkData &data)
#define FML_DCHECK(condition)
Definition: logging.h:86
const SkISize & frame_size() const
Definition: layer_tree.h:49
fml::TimePoint Set(Phase phase, fml::TimePoint value)
Definition: settings.h:39
fml::TaskRunnerAffineWeakPtr< Rasterizer > GetWeakPtr() const
Gets a weak pointer to the rasterizer. The rasterizer may only be accessed on the GPU task runner...
Definition: rasterizer.cc:63
Definition: ref_ptr.h:252
Dart_NativeFunction function
Definition: fuchsia.cc:51
fml::RefPtr< fml::TaskRunner > GetPlatformTaskRunner() const
Definition: task_runners.cc:30
virtual void PostTask(const fml::closure &task)
Definition: task_runner.cc:24
constexpr std::size_t size(T(&array)[N])
Definition: size.h:13
void Teardown()
Releases the previously setup on-screen render surface and collects associated resources. No more rendering may occur till the next call to Rasterizer::Setup with a new render surface. Calling a teardown without a setup is user error.
Definition: rasterizer.cc:99
~Screenshot()
Destroys the screenshot object and releases underlying data.
#define FML_LOG(severity)
Definition: logging.h:65
static constexpr std::chrono::milliseconds kSkiaCleanupExpiration(15000)
sk_sp< SkData > SerializeImageWithoutData(SkImage *image, void *ctx)
void DrawLastLayerTree()
Draws a last layer tree to the render surface. This may seem entirely redundant at first glance...
Definition: rasterizer.cc:147
Screenshot ScreenshotLastLayerTree(ScreenshotType type, bool base64_encode)
Screenshots the last layer tree to one of the supported screenshot types and optionally Base 64 encod...
Definition: rasterizer.cc:607
fml::RefPtr< fml::TaskRunner > GetRasterTaskRunner() const
Definition: task_runners.cc:42
virtual const TaskRunners & GetTaskRunners() const =0
Task runners used by the shell.
sk_sp< SkData > SerializeTypefaceWithData(SkTypeface *typeface, void *ctx)
virtual fml::TimePoint GetLatestFrameTargetTime() const =0
void DisableThreadMergerIfNeeded()
Disables the thread merger if the external view embedder supports dynamic thread merging.
Definition: rasterizer.cc:118
MockDelegate delegate_
std::function< void()> closure
Definition: closure.h:14
RasterThreadStatus DecrementLease()
void EnableThreadMergerIfNeeded()
Enables the thread merger if the external view embedder supports dynamic thread merging.
Definition: rasterizer.cc:112
A POD type used to return the screenshot data along with the size of the frame.
Definition: rasterizer.h:279
void SetMergeUnmergeCallback(const fml::closure &callback)
ScreenshotType
The type of the screenshot to obtain of the previously rendered layer tree.
Definition: rasterizer.h:249
void SetNextFrameCallback(const fml::closure &callback)
Sets a callback that will be executed when the next layer tree in rendered to the on-screen surface...
Definition: rasterizer.cc:650
Screenshot()
Creates an empty screenshot.
Definition: rasterizer.cc:699
void Draw(fml::RefPtr< Pipeline< flutter::LayerTree >> pipeline, LayerTreeDiscardCallback discardCallback=NoDiscard)
Takes the next item from the layer tree pipeline and executes the raster thread frame workload for th...
Definition: rasterizer.cc:154
static sk_sp< SkData > ScreenshotLayerTreeAsPicture(flutter::LayerTree *tree, flutter::CompositorContext &compositor_context)
Definition: rasterizer.cc:492
Used to forward events from the rasterizer to interested subsystems. Currently, the shell sets itself...
Definition: rasterizer.h:53
std::function< bool(flutter::LayerTree &)> LayerTreeDiscardCallback
Definition: rasterizer.h:209
std::function< void(ResourcePtr)> Consumer
Definition: pipeline.h:136
T * get() const
Definition: ref_ptr.h:112
static sk_sp< SkSurface > CreateSnapshotSurface(GrDirectContext *surface_context, const SkISize &size)
Definition: rasterizer.cc:521
~Rasterizer()
Destroys the rasterizer. This must happen on the GPU task runner. All GPU resources are collected bef...
fml::TimeDelta build_time() const
Definition: layer_tree.h:59
flutter::TextureRegistry * GetTextureRegistry()
Gets the registry of external textures currently in use by the rasterizer. These textures may be upda...
Definition: rasterizer.cc:139
float device_pixel_ratio() const
Definition: layer_tree.h:50
fml::TaskRunnerAffineWeakPtr< SnapshotDelegate > GetSnapshotDelegate() const
Definition: rasterizer.cc:67
static PersistentCache * GetCacheForProcess()
virtual fml::Milliseconds GetFrameBudget()=0
Rasterizer(Delegate &delegate)
Creates a new instance of a rasterizer. Rasterizers may only be created on the GPU task runner...
Definition: rasterizer.cc:39
virtual bool RunsTasksOnCurrentThread()
Definition: task_runner.cc:43
#define FML_DLOG(severity)
Definition: logging.h:85
void TraceEventAsyncComplete(TraceArg category_group, TraceArg name, TimePoint begin, TimePoint end)
Definition: trace_event.cc:326
flutter::CompositorContext * compositor_context()
Returns a pointer to the compositor context used by this rasterizer. This pointer will never be nullp...
Definition: rasterizer.h:358
flutter::LayerTree * GetLastLayerTree()
Sometimes, it may be necessary to render the same frame again without having to wait for the framewor...
Definition: rasterizer.cc:143
void SetResourceCacheMaxBytes(size_t max_bytes, bool from_user)
Skia has no notion of time. To work around the performance implications of this, it may cache GPU res...
Definition: rasterizer.cc:664
virtual void OnFrameRasterized(const FrameTiming &frame_timing)=0
Notifies the delegate that a frame has been rendered. The rasterizer collects profiling information f...
static TimePoint Now()
Definition: time_point.cc:26
static constexpr TimeDelta FromMillisecondsF(double millis)
Definition: time_delta.h:57
void NotifyLowMemoryWarning() const
Notifies the rasterizer that there is a low memory situation and it must purge as many unnecessary re...
Definition: rasterizer.cc:124
Represents the 2 code paths available when calling |SyncSwitch::Execute|.
Definition: sync_switch.h:24