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