Flutter Engine
The 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 <algorithm>
8#include <memory>
9#include <utility>
10
12#include "flow/frame_timings.h"
13#include "flutter/common/constants.h"
14#include "flutter/common/graphics/persistent_cache.h"
15#include "flutter/flow/layers/offscreen_surface.h"
16#include "flutter/fml/time/time_delta.h"
17#include "flutter/fml/time/time_point.h"
18#include "flutter/shell/common/base64.h"
19#include "flutter/shell/common/serialization_callbacks.h"
20#include "fml/closure.h"
21#include "fml/make_copyable.h"
39
40#if IMPELLER_SUPPORTS_RENDERING
41#include "impeller/aiks/aiks_context.h" // nogncheck
42#include "impeller/core/formats.h" // nogncheck
43#include "impeller/display_list/dl_dispatcher.h" // nogncheck
44#endif
45
46namespace flutter {
47
48// The rasterizer will tell Skia to purge cached resources that have not been
49// used within this interval.
50[[maybe_unused]] static constexpr std::chrono::milliseconds
52
54 MakeGpuImageBehavior gpu_image_behavior)
55 : delegate_(delegate),
56 gpu_image_behavior_(gpu_image_behavior),
57 compositor_context_(std::make_unique<flutter::CompositorContext>(*this)),
58 snapshot_controller_(
59 SnapshotController::Make(*this, delegate.GetSettings())),
60 weak_factory_(this) {
61 FML_DCHECK(compositor_context_);
62}
63
64Rasterizer::~Rasterizer() = default;
65
67 return weak_factory_.GetWeakPtr();
68}
69
71 const {
72 return weak_factory_.GetWeakPtr();
73}
74
76 std::weak_ptr<impeller::Context> impeller_context) {
77 impeller_context_ = std::move(impeller_context);
78}
79
80void Rasterizer::Setup(std::unique_ptr<Surface> surface) {
81 surface_ = std::move(surface);
82
83 if (max_cache_bytes_.has_value()) {
84 SetResourceCacheMaxBytes(max_cache_bytes_.value(),
85 user_override_resource_cache_bytes_);
86 }
87
88 auto context_switch = surface_->MakeRenderContextCurrent();
89 if (context_switch->GetResult()) {
90 compositor_context_->OnGrContextCreated();
91 }
92
93 if (external_view_embedder_ &&
94 external_view_embedder_->SupportsDynamicThreadMerging() &&
95 !raster_thread_merger_) {
96 const auto platform_id =
98 const auto gpu_id =
101 delegate_.GetParentRasterThreadMerger(), platform_id, gpu_id);
102 }
103 if (raster_thread_merger_) {
104 raster_thread_merger_->SetMergeUnmergeCallback([this]() {
105 // Clear the GL context after the thread configuration has changed.
106 if (surface_) {
107 surface_->ClearRenderContext();
108 }
109 });
110 }
111}
112
114 if (external_view_embedder_) {
115 external_view_embedder_->Teardown();
116 }
117}
118
120 is_torn_down_ = true;
121 if (surface_) {
122 auto context_switch = surface_->MakeRenderContextCurrent();
123 if (context_switch->GetResult()) {
124 compositor_context_->OnGrContextDestroyed();
125#if !SLIMPELLER
126 if (auto* context = surface_->GetContext()) {
127 context->purgeUnlockedResources(GrPurgeResourceOptions::kAllResources);
128 }
129#endif // !SLIMPELLER
130 }
131 surface_.reset();
132 }
133
134 view_records_.clear();
135
136 if (raster_thread_merger_.get() != nullptr &&
137 raster_thread_merger_.get()->IsMerged()) {
138 FML_DCHECK(raster_thread_merger_->IsEnabled());
139 raster_thread_merger_->UnMergeNowIfLastOne();
140 raster_thread_merger_->SetMergeUnmergeCallback(nullptr);
141 }
142}
143
145 return is_torn_down_;
146}
147
148std::optional<DrawSurfaceStatus> Rasterizer::GetLastDrawStatus(
149 int64_t view_id) {
150 auto found = view_records_.find(view_id);
151 if (found != view_records_.end()) {
152 return found->second.last_draw_status;
153 } else {
154 return std::optional<DrawSurfaceStatus>();
155 }
156}
157
159 if (raster_thread_merger_) {
160 raster_thread_merger_->Enable();
161 }
162}
163
165 if (raster_thread_merger_) {
166 raster_thread_merger_->Disable();
167 }
168}
169
171#if !SLIMPELLER
172 if (!surface_) {
173 FML_DLOG(INFO)
174 << "Rasterizer::NotifyLowMemoryWarning called with no surface.";
175 return;
176 }
177 auto context = surface_->GetContext();
178 if (!context) {
179 FML_DLOG(INFO)
180 << "Rasterizer::NotifyLowMemoryWarning called with no GrContext.";
181 return;
182 }
183 auto context_switch = surface_->MakeRenderContextCurrent();
184 if (!context_switch->GetResult()) {
185 return;
186 }
187 context->performDeferredCleanup(std::chrono::milliseconds(0));
188#endif // !SLIMPELLER
189}
190
191void Rasterizer::CollectView(int64_t view_id) {
192 if (external_view_embedder_) {
193 external_view_embedder_->CollectView(view_id);
194 }
195 view_records_.erase(view_id);
196}
197
198std::shared_ptr<flutter::TextureRegistry> Rasterizer::GetTextureRegistry() {
199 return compositor_context_->texture_registry();
200}
201
203 return surface_ ? surface_->GetContext() : nullptr;
204}
205
207 auto found = view_records_.find(view_id);
208 if (found == view_records_.end()) {
209 return nullptr;
210 }
211 auto& last_task = found->second.last_successful_task;
212 if (last_task == nullptr) {
213 return nullptr;
214 }
215 return last_task->layer_tree.get();
216}
217
219 std::unique_ptr<FrameTimingsRecorder> frame_timings_recorder) {
220 if (!surface_) {
221 return;
222 }
223 std::vector<std::unique_ptr<LayerTreeTask>> tasks;
224 for (auto& [view_id, view_record] : view_records_) {
225 if (view_record.last_successful_task) {
226 tasks.push_back(std::move(view_record.last_successful_task));
227 }
228 }
229 if (tasks.empty()) {
230 return;
231 }
232
233 DoDrawResult result =
234 DrawToSurfaces(*frame_timings_recorder, std::move(tasks));
235
236 // EndFrame should perform cleanups for the external_view_embedder.
237 if (external_view_embedder_ && external_view_embedder_->GetUsedThisFrame()) {
238 bool should_resubmit_frame = ShouldResubmitFrame(result);
239 external_view_embedder_->SetUsedThisFrame(false);
240 external_view_embedder_->EndFrame(should_resubmit_frame,
241 raster_thread_merger_);
242 }
243}
244
245DrawStatus Rasterizer::Draw(const std::shared_ptr<FramePipeline>& pipeline) {
246 TRACE_EVENT0("flutter", "GPURasterizer::Draw");
247 if (raster_thread_merger_ &&
248 !raster_thread_merger_->IsOnRasterizingThread()) {
249 // we yield and let this frame be serviced on the right thread.
251 }
252 FML_DCHECK(delegate_.GetTaskRunners()
255
256 DoDrawResult draw_result;
257 FramePipeline::Consumer consumer = [&draw_result,
258 this](std::unique_ptr<FrameItem> item) {
259 draw_result = DoDraw(std::move(item->frame_timings_recorder),
260 std::move(item->layer_tree_tasks));
261 };
262
263 PipelineConsumeResult consume_result = pipeline->Consume(consumer);
264 if (consume_result == PipelineConsumeResult::NoneAvailable) {
266 }
267 // if the raster status is to resubmit the frame, we push the frame to the
268 // front of the queue and also change the consume status to more available.
269
270 bool should_resubmit_frame = ShouldResubmitFrame(draw_result);
271 if (should_resubmit_frame) {
272 FML_CHECK(draw_result.resubmitted_item);
273 auto front_continuation = pipeline->ProduceIfEmpty();
274 PipelineProduceResult pipeline_result =
275 front_continuation.Complete(std::move(draw_result.resubmitted_item));
276 if (pipeline_result.success) {
278 }
279 } else if (draw_result.status == DoDrawStatus::kEnqueuePipeline) {
281 }
282
283 // EndFrame should perform cleanups for the external_view_embedder.
284 if (external_view_embedder_ && external_view_embedder_->GetUsedThisFrame()) {
285 external_view_embedder_->SetUsedThisFrame(false);
286 external_view_embedder_->EndFrame(should_resubmit_frame,
287 raster_thread_merger_);
288 }
289
290 // Consume as many pipeline items as possible. But yield the event loop
291 // between successive tries.
292 switch (consume_result) {
295 [weak_this = weak_factory_.GetWeakPtr(), pipeline]() {
296 if (weak_this) {
297 weak_this->Draw(pipeline);
298 }
299 });
300 break;
301 }
302 default:
303 break;
304 }
305
306 return ToDrawStatus(draw_result.status);
307}
308
309bool Rasterizer::ShouldResubmitFrame(const DoDrawResult& result) {
310 if (result.resubmitted_item) {
311 FML_CHECK(!result.resubmitted_item->layer_tree_tasks.empty());
312 return true;
313 }
314 return false;
315}
316
317DrawStatus Rasterizer::ToDrawStatus(DoDrawStatus status) {
318 switch (status) {
319 case DoDrawStatus::kEnqueuePipeline:
320 return DrawStatus::kDone;
321 case DoDrawStatus::kNotSetUp:
322 return DrawStatus::kNotSetUp;
323 case DoDrawStatus::kGpuUnavailable:
324 return DrawStatus::kGpuUnavailable;
325 case DoDrawStatus::kDone:
326 return DrawStatus::kDone;
327 }
329}
330
331#if !SLIMPELLER
332namespace {
333std::unique_ptr<SnapshotDelegate::GpuImageResult> MakeBitmapImage(
334 const sk_sp<DisplayList>& display_list,
335 const SkImageInfo& image_info) {
336 FML_DCHECK(display_list);
337 // Use 16384 as a proxy for the maximum texture size for a GPU image.
338 // This is meant to be large enough to avoid false positives in test contexts,
339 // but not so artificially large to be completely unrealistic on any platform.
340 // This limit is taken from the Metal specification. D3D, Vulkan, and GL
341 // generally have lower limits.
342 if (image_info.width() > 16384 || image_info.height() > 16384) {
343 return std::make_unique<SnapshotDelegate::GpuImageResult>(
344 GrBackendTexture(), nullptr, nullptr,
345 "unable to create bitmap render target at specified size " +
346 std::to_string(image_info.width()) + "x" +
347 std::to_string(image_info.height()));
348 };
349
351 auto canvas = DlSkCanvasAdapter(surface->getCanvas());
352 canvas.Clear(DlColor::kTransparent());
353 canvas.DrawDisplayList(display_list);
354
355 sk_sp<SkImage> image = surface->makeImageSnapshot();
356 return std::make_unique<SnapshotDelegate::GpuImageResult>(
357 GrBackendTexture(), nullptr, image,
358 image ? "" : "Unable to create image");
359}
360} // namespace
361#endif // !SLIMPELLER
362
363std::unique_ptr<Rasterizer::GpuImageResult> Rasterizer::MakeSkiaGpuImage(
364 sk_sp<DisplayList> display_list,
365 const SkImageInfo& image_info) {
366#if SLIMPELLER
367 FML_LOG(FATAL) << "Impeller opt-out unavailable.";
368 return nullptr;
369#else // SLIMPELLER
370 TRACE_EVENT0("flutter", "Rasterizer::MakeGpuImage");
371 FML_DCHECK(display_list);
372
373 std::unique_ptr<SnapshotDelegate::GpuImageResult> result;
374 delegate_.GetIsGpuDisabledSyncSwitch()->Execute(
376 .SetIfTrue([&result, &image_info, &display_list] {
377 // TODO(dnfield): This isn't safe if display_list contains any GPU
378 // resources like an SkImage_gpu.
379 result = MakeBitmapImage(display_list, image_info);
380 })
381 .SetIfFalse([&result, &image_info, &display_list,
382 surface = surface_.get(),
383 gpu_image_behavior = gpu_image_behavior_] {
384 if (!surface ||
385 gpu_image_behavior == MakeGpuImageBehavior::kBitmap) {
386 // TODO(dnfield): This isn't safe if display_list contains any GPU
387 // resources like an SkImage_gpu.
388 result = MakeBitmapImage(display_list, image_info);
389 return;
390 }
391
392 auto context_switch = surface->MakeRenderContextCurrent();
393 if (!context_switch->GetResult()) {
394 result = MakeBitmapImage(display_list, image_info);
395 return;
396 }
397
398 auto* context = surface->GetContext();
399 if (!context) {
400 result = MakeBitmapImage(display_list, image_info);
401 return;
402 }
403
404 GrBackendTexture texture = context->createBackendTexture(
405 image_info.width(), image_info.height(), image_info.colorType(),
407 if (!texture.isValid()) {
408 result = std::make_unique<SnapshotDelegate::GpuImageResult>(
409 GrBackendTexture(), nullptr, nullptr,
410 "unable to create texture render target at specified size " +
411 std::to_string(image_info.width()) + "x" +
412 std::to_string(image_info.height()));
413 return;
414 }
415
417 context, texture, kTopLeft_GrSurfaceOrigin, /*sampleCnt=*/0,
418 image_info.colorType(), image_info.refColorSpace(), nullptr);
419 if (!sk_surface) {
420 result = std::make_unique<SnapshotDelegate::GpuImageResult>(
421 GrBackendTexture(), nullptr, nullptr,
422 "unable to create rendering surface for image");
423 return;
424 }
425
426 auto canvas = DlSkCanvasAdapter(sk_surface->getCanvas());
427 canvas.Clear(DlColor::kTransparent());
428 canvas.DrawDisplayList(display_list);
429
430 result = std::make_unique<SnapshotDelegate::GpuImageResult>(
431 texture, sk_ref_sp(context), nullptr, "");
432 }));
433 return result;
434#endif // !SLIMPELLER
435}
436
437void Rasterizer::MakeRasterSnapshot(
438 sk_sp<DisplayList> display_list,
439 SkISize picture_size,
441 return snapshot_controller_->MakeRasterSnapshot(display_list, picture_size,
442 callback);
443}
444
445sk_sp<DlImage> Rasterizer::MakeRasterSnapshotSync(
446 sk_sp<DisplayList> display_list,
447 SkISize picture_size) {
448 return snapshot_controller_->MakeRasterSnapshotSync(display_list,
449 picture_size);
450}
451
452sk_sp<SkImage> Rasterizer::ConvertToRasterImage(sk_sp<SkImage> image) {
453 TRACE_EVENT0("flutter", __FUNCTION__);
454 return snapshot_controller_->ConvertToRasterImage(image);
455}
456
457// |SnapshotDelegate|
458void Rasterizer::CacheRuntimeStage(
459 const std::shared_ptr<impeller::RuntimeStage>& runtime_stage) {
460 snapshot_controller_->CacheRuntimeStage(runtime_stage);
461}
462
463fml::Milliseconds Rasterizer::GetFrameBudget() const {
464 return delegate_.GetFrameBudget();
465};
466
467Rasterizer::DoDrawResult Rasterizer::DoDraw(
468 std::unique_ptr<FrameTimingsRecorder> frame_timings_recorder,
469 std::vector<std::unique_ptr<LayerTreeTask>> tasks) {
470 TRACE_EVENT_WITH_FRAME_NUMBER(frame_timings_recorder, "flutter",
471 "Rasterizer::DoDraw", /*flow_id_count=*/0,
472 /*flow_ids=*/nullptr);
473 FML_DCHECK(delegate_.GetTaskRunners()
474 .GetRasterTaskRunner()
475 ->RunsTasksOnCurrentThread());
476 frame_timings_recorder->AssertInState(FrameTimingsRecorder::State::kBuildEnd);
477
478 if (tasks.empty()) {
479 return DoDrawResult{DoDrawStatus::kDone};
480 }
481 if (!surface_) {
482 return DoDrawResult{DoDrawStatus::kNotSetUp};
483 }
484
485#if !SLIMPELLER
486 PersistentCache* persistent_cache = PersistentCache::GetCacheForProcess();
487 persistent_cache->ResetStoredNewShaders();
488#endif // !SLIMPELLER
489
490 DoDrawResult result =
491 DrawToSurfaces(*frame_timings_recorder, std::move(tasks));
492
493 FML_DCHECK(result.status != DoDrawStatus::kEnqueuePipeline);
494 if (result.status == DoDrawStatus::kGpuUnavailable) {
495 return DoDrawResult{DoDrawStatus::kGpuUnavailable};
496 }
497
498#if !SLIMPELLER
499 if (persistent_cache->IsDumpingSkp() &&
500 persistent_cache->StoredNewShaders()) {
501 auto screenshot =
502 ScreenshotLastLayerTree(ScreenshotType::SkiaPicture, false);
503 persistent_cache->DumpSkp(*screenshot.data);
504 }
505#endif // !SLIMPELLER
506
507 // TODO(liyuqian): in Fuchsia, the rasterization doesn't finish when
508 // Rasterizer::DoDraw finishes. Future work is needed to adapt the timestamp
509 // for Fuchsia to capture SceneUpdateContext::ExecutePaintTasks.
510 delegate_.OnFrameRasterized(frame_timings_recorder->GetRecordedTime());
511
512// SceneDisplayLag events are disabled on Fuchsia.
513// see: https://github.com/flutter/flutter/issues/56598
514#if !defined(OS_FUCHSIA)
515 const fml::TimePoint raster_finish_time =
516 frame_timings_recorder->GetRasterEndTime();
517 fml::TimePoint frame_target_time =
518 frame_timings_recorder->GetVsyncTargetTime();
519 if (raster_finish_time > frame_target_time) {
520 fml::TimePoint latest_frame_target_time =
521 delegate_.GetLatestFrameTargetTime();
522 const auto frame_budget_millis = delegate_.GetFrameBudget().count();
523 if (latest_frame_target_time < raster_finish_time) {
524 latest_frame_target_time =
525 latest_frame_target_time +
526 fml::TimeDelta::FromMillisecondsF(frame_budget_millis);
527 }
528 const auto frame_lag =
529 (latest_frame_target_time - frame_target_time).ToMillisecondsF();
530 const int vsync_transitions_missed = round(frame_lag / frame_budget_millis);
532 "flutter", // category
533 "SceneDisplayLag", // name
534 raster_finish_time, // begin_time
535 latest_frame_target_time, // end_time
536 "frame_target_time", // arg_key_1
537 frame_target_time, // arg_val_1
538 "current_frame_target_time", // arg_key_2
539 latest_frame_target_time, // arg_val_2
540 "vsync_transitions_missed", // arg_key_3
541 vsync_transitions_missed // arg_val_3
542 );
543 }
544#endif
545
546 // Pipeline pressure is applied from a couple of places:
547 // rasterizer: When there are more items as of the time of Consume.
548 // animator (via shell): Frame gets produces every vsync.
549 // Enqueing here is to account for the following scenario:
550 // T = 1
551 // - one item (A) in the pipeline
552 // - rasterizer starts (and merges the threads)
553 // - pipeline consume result says no items to process
554 // T = 2
555 // - animator produces (B) to the pipeline
556 // - applies pipeline pressure via platform thread.
557 // T = 3
558 // - rasterizes finished (and un-merges the threads)
559 // - |Draw| for B yields as its on the wrong thread.
560 // This enqueue ensures that we attempt to consume from the right
561 // thread one more time after un-merge.
562 if (raster_thread_merger_) {
563 if (raster_thread_merger_->DecrementLease() ==
565 return DoDrawResult{
566 .status = DoDrawStatus::kEnqueuePipeline,
567 .resubmitted_item = std::move(result.resubmitted_item),
568 };
569 }
570 }
571
572 return result;
573}
574
575Rasterizer::DoDrawResult Rasterizer::DrawToSurfaces(
576 FrameTimingsRecorder& frame_timings_recorder,
577 std::vector<std::unique_ptr<LayerTreeTask>> tasks) {
578 TRACE_EVENT0("flutter", "Rasterizer::DrawToSurfaces");
580 frame_timings_recorder.AssertInState(FrameTimingsRecorder::State::kBuildEnd);
581
582 DoDrawResult result{
583 .status = DoDrawStatus::kDone,
584 };
585 if (surface_->AllowsDrawingWhenGpuDisabled()) {
586 result.resubmitted_item =
587 DrawToSurfacesUnsafe(frame_timings_recorder, std::move(tasks));
588 } else {
589 delegate_.GetIsGpuDisabledSyncSwitch()->Execute(
591 .SetIfTrue([&] {
592 result.status = DoDrawStatus::kGpuUnavailable;
593 frame_timings_recorder.RecordRasterStart(fml::TimePoint::Now());
594 frame_timings_recorder.RecordRasterEnd();
595 })
596 .SetIfFalse([&] {
597 result.resubmitted_item = DrawToSurfacesUnsafe(
598 frame_timings_recorder, std::move(tasks));
599 }));
600 }
601 frame_timings_recorder.AssertInState(FrameTimingsRecorder::State::kRasterEnd);
602
603 return result;
604}
605
606std::unique_ptr<FrameItem> Rasterizer::DrawToSurfacesUnsafe(
607 FrameTimingsRecorder& frame_timings_recorder,
608 std::vector<std::unique_ptr<LayerTreeTask>> tasks) {
609 compositor_context_->ui_time().SetLapTime(
610 frame_timings_recorder.GetBuildDuration());
611
612 // First traverse: Filter out discarded trees
613 auto task_iter = tasks.begin();
614 while (task_iter != tasks.end()) {
615 LayerTreeTask& task = **task_iter;
616 if (delegate_.ShouldDiscardLayerTree(task.view_id, *task.layer_tree)) {
617 EnsureViewRecord(task.view_id).last_draw_status =
618 DrawSurfaceStatus::kDiscarded;
619 task_iter = tasks.erase(task_iter);
620 } else {
621 ++task_iter;
622 }
623 }
624 if (tasks.empty()) {
625 frame_timings_recorder.RecordRasterStart(fml::TimePoint::Now());
626 frame_timings_recorder.RecordRasterEnd();
627 return nullptr;
628 }
629
630 if (external_view_embedder_) {
631 FML_DCHECK(!external_view_embedder_->GetUsedThisFrame());
632 external_view_embedder_->SetUsedThisFrame(true);
633 external_view_embedder_->BeginFrame(surface_->GetContext(),
634 raster_thread_merger_);
635 }
636
637 std::optional<fml::TimePoint> presentation_time = std::nullopt;
638 // TODO (https://github.com/flutter/flutter/issues/105596): this can be in
639 // the past and might need to get snapped to future as this frame could
640 // have been resubmitted. `presentation_time` on SubmitInfo is not set
641 // in this case.
642 {
643 const auto vsync_target_time = frame_timings_recorder.GetVsyncTargetTime();
644 if (vsync_target_time > fml::TimePoint::Now()) {
645 presentation_time = vsync_target_time;
646 }
647 }
648
649 frame_timings_recorder.RecordRasterStart(fml::TimePoint::Now());
650
651 // Second traverse: draw all layer trees.
652 std::vector<std::unique_ptr<LayerTreeTask>> resubmitted_tasks;
653 for (std::unique_ptr<LayerTreeTask>& task : tasks) {
654 int64_t view_id = task->view_id;
655 std::unique_ptr<LayerTree> layer_tree = std::move(task->layer_tree);
656 float device_pixel_ratio = task->device_pixel_ratio;
657
658 DrawSurfaceStatus status = DrawToSurfaceUnsafe(
659 view_id, *layer_tree, device_pixel_ratio, presentation_time);
660 FML_DCHECK(status != DrawSurfaceStatus::kDiscarded);
661
662 auto& view_record = EnsureViewRecord(task->view_id);
663 view_record.last_draw_status = status;
664 if (status == DrawSurfaceStatus::kSuccess) {
665 view_record.last_successful_task = std::make_unique<LayerTreeTask>(
666 view_id, std::move(layer_tree), device_pixel_ratio);
667 } else if (status == DrawSurfaceStatus::kRetry) {
668 resubmitted_tasks.push_back(std::make_unique<LayerTreeTask>(
669 view_id, std::move(layer_tree), device_pixel_ratio));
670 }
671 }
672 // TODO(dkwingsmt): Pass in raster cache(s) for all views.
673 // See https://github.com/flutter/flutter/issues/135530, item 4.
674 frame_timings_recorder.RecordRasterEnd(
675 NOT_SLIMPELLER(&compositor_context_->raster_cache()));
676
677 FireNextFrameCallbackIfPresent();
678
679#if !SLIMPELLER
680 if (surface_->GetContext()) {
681 surface_->GetContext()->performDeferredCleanup(kSkiaCleanupExpiration);
682 }
683#endif // !SLIMPELLER
684
685 if (resubmitted_tasks.empty()) {
686 return nullptr;
687 } else {
688 return std::make_unique<FrameItem>(
689 std::move(resubmitted_tasks),
690 frame_timings_recorder.CloneUntil(
691 FrameTimingsRecorder::State::kBuildEnd));
692 }
693}
694
695/// \see Rasterizer::DrawToSurfaces
696DrawSurfaceStatus Rasterizer::DrawToSurfaceUnsafe(
697 int64_t view_id,
698 flutter::LayerTree& layer_tree,
699 float device_pixel_ratio,
700 std::optional<fml::TimePoint> presentation_time) {
702
703 DlCanvas* embedder_root_canvas = nullptr;
704 if (external_view_embedder_) {
705 external_view_embedder_->PrepareFlutterView(layer_tree.frame_size(),
706 device_pixel_ratio);
707 // TODO(dkwingsmt): Add view ID here.
708 embedder_root_canvas = external_view_embedder_->GetRootCanvas();
709 }
710
711 // On Android, the external view embedder deletes surfaces in `BeginFrame`.
712 //
713 // Deleting a surface also clears the GL context. Therefore, acquire the
714 // frame after calling `BeginFrame` as this operation resets the GL context.
715 auto frame = surface_->AcquireFrame(layer_tree.frame_size());
716 if (frame == nullptr) {
717 return DrawSurfaceStatus::kFailed;
718 }
719
720 // If the external view embedder has specified an optional root surface, the
721 // root surface transformation is set by the embedder instead of
722 // having to apply it here.
723 SkMatrix root_surface_transformation =
724 embedder_root_canvas ? SkMatrix{} : surface_->GetRootTransformation();
725
726 auto root_surface_canvas =
727 embedder_root_canvas ? embedder_root_canvas : frame->Canvas();
728 auto compositor_frame = compositor_context_->AcquireFrame(
729 surface_->GetContext(), // skia GrContext
730 root_surface_canvas, // root surface canvas
731 external_view_embedder_.get(), // external view embedder
732 root_surface_transformation, // root surface transformation
733 true, // instrumentation enabled
734 frame->framebuffer_info()
735 .supports_readback, // surface supports pixel reads
736 raster_thread_merger_, // thread merger
737 surface_->GetAiksContext().get() // aiks context
738 );
739 if (compositor_frame) {
740 NOT_SLIMPELLER(compositor_context_->raster_cache().BeginFrame());
741
742 std::unique_ptr<FrameDamage> damage;
743 // when leaf layer tracing is enabled we wish to repaint the whole frame
744 // for accurate performance metrics.
745 if (frame->framebuffer_info().supports_partial_repaint &&
746 !layer_tree.is_leaf_layer_tracing_enabled()) {
747 // Disable partial repaint if external_view_embedder_ SubmitFlutterView is
748 // involved - ExternalViewEmbedder unconditionally clears the entire
749 // surface and also partial repaint with platform view present is
750 // something that still need to be figured out.
751 bool force_full_repaint =
752 external_view_embedder_ &&
753 (!raster_thread_merger_ || raster_thread_merger_->IsMerged());
754
755 damage = std::make_unique<FrameDamage>();
756 auto existing_damage = frame->framebuffer_info().existing_damage;
757 if (existing_damage.has_value() && !force_full_repaint) {
758 damage->SetPreviousLayerTree(GetLastLayerTree(view_id));
759 damage->AddAdditionalDamage(existing_damage.value());
760 damage->SetClipAlignment(
761 frame->framebuffer_info().horizontal_clip_alignment,
762 frame->framebuffer_info().vertical_clip_alignment);
763 }
764 }
765
766 bool ignore_raster_cache = true;
767 if (surface_->EnableRasterCache() &&
768 !layer_tree.is_leaf_layer_tracing_enabled()) {
769 ignore_raster_cache = false;
770 }
771
772 RasterStatus frame_status =
773 compositor_frame->Raster(layer_tree, // layer tree
774 ignore_raster_cache, // ignore raster cache
775 damage.get() // frame damage
776 );
777 if (frame_status == RasterStatus::kSkipAndRetry) {
778 return DrawSurfaceStatus::kRetry;
779 }
780
781 SurfaceFrame::SubmitInfo submit_info;
782 submit_info.presentation_time = presentation_time;
783 if (damage) {
784 submit_info.frame_damage = damage->GetFrameDamage();
785 submit_info.buffer_damage = damage->GetBufferDamage();
786 }
787
788 frame->set_submit_info(submit_info);
789
790 if (external_view_embedder_ &&
791 (!raster_thread_merger_ || raster_thread_merger_->IsMerged())) {
792 FML_DCHECK(!frame->IsSubmitted());
793 external_view_embedder_->SubmitFlutterView(
794 view_id, surface_->GetContext(), surface_->GetAiksContext(),
795 std::move(frame));
796 } else {
797 frame->Submit();
798 }
799
800#if !SLIMPELLER
801 // Do not update raster cache metrics for kResubmit because that status
802 // indicates that the frame was not actually painted.
803 if (frame_status != RasterStatus::kResubmit) {
804 compositor_context_->raster_cache().EndFrame();
805 }
806#endif // !SLIMPELLER
807
808 if (frame_status == RasterStatus::kResubmit) {
809 return DrawSurfaceStatus::kRetry;
810 } else {
811 FML_CHECK(frame_status == RasterStatus::kSuccess);
813 }
814 }
815
816 return DrawSurfaceStatus::kFailed;
817}
818
819Rasterizer::ViewRecord& Rasterizer::EnsureViewRecord(int64_t view_id) {
820 return view_records_[view_id];
821}
822
824 flutter::LayerTree* tree,
825 flutter::CompositorContext& compositor_context) {
826#if SLIMPELLER
827 return nullptr;
828#else // SLIMPELLER
829 FML_DCHECK(tree != nullptr);
830 SkPictureRecorder recorder;
831 recorder.beginRecording(
832 SkRect::MakeWH(tree->frame_size().width(), tree->frame_size().height()));
833
834 SkMatrix root_surface_transformation;
835 root_surface_transformation.reset();
836 DlSkCanvasAdapter canvas(recorder.getRecordingCanvas());
837
838 // TODO(amirh): figure out how to take a screenshot with embedded UIView.
839 // https://github.com/flutter/flutter/issues/23435
840 auto frame = compositor_context.AcquireFrame(nullptr, &canvas, nullptr,
841 root_surface_transformation,
842 false, true, nullptr, nullptr);
843 frame->Raster(*tree, true, nullptr);
844
845#if defined(OS_FUCHSIA)
846 SkSerialProcs procs = {0};
849#else
850 SkSerialProcs procs = {0};
852 procs.fImageProc = [](SkImage* img, void*) -> sk_sp<SkData> {
853 return SkPngEncoder::Encode(nullptr, img, SkPngEncoder::Options{});
854 };
855#endif
856
857 return recorder.finishRecordingAsPicture()->serialize(&procs);
858#endif // SLIMPELLER
859}
860
862 flutter::CompositorContext& compositor_context,
863 DlCanvas* canvas,
864 flutter::LayerTree* tree,
865 GrDirectContext* surface_context,
866 const std::shared_ptr<impeller::AiksContext>& aiks_context) {
867 // There is no root surface transformation for the screenshot layer. Reset
868 // the matrix to identity.
869 SkMatrix root_surface_transformation;
870 root_surface_transformation.reset();
871
872 auto frame = compositor_context.AcquireFrame(
873 /*gr_context=*/surface_context,
874 /*canvas=*/canvas,
875 /*view_embedder=*/nullptr,
876 /*root_surface_transformation=*/root_surface_transformation,
877 /*instrumentation_enabled=*/false,
878 /*surface_supports_readback=*/true,
879 /*raster_thread_merger=*/nullptr,
880 /*aiks_context=*/aiks_context.get());
881 canvas->Clear(DlColor::kTransparent());
882 frame->Raster(*tree, true, nullptr);
883 canvas->Flush();
884}
885
886#if IMPELLER_SUPPORTS_RENDERING
887Rasterizer::ScreenshotFormat ToScreenshotFormat(impeller::PixelFormat format) {
888 switch (format) {
902 FML_DCHECK(false);
905 return Rasterizer::ScreenshotFormat::kR8G8B8A8UNormInt;
907 return Rasterizer::ScreenshotFormat::kB8G8R8A8UNormInt;
909 return Rasterizer::ScreenshotFormat::kR16G16B16A16Float;
910 }
911}
912
913static std::pair<sk_sp<SkData>, Rasterizer::ScreenshotFormat>
914ScreenshotLayerTreeAsImageImpeller(
915 const std::shared_ptr<impeller::AiksContext>& aiks_context,
916 flutter::LayerTree* tree,
917 flutter::CompositorContext& compositor_context,
918 bool compressed) {
919 if (compressed) {
920 FML_LOG(ERROR) << "Compressed screenshots not supported for Impeller";
922 }
923
924 DisplayListBuilder builder(SkRect::MakeSize(
925 SkSize::Make(tree->frame_size().fWidth, tree->frame_size().fHeight)));
926
927 RenderFrameForScreenshot(compositor_context, &builder, tree, nullptr,
928 aiks_context);
929
930 impeller::DlDispatcher dispatcher;
931 builder.Build()->Dispatch(dispatcher);
932 const auto& picture = dispatcher.EndRecordingAsPicture();
933 const auto& image = picture.ToImage(
934 *aiks_context,
936 const auto& texture = image->GetTexture();
939 buffer_desc.size =
940 texture->GetTextureDescriptor().GetByteSizeOfBaseMipLevel();
941 auto impeller_context = aiks_context->GetContext();
942 auto buffer =
943 impeller_context->GetResourceAllocator()->CreateBuffer(buffer_desc);
944 auto command_buffer = impeller_context->CreateCommandBuffer();
945 command_buffer->SetLabel("BlitTextureToBuffer Command Buffer");
946 auto pass = command_buffer->CreateBlitPass();
947 pass->AddCopy(texture, buffer);
948 pass->EncodeCommands(impeller_context->GetResourceAllocator());
950 sk_sp<SkData> sk_data;
951 auto completion = [buffer, &buffer_desc, &sk_data,
952 &latch](impeller::CommandBuffer::Status status) {
953 fml::ScopedCleanupClosure cleanup([&latch]() { latch.Signal(); });
955 FML_LOG(ERROR) << "Failed to complete blit pass.";
956 return;
957 }
958 sk_data = SkData::MakeWithCopy(buffer->OnGetContents(), buffer_desc.size);
959 };
960
961 if (!impeller_context->GetCommandQueue()
962 ->Submit({command_buffer}, completion)
963 .ok()) {
964 FML_LOG(ERROR) << "Failed to submit commands.";
965 }
966 latch.Wait();
967 return std::make_pair(
968 sk_data, ToScreenshotFormat(texture->GetTextureDescriptor().format));
969}
970#endif
971
972std::pair<sk_sp<SkData>, Rasterizer::ScreenshotFormat>
973Rasterizer::ScreenshotLayerTreeAsImage(
974 flutter::LayerTree* tree,
975 flutter::CompositorContext& compositor_context,
976 bool compressed) {
977#if IMPELLER_SUPPORTS_RENDERING
978 if (delegate_.GetSettings().enable_impeller) {
979 return ScreenshotLayerTreeAsImageImpeller(GetAiksContext(), tree,
980 compositor_context, compressed);
981 }
982#endif // IMPELLER_SUPPORTS_RENDERING
983
984#if SLIMPELLER
985 FML_LOG(FATAL) << "Impeller opt-out unavailable.";
986 return {nullptr, ScreenshotFormat::kUnknown};
987#else // SLIMPELLER
988 GrDirectContext* surface_context = GetGrContext();
989 // Attempt to create a snapshot surface depending on whether we have access
990 // to a valid GPU rendering context.
991 std::unique_ptr<OffscreenSurface> snapshot_surface =
992 std::make_unique<OffscreenSurface>(surface_context, tree->frame_size());
993
994 if (!snapshot_surface->IsValid()) {
995 FML_LOG(ERROR) << "Screenshot: unable to create snapshot surface";
996 return {nullptr, ScreenshotFormat::kUnknown};
997 }
998
999 // Draw the current layer tree into the snapshot surface.
1000 DlCanvas* canvas = snapshot_surface->GetCanvas();
1001
1002 // snapshot_surface->makeImageSnapshot needs the GL context to be set if the
1003 // render context is GL. frame->Raster() pops the gl context in platforms
1004 // that gl context switching are used. (For example, older iOS that uses GL)
1005 // We reset the GL context using the context switch.
1006 auto context_switch = surface_->MakeRenderContextCurrent();
1007 if (!context_switch->GetResult()) {
1008 FML_LOG(ERROR) << "Screenshot: unable to make image screenshot";
1009 return {nullptr, ScreenshotFormat::kUnknown};
1010 }
1011
1012 RenderFrameForScreenshot(compositor_context, canvas, tree, surface_context,
1013 nullptr);
1014
1015 return std::make_pair(snapshot_surface->GetRasterData(compressed),
1017#endif // !SLIMPELLER
1018}
1019
1020Rasterizer::Screenshot Rasterizer::ScreenshotLastLayerTree(
1022 bool base64_encode) {
1023 if (delegate_.GetSettings().enable_impeller &&
1024 type == ScreenshotType::SkiaPicture) {
1025 FML_DCHECK(false);
1026 FML_LOG(ERROR) << "Last layer tree cannot be screenshotted as a "
1027 "SkiaPicture when using Impeller.";
1028 return {};
1029 }
1030 // TODO(dkwingsmt): Support screenshotting all last layer trees
1031 // when the shell protocol supports multi-views.
1032 // https://github.com/flutter/flutter/issues/135534
1033 // https://github.com/flutter/flutter/issues/135535
1034 auto* layer_tree = GetLastLayerTree(kFlutterImplicitViewId);
1035 if (layer_tree == nullptr) {
1036 FML_LOG(ERROR) << "Last layer tree was null when screenshotting.";
1037 return {};
1038 }
1039
1040 std::pair<sk_sp<SkData>, ScreenshotFormat> data{nullptr,
1042 std::string format;
1043
1044 switch (type) {
1045 case ScreenshotType::SkiaPicture:
1046 format = "ScreenshotType::SkiaPicture";
1047 data.first =
1048 ScreenshotLayerTreeAsPicture(layer_tree, *compositor_context_);
1049 break;
1050 case ScreenshotType::UncompressedImage:
1051 format = "ScreenshotType::UncompressedImage";
1052 data =
1053 ScreenshotLayerTreeAsImage(layer_tree, *compositor_context_, false);
1054 break;
1055 case ScreenshotType::CompressedImage:
1056 format = "ScreenshotType::CompressedImage";
1057 data = ScreenshotLayerTreeAsImage(layer_tree, *compositor_context_, true);
1058 break;
1059 case ScreenshotType::SurfaceData: {
1060 Surface::SurfaceData surface_data = surface_->GetSurfaceData();
1061 format = surface_data.pixel_format;
1062 data.first = surface_data.data;
1063 break;
1064 }
1065 }
1066
1067 if (data.first == nullptr) {
1068 FML_LOG(ERROR) << "Screenshot data was null.";
1069 return {};
1070 }
1071
1072 if (base64_encode) {
1073 size_t b64_size = Base64::EncodedSize(data.first->size());
1074 auto b64_data = SkData::MakeUninitialized(b64_size);
1075 Base64::Encode(data.first->data(), data.first->size(),
1076 b64_data->writable_data());
1077 return Rasterizer::Screenshot{b64_data, layer_tree->frame_size(), format,
1078 data.second};
1079 }
1080
1081 return Rasterizer::Screenshot{data.first, layer_tree->frame_size(), format,
1082 data.second};
1083}
1084
1085void Rasterizer::SetNextFrameCallback(const fml::closure& callback) {
1086 next_frame_callback_ = callback;
1087}
1088
1089void Rasterizer::SetExternalViewEmbedder(
1090 const std::shared_ptr<ExternalViewEmbedder>& view_embedder) {
1091 external_view_embedder_ = view_embedder;
1092}
1093
1094void Rasterizer::SetSnapshotSurfaceProducer(
1095 std::unique_ptr<SnapshotSurfaceProducer> producer) {
1096 snapshot_surface_producer_ = std::move(producer);
1097}
1098
1099fml::RefPtr<fml::RasterThreadMerger> Rasterizer::GetRasterThreadMerger() {
1100 return raster_thread_merger_;
1101}
1102
1103void Rasterizer::FireNextFrameCallbackIfPresent() {
1104 if (!next_frame_callback_) {
1105 return;
1106 }
1107 // It is safe for the callback to set a new callback.
1108 auto callback = next_frame_callback_;
1109 next_frame_callback_ = nullptr;
1110 callback();
1111}
1112
1113void Rasterizer::SetResourceCacheMaxBytes(size_t max_bytes, bool from_user) {
1114#if !SLIMPELLER
1115 user_override_resource_cache_bytes_ |= from_user;
1116
1117 if (!from_user && user_override_resource_cache_bytes_) {
1118 // We should not update the setting here if a user has explicitly set a
1119 // value for this over the flutter/skia channel.
1120 return;
1121 }
1122
1123 max_cache_bytes_ = max_bytes;
1124 if (!surface_) {
1125 return;
1126 }
1127
1128 GrDirectContext* context = surface_->GetContext();
1129 if (context) {
1130 auto context_switch = surface_->MakeRenderContextCurrent();
1131 if (!context_switch->GetResult()) {
1132 return;
1133 }
1134
1135 context->setResourceCacheLimit(max_bytes);
1136 }
1137#endif // !SLIMPELLER
1138}
1139
1140std::optional<size_t> Rasterizer::GetResourceCacheMaxBytes() const {
1141#if SLIMPELLER
1142 return std::nullopt;
1143#else // SLIMPELLER
1144 if (!surface_) {
1145 return std::nullopt;
1146 }
1147 GrDirectContext* context = surface_->GetContext();
1148 if (context) {
1149 return context->getResourceCacheLimit();
1150 }
1151 return std::nullopt;
1152#endif // SLIMPELLER
1153}
1154
1155Rasterizer::Screenshot::Screenshot() {}
1156
1157Rasterizer::Screenshot::Screenshot(sk_sp<SkData> p_data,
1158 SkISize p_size,
1159 const std::string& p_format,
1160 ScreenshotFormat p_pixel_format)
1161 : data(std::move(p_data)),
1162 frame_size(p_size),
1163 format(p_format),
1164 pixel_format(p_pixel_format) {}
1165
1166Rasterizer::Screenshot::Screenshot(const Screenshot& other) = default;
1167
1169
1170} // namespace flutter
static void round(SkPoint *p)
@ kTopLeft_GrSurfaceOrigin
Definition: GrTypes.h:148
sk_sp< T > sk_ref_sp(T *obj)
Definition: SkRefCnt.h:381
GLenum type
size_t getResourceCacheLimit() const
void setResourceCacheLimit(size_t maxResourceBytes)
static sk_sp< SkData > MakeUninitialized(size_t length)
Definition: SkData.cpp:116
static sk_sp< SkData > MakeWithCopy(const void *data, size_t length)
Definition: SkData.cpp:111
SkScalar get(int index) const
Definition: SkMatrix.h:392
SkMatrix & reset()
Definition: SkMatrix.cpp:49
SkCanvas * beginRecording(const SkRect &bounds, sk_sp< SkBBoxHierarchy > bbh)
SkCanvas * getRecordingCanvas()
sk_sp< SkPicture > finishRecordingAsPicture()
sk_sp< SkData > serialize(const SkSerialProcs *procs=nullptr) const
Definition: SkPicture.cpp:249
SkCanvas * getCanvas()
Definition: SkSurface.cpp:82
virtual std::unique_ptr< ScopedFrame > AcquireFrame(GrDirectContext *gr_context, DlCanvas *canvas, ExternalViewEmbedder *view_embedder, const SkMatrix &root_surface_transformation, bool instrumentation_enabled, bool surface_supports_readback, fml::RefPtr< fml::RasterThreadMerger > raster_thread_merger, impeller::AiksContext *aiks_context)
Developer-facing API for rendering anything within the engine.
Definition: dl_canvas.h:38
void Clear(DlColor color)
Definition: dl_canvas.h:132
virtual void Flush()=0
Backend implementation of |DlCanvas| for |SkCanvas|.
Definition: dl_sk_canvas.h:20
const SkISize & frame_size() const
Definition: layer_tree.h:54
bool is_leaf_layer_tracing_enabled() const
Definition: layer_tree.h:69
std::function< void(ResourcePtr)> Consumer
Definition: pipeline.h:180
Used to forward events from the rasterizer to interested subsystems. Currently, the shell sets itself...
Definition: rasterizer.h:128
virtual const TaskRunners & GetTaskRunners() const =0
Task runners used by the shell.
virtual const fml::RefPtr< fml::RasterThreadMerger > GetParentRasterThreadMerger() const =0
The raster thread merger from parent shell's rasterizer.
bool IsTornDown()
Returns whether TearDown has been called.
Definition: rasterizer.cc:144
flutter::LayerTree * GetLastLayerTree(int64_t view_id)
Returns the last successfully drawn layer tree for the given view, or nullptr if there isn't any....
Definition: rasterizer.cc:206
ScreenshotType
The type of the screenshot to obtain of the previously rendered layer tree.
Definition: rasterizer.h:347
void DisableThreadMergerIfNeeded()
Disables the thread merger if the external view embedder supports dynamic thread merging.
Definition: rasterizer.cc:164
~Rasterizer()
Destroys the rasterizer. This must happen on the raster task runner. All GPU resources are collected ...
Rasterizer(Delegate &delegate, MakeGpuImageBehavior gpu_image_behavior=MakeGpuImageBehavior::kGpu)
Creates a new instance of a rasterizer. Rasterizers may only be created on the raster task runner....
Definition: rasterizer.cc:53
DrawStatus Draw(const std::shared_ptr< FramePipeline > &pipeline)
Takes the next item from the layer tree pipeline and executes the raster thread frame workload for th...
Definition: rasterizer.cc:245
fml::TaskRunnerAffineWeakPtr< Rasterizer > GetWeakPtr() const
Gets a weak pointer to the rasterizer. The rasterizer may only be accessed on the raster task runner.
Definition: rasterizer.cc:66
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:1113
void DrawLastLayerTrees(std::unique_ptr< FrameTimingsRecorder > frame_timings_recorder)
Draws the last layer trees with their last configuration. This may seem entirely redundant at first g...
Definition: rasterizer.cc:218
MakeGpuImageBehavior
How to handle calls to MakeSkiaGpuImage.
Definition: rasterizer.h:178
void TeardownExternalViewEmbedder()
Releases any resource used by the external view embedder. For example, overlay surfaces or Android vi...
Definition: rasterizer.cc:113
void EnableThreadMergerIfNeeded()
Enables the thread merger if the external view embedder supports dynamic thread merging.
Definition: rasterizer.cc:158
fml::TaskRunnerAffineWeakPtr< SnapshotDelegate > GetSnapshotDelegate() const
Definition: rasterizer.cc:70
std::shared_ptr< flutter::TextureRegistry > GetTextureRegistry() override
Gets the registry of external textures currently in use by the rasterizer. These textures may be upda...
Definition: rasterizer.cc:198
void Teardown()
Releases the previously set up on-screen render surface and collects associated resources....
Definition: rasterizer.cc:119
GrDirectContext * GetGrContext() override
Definition: rasterizer.cc:202
void CollectView(int64_t view_id)
Deallocate the resources for displaying a view.
Definition: rasterizer.cc:191
void Setup(std::unique_ptr< Surface > surface)
Rasterizers may be created well before an on-screen surface is available for rendering....
Definition: rasterizer.cc:80
std::optional< DrawSurfaceStatus > GetLastDrawStatus(int64_t view_id)
Returns the last status of drawing the specific view.
Definition: rasterizer.cc:148
void NotifyLowMemoryWarning() const
Notifies the rasterizer that there is a low memory situation and it must purge as many unnecessary re...
Definition: rasterizer.cc:170
void SetImpellerContext(std::weak_ptr< impeller::Context > impeller_context)
Definition: rasterizer.cc:75
fml::RefPtr< fml::TaskRunner > GetRasterTaskRunner() const
Definition: task_runners.cc:42
fml::RefPtr< fml::TaskRunner > GetPlatformTaskRunner() const
Definition: task_runners.cc:30
static fml::RefPtr< fml::RasterThreadMerger > CreateOrShareThreadMerger(const fml::RefPtr< fml::RasterThreadMerger > &parent_merger, TaskQueueId platform_id, TaskQueueId raster_id)
void SetMergeUnmergeCallback(const fml::closure &callback)
T * get() const
Definition: ref_ptr.h:116
Wraps a closure that is invoked in the destructor unless released by the caller.
Definition: closure.h:32
virtual void PostTask(const fml::closure &task) override
Definition: task_runner.cc:24
virtual bool RunsTasksOnCurrentThread()
Definition: task_runner.cc:43
virtual TaskQueueId GetTaskQueueId()
Definition: task_runner.cc:38
static constexpr TimeDelta FromMillisecondsF(double millis)
Definition: time_delta.h:57
static TimePoint Now()
Definition: time_point.cc:49
#define NOT_SLIMPELLER(code)
Definition: macros.h:16
static constexpr FlutterViewId kFlutterImplicitViewId
Definition: embedder.cc:108
@ kSuccess
Definition: embedder.h:73
MockDelegate delegate_
VkSurfaceKHR surface
Definition: main.cc:49
double frame
Definition: examples.cpp:31
#define FATAL(error)
FlKeyEvent uint64_t FlKeyResponderAsyncCallback callback
GAsyncResult * result
uint32_t uint32_t * format
#define FML_DLOG(severity)
Definition: logging.h:102
#define FML_LOG(severity)
Definition: logging.h:82
#define FML_CHECK(condition)
Definition: logging.h:85
#define FML_UNREACHABLE()
Definition: logging.h:109
#define FML_DCHECK(condition)
Definition: logging.h:103
#define TRACE_EVENT_WITH_FRAME_NUMBER(recorder, category_group, name, flow_id_count, flow_ids)
Definition: frame_timings.h:17
Dart_NativeFunction function
Definition: fuchsia.cc:51
EGLSurface surface_
FlTexture * texture
constexpr SkColor4f kTransparent
Definition: SkColor.h:434
SK_API bool Encode(SkWStream *dst, const SkPixmap &src, const Options &options)
SK_API sk_sp< SkDocument > Make(SkWStream *dst, const SkSerialProcs *=nullptr, std::function< void(const SkPicture *)> onEndPage=nullptr)
SK_API bool Encode(SkWStream *dst, const SkPixmap &src, const Options &options)
sk_sp< const SkImage > image
Definition: SkRecords.h:269
sk_sp< const SkPicture > picture
Definition: SkRecords.h:299
SK_API sk_sp< SkSurface > Raster(const SkImageInfo &imageInfo, size_t rowBytes, const SkSurfaceProps *surfaceProps)
SK_API sk_sp< SkSurface > WrapBackendTexture(GrRecordingContext *context, const GrBackendTexture &backendTexture, GrSurfaceOrigin origin, int sampleCnt, SkColorType colorType, sk_sp< SkColorSpace > colorSpace, const SkSurfaceProps *surfaceProps, TextureReleaseProc textureReleaseProc=nullptr, ReleaseContext releaseContext=nullptr)
sk_sp< SkData > SerializeTypefaceWithData(SkTypeface *typeface, void *ctx)
DrawSurfaceStatus
Definition: rasterizer.h:68
static sk_sp< SkData > ScreenshotLayerTreeAsPicture(flutter::LayerTree *tree, flutter::CompositorContext &compositor_context)
Definition: rasterizer.cc:823
sk_sp< SkData > SerializeTypefaceWithoutData(SkTypeface *typeface, void *ctx)
static void RenderFrameForScreenshot(flutter::CompositorContext &compositor_context, DlCanvas *canvas, flutter::LayerTree *tree, GrDirectContext *surface_context, const std::shared_ptr< impeller::AiksContext > &aiks_context)
Definition: rasterizer.cc:861
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not defaults to or::depending on whether ipv6 is specified vm service A custom Dart VM Service port The default is to pick a randomly available open port disable vm Disable the Dart VM Service The Dart VM Service is never available in release mode disable vm service Disable mDNS Dart VM Service publication Bind to the IPv6 localhost address for the Dart VM Service Ignored if vm service host is set endless trace buffer
Definition: switches.h:126
sk_sp< SkData > SerializeImageWithoutData(SkImage *image, void *ctx)
PipelineConsumeResult
Definition: pipeline.h:29
static constexpr std::chrono::milliseconds kSkiaCleanupExpiration(15000)
void TraceEventAsyncComplete(TraceArg category_group, TraceArg name, TimePoint begin, TimePoint end)
Definition: trace_event.cc:431
std::chrono::duration< double, std::milli > Milliseconds
Definition: time_delta.h:18
std::function< void()> closure
Definition: closure.h:14
PixelFormat
The Pixel formats supported by Impeller. The naming convention denotes the usage of the component,...
Definition: formats.h:99
Definition: ref_ptr.h:256
flutter::DlCanvas DlCanvas
static SkString to_string(int n)
Definition: nanobench.cpp:119
Definition: SkSize.h:16
int32_t fHeight
Definition: SkSize.h:18
int32_t fWidth
Definition: SkSize.h:17
constexpr int32_t width() const
Definition: SkSize.h:36
constexpr int32_t height() const
Definition: SkSize.h:37
sk_sp< SkColorSpace > refColorSpace() const
int width() const
Definition: SkImageInfo.h:365
SkColorType colorType() const
Definition: SkImageInfo.h:373
int height() const
Definition: SkImageInfo.h:371
static constexpr SkRect MakeSize(const SkSize &size)
Definition: SkRect.h:633
static constexpr SkRect MakeWH(float w, float h)
Definition: SkRect.h:609
SkSerialImageProc fImageProc
Definition: SkSerialProcs.h:90
SkSerialTypefaceProc fTypefaceProc
Definition: SkSerialProcs.h:93
static constexpr SkSize Make(SkScalar w, SkScalar h)
Definition: SkSize.h:56
A POD type used to return the screenshot data along with the size of the frame.
Definition: rasterizer.h:398
Screenshot()
Creates an empty screenshot.
Definition: rasterizer.cc:1155
~Screenshot()
Destroys the screenshot object and releases underlying data.
A screenshot of the surface's raw data.
Definition: surface.h:27
sk_sp< SkData > data
Definition: surface.h:29
Represents the 2 code paths available when calling |SyncSwitch::Execute|.
Definition: sync_switch.h:35
std::shared_ptr< const fml::Mapping > data
Definition: texture_gles.cc:63
#define ERROR(message)
Definition: elf_loader.cc:260
#define TRACE_EVENT0(category_group, name)
Definition: trace_event.h:131