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 context_switch.reset();
133 surface_->ClearRenderContext();
134 surface_.reset();
135 }
136
137 view_records_.clear();
138
139 if (raster_thread_merger_.get() != nullptr &&
140 raster_thread_merger_.get()->IsMerged()) {
141 FML_DCHECK(raster_thread_merger_->IsEnabled());
142 raster_thread_merger_->UnMergeNowIfLastOne();
143 raster_thread_merger_->SetMergeUnmergeCallback(nullptr);
144 }
145}
146
148 return is_torn_down_;
149}
150
151std::optional<DrawSurfaceStatus> Rasterizer::GetLastDrawStatus(
152 int64_t view_id) {
153 auto found = view_records_.find(view_id);
154 if (found != view_records_.end()) {
155 return found->second.last_draw_status;
156 } else {
157 return std::optional<DrawSurfaceStatus>();
158 }
159}
160
162 if (raster_thread_merger_) {
163 raster_thread_merger_->Enable();
164 }
165}
166
168 if (raster_thread_merger_) {
169 raster_thread_merger_->Disable();
170 }
171}
172
174#if !SLIMPELLER
175 if (!surface_) {
176 FML_DLOG(INFO)
177 << "Rasterizer::NotifyLowMemoryWarning called with no surface.";
178 return;
179 }
180 auto context = surface_->GetContext();
181 if (!context) {
182 FML_DLOG(INFO)
183 << "Rasterizer::NotifyLowMemoryWarning called with no GrContext.";
184 return;
185 }
186 auto context_switch = surface_->MakeRenderContextCurrent();
187 if (!context_switch->GetResult()) {
188 return;
189 }
190 context->performDeferredCleanup(std::chrono::milliseconds(0));
191#endif // !SLIMPELLER
192}
193
195 if (external_view_embedder_) {
196 external_view_embedder_->CollectView(view_id);
197 }
198 view_records_.erase(view_id);
199}
200
201std::shared_ptr<flutter::TextureRegistry> Rasterizer::GetTextureRegistry() {
202 return compositor_context_->texture_registry();
203}
204
205GrDirectContext* Rasterizer::GetGrContext() {
206 return surface_ ? surface_->GetContext() : nullptr;
207}
208
210 auto found = view_records_.find(view_id);
211 if (found == view_records_.end()) {
212 return nullptr;
213 }
214 auto& last_task = found->second.last_successful_task;
215 if (last_task == nullptr) {
216 return nullptr;
217 }
218 return last_task->layer_tree.get();
219}
220
222 std::unique_ptr<FrameTimingsRecorder> frame_timings_recorder) {
223 if (!surface_) {
224 return;
225 }
226 std::vector<std::unique_ptr<LayerTreeTask>> tasks;
227 for (auto& [view_id, view_record] : view_records_) {
228 if (view_record.last_successful_task) {
229 tasks.push_back(std::move(view_record.last_successful_task));
230 }
231 }
232 if (tasks.empty()) {
233 return;
234 }
235
236 DoDrawResult result =
237 DrawToSurfaces(*frame_timings_recorder, std::move(tasks));
238
239 // EndFrame should perform cleanups for the external_view_embedder.
240 if (external_view_embedder_ && external_view_embedder_->GetUsedThisFrame()) {
241 bool should_resubmit_frame = ShouldResubmitFrame(result);
242 external_view_embedder_->SetUsedThisFrame(false);
243 external_view_embedder_->EndFrame(should_resubmit_frame,
244 raster_thread_merger_);
245 }
246}
247
248DrawStatus Rasterizer::Draw(const std::shared_ptr<FramePipeline>& pipeline) {
249 TRACE_EVENT0("flutter", "GPURasterizer::Draw");
250 if (raster_thread_merger_ &&
251 !raster_thread_merger_->IsOnRasterizingThread()) {
252 // we yield and let this frame be serviced on the right thread.
254 }
255 FML_DCHECK(delegate_.GetTaskRunners()
258
259 DoDrawResult draw_result;
260 FramePipeline::Consumer consumer = [&draw_result,
261 this](std::unique_ptr<FrameItem> item) {
262 draw_result = DoDraw(std::move(item->frame_timings_recorder),
263 std::move(item->layer_tree_tasks));
264 };
265
266 PipelineConsumeResult consume_result = pipeline->Consume(consumer);
267 if (consume_result == PipelineConsumeResult::NoneAvailable) {
269 }
270 // if the raster status is to resubmit the frame, we push the frame to the
271 // front of the queue and also change the consume status to more available.
272
273 bool should_resubmit_frame = ShouldResubmitFrame(draw_result);
274 if (should_resubmit_frame) {
275 FML_CHECK(draw_result.resubmitted_item);
276 auto front_continuation = pipeline->ProduceIfEmpty();
277 PipelineProduceResult pipeline_result =
278 front_continuation.Complete(std::move(draw_result.resubmitted_item));
279 if (pipeline_result.success) {
281 }
282 } else if (draw_result.status == DoDrawStatus::kEnqueuePipeline) {
284 }
285
286 // EndFrame should perform cleanups for the external_view_embedder.
287 if (external_view_embedder_ && external_view_embedder_->GetUsedThisFrame()) {
288 external_view_embedder_->SetUsedThisFrame(false);
289 external_view_embedder_->EndFrame(should_resubmit_frame,
290 raster_thread_merger_);
291 }
292
293 // Consume as many pipeline items as possible. But yield the event loop
294 // between successive tries.
295 switch (consume_result) {
298 [weak_this = weak_factory_.GetWeakPtr(), pipeline]() {
299 if (weak_this) {
300 weak_this->Draw(pipeline);
301 }
302 });
303 break;
304 }
305 default:
306 break;
307 }
308
309 return ToDrawStatus(draw_result.status);
310}
311
312bool Rasterizer::ShouldResubmitFrame(const DoDrawResult& result) {
313 if (result.resubmitted_item) {
314 FML_CHECK(!result.resubmitted_item->layer_tree_tasks.empty());
315 return true;
316 }
317 return false;
318}
319
320DrawStatus Rasterizer::ToDrawStatus(DoDrawStatus status) {
321 switch (status) {
322 case DoDrawStatus::kEnqueuePipeline:
323 return DrawStatus::kDone;
324 case DoDrawStatus::kNotSetUp:
325 return DrawStatus::kNotSetUp;
326 case DoDrawStatus::kGpuUnavailable:
327 return DrawStatus::kGpuUnavailable;
328 case DoDrawStatus::kDone:
329 return DrawStatus::kDone;
330 }
332}
333
334#if !SLIMPELLER
335namespace {
336std::unique_ptr<SnapshotDelegate::GpuImageResult> MakeBitmapImage(
337 const sk_sp<DisplayList>& display_list,
338 const SkImageInfo& image_info) {
339 FML_DCHECK(display_list);
340 // Use 16384 as a proxy for the maximum texture size for a GPU image.
341 // This is meant to be large enough to avoid false positives in test contexts,
342 // but not so artificially large to be completely unrealistic on any platform.
343 // This limit is taken from the Metal specification. D3D, Vulkan, and GL
344 // generally have lower limits.
345 if (image_info.width() > 16384 || image_info.height() > 16384) {
346 return std::make_unique<SnapshotDelegate::GpuImageResult>(
347 GrBackendTexture(), nullptr, nullptr,
348 "unable to create bitmap render target at specified size " +
349 std::to_string(image_info.width()) + "x" +
350 std::to_string(image_info.height()));
351 };
352
353 sk_sp<SkSurface> surface = SkSurfaces::Raster(image_info);
354 auto canvas = DlSkCanvasAdapter(surface->getCanvas());
355 canvas.Clear(DlColor::kTransparent());
356 canvas.DrawDisplayList(display_list);
357
358 sk_sp<SkImage> image = surface->makeImageSnapshot();
359 return std::make_unique<SnapshotDelegate::GpuImageResult>(
360 GrBackendTexture(), nullptr, image,
361 image ? "" : "Unable to create image");
362}
363} // namespace
364#endif // !SLIMPELLER
365
366std::unique_ptr<Rasterizer::GpuImageResult> Rasterizer::MakeSkiaGpuImage(
367 sk_sp<DisplayList> display_list,
368 const SkImageInfo& image_info) {
369#if SLIMPELLER
370 FML_LOG(FATAL) << "Impeller opt-out unavailable.";
371 return nullptr;
372#else // SLIMPELLER
373 TRACE_EVENT0("flutter", "Rasterizer::MakeGpuImage");
374 FML_DCHECK(display_list);
375
376 std::unique_ptr<SnapshotDelegate::GpuImageResult> result;
377 delegate_.GetIsGpuDisabledSyncSwitch()->Execute(
379 .SetIfTrue([&result, &image_info, &display_list] {
380 // TODO(dnfield): This isn't safe if display_list contains any GPU
381 // resources like an SkImage_gpu.
382 result = MakeBitmapImage(display_list, image_info);
383 })
384 .SetIfFalse([&result, &image_info, &display_list,
385 surface = surface_.get(),
386 gpu_image_behavior = gpu_image_behavior_] {
387 if (!surface ||
388 gpu_image_behavior == MakeGpuImageBehavior::kBitmap) {
389 // TODO(dnfield): This isn't safe if display_list contains any GPU
390 // resources like an SkImage_gpu.
391 result = MakeBitmapImage(display_list, image_info);
392 return;
393 }
394
395 auto context_switch = surface->MakeRenderContextCurrent();
396 if (!context_switch->GetResult()) {
397 result = MakeBitmapImage(display_list, image_info);
398 return;
399 }
400
401 auto* context = surface->GetContext();
402 if (!context) {
403 result = MakeBitmapImage(display_list, image_info);
404 return;
405 }
406
407 GrBackendTexture texture = context->createBackendTexture(
408 image_info.width(), image_info.height(), image_info.colorType(),
409 skgpu::Mipmapped::kNo, GrRenderable::kYes);
410 if (!texture.isValid()) {
411 result = std::make_unique<SnapshotDelegate::GpuImageResult>(
412 GrBackendTexture(), nullptr, nullptr,
413 "unable to create texture render target at specified size " +
414 std::to_string(image_info.width()) + "x" +
415 std::to_string(image_info.height()));
416 return;
417 }
418
419 sk_sp<SkSurface> sk_surface = SkSurfaces::WrapBackendTexture(
420 context, texture, kTopLeft_GrSurfaceOrigin, /*sampleCnt=*/0,
421 image_info.colorType(), image_info.refColorSpace(), nullptr);
422 if (!sk_surface) {
423 result = std::make_unique<SnapshotDelegate::GpuImageResult>(
424 GrBackendTexture(), nullptr, nullptr,
425 "unable to create rendering surface for image");
426 return;
427 }
428
429 auto canvas = DlSkCanvasAdapter(sk_surface->getCanvas());
430 canvas.Clear(DlColor::kTransparent());
431 canvas.DrawDisplayList(display_list);
432
433 result = std::make_unique<SnapshotDelegate::GpuImageResult>(
434 texture, sk_ref_sp(context), nullptr, "");
435 }));
436 return result;
437#endif // !SLIMPELLER
438}
439
440void Rasterizer::MakeSkiaSnapshot(sk_sp<DisplayList> display_list,
441 DlISize picture_size,
442 std::function<void(sk_sp<SkImage>)> callback,
443 SnapshotPixelFormat pixel_format) {
444 return snapshot_controller_->MakeSkiaSnapshot(
445 display_list, picture_size, std::move(callback), pixel_format);
446}
447
448sk_sp<SkImage> Rasterizer::MakeSkiaSnapshotSync(
449 sk_sp<DisplayList> display_list,
450 DlISize picture_size,
451 SnapshotPixelFormat pixel_format) {
452 return snapshot_controller_->MakeSkiaSnapshotSync(std::move(display_list),
453 picture_size, pixel_format);
454}
455
456void Rasterizer::MakeImpellerSnapshot(
457 sk_sp<DisplayList> display_list,
458 DlISize picture_size,
459 std::function<void(std::shared_ptr<impeller::Texture>)> callback,
460 SnapshotPixelFormat pixel_format) {
461 return snapshot_controller_->MakeImpellerSnapshot(
462 display_list, picture_size, std::move(callback), pixel_format);
463}
464
465std::shared_ptr<impeller::Texture> Rasterizer::MakeImpellerSnapshotSync(
466 sk_sp<DisplayList> display_list,
467 DlISize picture_size,
468 SnapshotPixelFormat pixel_format) {
469 return snapshot_controller_->MakeImpellerSnapshotSync(
470 std::move(display_list), picture_size, pixel_format);
471}
472
473sk_sp<SkImage> Rasterizer::ConvertToRasterImage(sk_sp<SkImage> image) {
474 TRACE_EVENT0("flutter", __FUNCTION__);
475 return snapshot_controller_->ConvertToRasterImage(image);
476}
477
478sk_sp<SkImage> Rasterizer::MakeSkiaTextureImage(
479 sk_sp<SkImage> image,
480 SnapshotPixelFormat pixel_format) {
481 TRACE_EVENT0("flutter", __FUNCTION__);
482 return snapshot_controller_->MakeSkiaTextureImage(image, pixel_format);
483}
484
485std::shared_ptr<impeller::Texture> Rasterizer::MakeImpellerTextureImage(
486 sk_sp<SkImage> image,
487 SnapshotPixelFormat pixel_format) {
488 TRACE_EVENT0("flutter", __FUNCTION__);
489 return snapshot_controller_->MakeImpellerTextureImage(image, pixel_format);
490}
491
492// |SnapshotDelegate|
493void Rasterizer::CacheRuntimeStage(
494 const std::shared_ptr<impeller::RuntimeStage>& runtime_stage) {
495 if (snapshot_controller_) {
496 snapshot_controller_->CacheRuntimeStage(runtime_stage);
497 }
498}
499
500// |SnapshotDelegate|
501bool Rasterizer::MakeRenderContextCurrent() {
502 return snapshot_controller_->MakeRenderContextCurrent();
503}
504
505fml::Milliseconds Rasterizer::GetFrameBudget() const {
506 return delegate_.GetFrameBudget();
507};
508
509Rasterizer::DoDrawResult Rasterizer::DoDraw(
510 std::unique_ptr<FrameTimingsRecorder> frame_timings_recorder,
511 std::vector<std::unique_ptr<LayerTreeTask>> tasks) {
512 TRACE_EVENT_WITH_FRAME_NUMBER(frame_timings_recorder, "flutter",
513 "Rasterizer::DoDraw", /*flow_id_count=*/0,
514 /*flow_ids=*/nullptr);
515 FML_DCHECK(delegate_.GetTaskRunners()
516 .GetRasterTaskRunner()
517 ->RunsTasksOnCurrentThread());
518 frame_timings_recorder->AssertInState(FrameTimingsRecorder::State::kBuildEnd);
519
520 if (tasks.empty()) {
521 return DoDrawResult{DoDrawStatus::kDone};
522 }
523 if (!surface_) {
524 return DoDrawResult{DoDrawStatus::kNotSetUp};
525 }
526
527#if !SLIMPELLER
528 PersistentCache* persistent_cache = PersistentCache::GetCacheForProcess();
529 persistent_cache->ResetStoredNewShaders();
530#endif // !SLIMPELLER
531
532 DoDrawResult result =
533 DrawToSurfaces(*frame_timings_recorder, std::move(tasks));
534
535 FML_DCHECK(result.status != DoDrawStatus::kEnqueuePipeline);
536 if (result.status == DoDrawStatus::kGpuUnavailable) {
537 return DoDrawResult{DoDrawStatus::kGpuUnavailable};
538 }
539
540#if !SLIMPELLER
541 if (persistent_cache->IsDumpingSkp() &&
542 persistent_cache->StoredNewShaders()) {
543 auto screenshot =
544 ScreenshotLastLayerTree(ScreenshotType::SkiaPicture, false);
545 persistent_cache->DumpSkp(*screenshot.data);
546 }
547#endif // !SLIMPELLER
548
549 // TODO(liyuqian): in Fuchsia, the rasterization doesn't finish when
550 // Rasterizer::DoDraw finishes. Future work is needed to adapt the timestamp
551 // for Fuchsia to capture SceneUpdateContext::ExecutePaintTasks.
552 delegate_.OnFrameRasterized(frame_timings_recorder->GetRecordedTime());
553
554// SceneDisplayLag events are disabled on Fuchsia.
555// see: https://github.com/flutter/flutter/issues/56598
556#if !defined(OS_FUCHSIA)
557 const fml::TimePoint raster_finish_time =
558 frame_timings_recorder->GetRasterEndTime();
559 fml::TimePoint frame_target_time =
560 frame_timings_recorder->GetVsyncTargetTime();
561 if (raster_finish_time > frame_target_time) {
562 fml::TimePoint latest_frame_target_time =
563 delegate_.GetLatestFrameTargetTime();
564 const auto frame_budget_millis = delegate_.GetFrameBudget().count();
565 if (latest_frame_target_time < raster_finish_time) {
566 latest_frame_target_time =
567 latest_frame_target_time +
568 fml::TimeDelta::FromMillisecondsF(frame_budget_millis);
569 }
570 const auto frame_lag =
571 (latest_frame_target_time - frame_target_time).ToMillisecondsF();
572 const int vsync_transitions_missed = round(frame_lag / frame_budget_millis);
574 "flutter", // category
575 "SceneDisplayLag", // name
576 raster_finish_time, // begin_time
577 latest_frame_target_time, // end_time
578 "frame_target_time", // arg_key_1
579 frame_target_time, // arg_val_1
580 "current_frame_target_time", // arg_key_2
581 latest_frame_target_time, // arg_val_2
582 "vsync_transitions_missed", // arg_key_3
583 vsync_transitions_missed // arg_val_3
584 );
585 }
586#endif
587
588 // Pipeline pressure is applied from a couple of places:
589 // rasterizer: When there are more items as of the time of Consume.
590 // animator (via shell): Frame gets produces every vsync.
591 // Enqueing here is to account for the following scenario:
592 // T = 1
593 // - one item (A) in the pipeline
594 // - rasterizer starts (and merges the threads)
595 // - pipeline consume result says no items to process
596 // T = 2
597 // - animator produces (B) to the pipeline
598 // - applies pipeline pressure via platform thread.
599 // T = 3
600 // - rasterizes finished (and un-merges the threads)
601 // - |Draw| for B yields as its on the wrong thread.
602 // This enqueue ensures that we attempt to consume from the right
603 // thread one more time after un-merge.
604 if (raster_thread_merger_) {
605 if (raster_thread_merger_->DecrementLease() ==
607 return DoDrawResult{
608 .status = DoDrawStatus::kEnqueuePipeline,
609 .resubmitted_item = std::move(result.resubmitted_item),
610 };
611 }
612 }
613
614 return result;
615}
616
617Rasterizer::DoDrawResult Rasterizer::DrawToSurfaces(
618 FrameTimingsRecorder& frame_timings_recorder,
619 std::vector<std::unique_ptr<LayerTreeTask>> tasks) {
620 TRACE_EVENT0("flutter", "Rasterizer::DrawToSurfaces");
622 frame_timings_recorder.AssertInState(FrameTimingsRecorder::State::kBuildEnd);
623
624 DoDrawResult result{
625 .status = DoDrawStatus::kDone,
626 };
627 if (surface_->AllowsDrawingWhenGpuDisabled()) {
628 result.resubmitted_item =
629 DrawToSurfacesUnsafe(frame_timings_recorder, std::move(tasks));
630 } else {
631 delegate_.GetIsGpuDisabledSyncSwitch()->Execute(
633 .SetIfTrue([&] {
634 result.status = DoDrawStatus::kGpuUnavailable;
635 frame_timings_recorder.RecordRasterStart(fml::TimePoint::Now());
636 frame_timings_recorder.RecordRasterEnd();
637 })
638 .SetIfFalse([&] {
639 result.resubmitted_item = DrawToSurfacesUnsafe(
640 frame_timings_recorder, std::move(tasks));
641 }));
642 }
643 frame_timings_recorder.AssertInState(FrameTimingsRecorder::State::kRasterEnd);
644
645 return result;
646}
647
648std::unique_ptr<FrameItem> Rasterizer::DrawToSurfacesUnsafe(
649 FrameTimingsRecorder& frame_timings_recorder,
650 std::vector<std::unique_ptr<LayerTreeTask>> tasks) {
651 compositor_context_->ui_time().SetLapTime(
652 frame_timings_recorder.GetBuildDuration());
653
654 // First traverse: Filter out discarded trees
655 auto task_iter = tasks.begin();
656 while (task_iter != tasks.end()) {
657 LayerTreeTask& task = **task_iter;
658 if (delegate_.ShouldDiscardLayerTree(task.view_id, *task.layer_tree)) {
659 EnsureViewRecord(task.view_id).last_draw_status =
660 DrawSurfaceStatus::kDiscarded;
661 task_iter = tasks.erase(task_iter);
662 } else {
663 ++task_iter;
664 }
665 }
666 if (tasks.empty()) {
667 frame_timings_recorder.RecordRasterStart(fml::TimePoint::Now());
668 frame_timings_recorder.RecordRasterEnd();
669 return nullptr;
670 }
671
672 if (external_view_embedder_) {
673 FML_DCHECK(!external_view_embedder_->GetUsedThisFrame());
674 external_view_embedder_->SetUsedThisFrame(true);
675 external_view_embedder_->BeginFrame(surface_->GetContext(),
676 raster_thread_merger_);
677 }
678
679 std::optional<fml::TimePoint> presentation_time = std::nullopt;
680 // TODO (https://github.com/flutter/flutter/issues/105596): this can be in
681 // the past and might need to get snapped to future as this frame could
682 // have been resubmitted. `presentation_time` on SubmitInfo is not set
683 // in this case.
684 {
685 const auto vsync_target_time = frame_timings_recorder.GetVsyncTargetTime();
686 if (vsync_target_time > fml::TimePoint::Now()) {
687 presentation_time = vsync_target_time;
688 }
689 }
690
691 frame_timings_recorder.RecordRasterStart(fml::TimePoint::Now());
692
693 // Second traverse: draw all layer trees.
694 std::vector<std::unique_ptr<LayerTreeTask>> resubmitted_tasks;
695 for (std::unique_ptr<LayerTreeTask>& task : tasks) {
696 int64_t view_id = task->view_id;
697 std::unique_ptr<LayerTree> layer_tree = std::move(task->layer_tree);
698 float device_pixel_ratio = task->device_pixel_ratio;
699
700 DrawSurfaceStatus status = DrawToSurfaceUnsafe(
701 view_id, *layer_tree, device_pixel_ratio, presentation_time);
702 FML_DCHECK(status != DrawSurfaceStatus::kDiscarded);
703
704 auto& view_record = EnsureViewRecord(task->view_id);
705 view_record.last_draw_status = status;
706 if (status == DrawSurfaceStatus::kSuccess) {
707 view_record.last_successful_task = std::make_unique<LayerTreeTask>(
708 view_id, std::move(layer_tree), device_pixel_ratio);
709 } else if (status == DrawSurfaceStatus::kRetry) {
710 resubmitted_tasks.push_back(std::make_unique<LayerTreeTask>(
711 view_id, std::move(layer_tree), device_pixel_ratio));
712 }
713 }
714 // TODO(dkwingsmt): Pass in raster cache(s) for all views.
715 // See https://github.com/flutter/flutter/issues/135530, item 4.
716 frame_timings_recorder.RecordRasterEnd(
717 NOT_SLIMPELLER(&compositor_context_->raster_cache()));
718
719 FireNextFrameCallbackIfPresent();
720
721#if !SLIMPELLER
722 if (surface_->GetContext()) {
723 surface_->GetContext()->performDeferredCleanup(kSkiaCleanupExpiration);
724 }
725#endif // !SLIMPELLER
726
727 if (resubmitted_tasks.empty()) {
728 return nullptr;
729 } else {
730 return std::make_unique<FrameItem>(
731 std::move(resubmitted_tasks),
732 frame_timings_recorder.CloneUntil(
733 FrameTimingsRecorder::State::kBuildEnd));
734 }
735}
736
737/// \see Rasterizer::DrawToSurfaces
738DrawSurfaceStatus Rasterizer::DrawToSurfaceUnsafe(
739 int64_t view_id,
740 flutter::LayerTree& layer_tree,
741 float device_pixel_ratio,
742 std::optional<fml::TimePoint> presentation_time) {
744
745 DlCanvas* embedder_root_canvas = nullptr;
746 if (external_view_embedder_) {
747 external_view_embedder_->PrepareFlutterView(layer_tree.frame_size(),
748 device_pixel_ratio);
749 // TODO(dkwingsmt): Add view ID here.
750 embedder_root_canvas = external_view_embedder_->GetRootCanvas();
751 }
752
753 // On Android, the external view embedder deletes surfaces in `BeginFrame`.
754 //
755 // Deleting a surface also clears the GL context. Therefore, acquire the
756 // frame after calling `BeginFrame` as this operation resets the GL context.
757 auto frame = surface_->AcquireFrame(layer_tree.frame_size());
758 if (frame == nullptr) {
759 return DrawSurfaceStatus::kFailed;
760 }
761
762 // If the external view embedder has specified an optional root surface, the
763 // root surface transformation is set by the embedder instead of
764 // having to apply it here.
765 DlMatrix root_surface_transformation =
766 embedder_root_canvas ? DlMatrix() : surface_->GetRootTransformation();
767
768 auto root_surface_canvas =
769 embedder_root_canvas ? embedder_root_canvas : frame->Canvas();
770 auto compositor_frame = compositor_context_->AcquireFrame(
771 surface_->GetContext(), // skia GrContext
772 root_surface_canvas, // root surface canvas
773 external_view_embedder_.get(), // external view embedder
774 root_surface_transformation, // root surface transformation
775 true, // instrumentation enabled
776 frame->framebuffer_info()
777 .supports_readback, // surface supports pixel reads
778 raster_thread_merger_, // thread merger
779 surface_->GetAiksContext().get() // aiks context
780 );
781 if (compositor_frame) {
782 NOT_SLIMPELLER(compositor_context_->raster_cache().BeginFrame());
783
784 std::unique_ptr<FrameDamage> damage;
785 // when leaf layer tracing is enabled we wish to repaint the whole frame
786 // for accurate performance metrics.
787 if (frame->framebuffer_info().supports_partial_repaint) {
788 // Disable partial repaint if external_view_embedder_ SubmitFlutterView is
789 // involved - ExternalViewEmbedder unconditionally clears the entire
790 // surface and also partial repaint with platform view present is
791 // something that still need to be figured out.
792 bool force_full_repaint =
793 external_view_embedder_ &&
794 (!raster_thread_merger_ || raster_thread_merger_->IsMerged());
795
796 damage = std::make_unique<FrameDamage>();
797 auto existing_damage = frame->framebuffer_info().existing_damage;
798 if (existing_damage.has_value() && !force_full_repaint) {
799 damage->SetPreviousLayerTree(GetLastLayerTree(view_id));
800 damage->AddAdditionalDamage(existing_damage.value());
801 damage->SetClipAlignment(
802 frame->framebuffer_info().horizontal_clip_alignment,
803 frame->framebuffer_info().vertical_clip_alignment);
804 }
805 }
806
807 bool ignore_raster_cache = true;
808 if (surface_->EnableRasterCache()) {
809 ignore_raster_cache = false;
810 }
811
812 RasterStatus frame_status =
813 compositor_frame->Raster(layer_tree, // layer tree
814 ignore_raster_cache, // ignore raster cache
815 damage.get() // frame damage
816 );
817 if (frame_status == RasterStatus::kSkipAndRetry) {
818 return DrawSurfaceStatus::kRetry;
819 }
820
821 SurfaceFrame::SubmitInfo submit_info;
822 submit_info.presentation_time = presentation_time;
823 if (damage) {
824 submit_info.frame_damage = damage->GetFrameDamage();
825 submit_info.buffer_damage = damage->GetBufferDamage();
826 }
827
828 frame->set_submit_info(submit_info);
829
830 if (external_view_embedder_ &&
831 (!raster_thread_merger_ || raster_thread_merger_->IsMerged())) {
832 FML_DCHECK(!frame->IsSubmitted());
833 external_view_embedder_->SubmitFlutterView(
834 view_id, surface_->GetContext(), surface_->GetAiksContext(),
835 std::move(frame));
836 } else {
837 frame->Submit();
838 }
839
840#if !SLIMPELLER
841 // Do not update raster cache metrics for kResubmit because that status
842 // indicates that the frame was not actually painted.
843 if (frame_status != RasterStatus::kResubmit) {
844 compositor_context_->raster_cache().EndFrame();
845 }
846#endif // !SLIMPELLER
847
848 if (frame_status == RasterStatus::kResubmit) {
849 return DrawSurfaceStatus::kRetry;
850 } else {
851 FML_CHECK(frame_status == RasterStatus::kSuccess);
852 return DrawSurfaceStatus::kSuccess;
853 }
854 }
855
856 return DrawSurfaceStatus::kFailed;
857}
858
859Rasterizer::ViewRecord& Rasterizer::EnsureViewRecord(int64_t view_id) {
860 return view_records_[view_id];
861}
862
863static sk_sp<SkData> ScreenshotLayerTreeAsPicture(
864 flutter::LayerTree* tree,
865 flutter::CompositorContext& compositor_context) {
866#if SLIMPELLER
867 return nullptr;
868#else // SLIMPELLER
869 FML_DCHECK(tree != nullptr);
870 SkPictureRecorder recorder;
871 recorder.beginRecording(
872 SkRect::MakeWH(tree->frame_size().width, tree->frame_size().height));
873
874 DlMatrix root_surface_transformation;
875 DlSkCanvasAdapter canvas(recorder.getRecordingCanvas());
876
877 // TODO(amirh): figure out how to take a screenshot with embedded UIView.
878 // https://github.com/flutter/flutter/issues/23435
879 auto frame = compositor_context.AcquireFrame(nullptr, &canvas, nullptr,
880 root_surface_transformation,
881 false, true, nullptr, nullptr);
882 frame->Raster(*tree, true, nullptr);
883
884#if defined(OS_FUCHSIA)
885 SkSerialProcs procs = {0};
886 procs.fImageProc = SerializeImageWithoutData;
887 procs.fTypefaceProc = SerializeTypefaceWithoutData;
888#else
889 SkSerialProcs procs = {0};
890 procs.fTypefaceProc = SerializeTypefaceWithData;
891 procs.fImageProc = [](SkImage* img, void*) -> SkSerialReturnType {
892 return SkPngEncoder::Encode(nullptr, img, SkPngEncoder::Options{});
893 };
894#endif
895
896 return recorder.finishRecordingAsPicture()->serialize(&procs);
897#endif // SLIMPELLER
898}
899
901 flutter::CompositorContext& compositor_context,
902 DlCanvas* canvas,
903 flutter::LayerTree* tree,
904 GrDirectContext* surface_context,
905 const std::shared_ptr<impeller::AiksContext>& aiks_context) {
906 // There is no root surface transformation for the screenshot layer. Reset
907 // the matrix to identity.
908 DlMatrix root_surface_transformation;
909
910 auto frame = compositor_context.AcquireFrame(
911 /*gr_context=*/surface_context,
912 /*canvas=*/canvas,
913 /*view_embedder=*/nullptr,
914 /*root_surface_transformation=*/root_surface_transformation,
915 /*instrumentation_enabled=*/false,
916 /*surface_supports_readback=*/true,
917 /*raster_thread_merger=*/nullptr,
918 /*aiks_context=*/aiks_context.get());
919 canvas->Clear(DlColor::kTransparent());
920 frame->Raster(*tree, true, nullptr);
921 canvas->Flush();
922}
923
924#if IMPELLER_SUPPORTS_RENDERING
925Rasterizer::ScreenshotFormat ToScreenshotFormat(impeller::PixelFormat format) {
926 switch (format) {
958 FML_DCHECK(false);
959 return Rasterizer::ScreenshotFormat::kUnknown;
961 return Rasterizer::ScreenshotFormat::kR8G8B8A8UNormInt;
963 return Rasterizer::ScreenshotFormat::kB8G8R8A8UNormInt;
965 return Rasterizer::ScreenshotFormat::kR16G16B16A16Float;
966 }
967}
968
969static std::pair<sk_sp<SkData>, Rasterizer::ScreenshotFormat>
970ScreenshotLayerTreeAsImageImpeller(
971 const std::shared_ptr<impeller::AiksContext>& aiks_context,
972 flutter::LayerTree* tree,
973 flutter::CompositorContext& compositor_context,
974 bool compressed) {
975 if (compressed) {
976 FML_LOG(ERROR) << "Compressed screenshots not supported for Impeller";
977 return {nullptr, Rasterizer::ScreenshotFormat::kUnknown};
978 }
979
980 DisplayListBuilder builder(DlRect::MakeSize(tree->frame_size()));
981
982 RenderFrameForScreenshot(compositor_context, &builder, tree, nullptr,
983 aiks_context);
984
985 std::shared_ptr<impeller::Texture> texture = impeller::DisplayListToTexture(
986 builder.Build(), impeller::ISize(tree->frame_size()), *aiks_context);
987 if (!texture) {
988 FML_LOG(ERROR) << "Failed to render to texture";
989 return {nullptr, Rasterizer::ScreenshotFormat::kUnknown};
990 }
991
994 buffer_desc.size =
995 texture->GetTextureDescriptor().GetByteSizeOfBaseMipLevel();
996 auto impeller_context = aiks_context->GetContext();
997 auto buffer =
998 impeller_context->GetResourceAllocator()->CreateBuffer(buffer_desc);
999 auto command_buffer = impeller_context->CreateCommandBuffer();
1000 command_buffer->SetLabel("BlitTextureToBuffer Command Buffer");
1001 auto pass = command_buffer->CreateBlitPass();
1002 pass->AddCopy(texture, buffer);
1003 pass->EncodeCommands();
1005 sk_sp<SkData> sk_data;
1006 auto completion = [buffer, &buffer_desc, &sk_data,
1007 &latch](impeller::CommandBuffer::Status status) {
1008 fml::ScopedCleanupClosure cleanup([&latch]() { latch.Signal(); });
1010 FML_LOG(ERROR) << "Failed to complete blit pass.";
1011 return;
1012 }
1013 sk_data = SkData::MakeWithCopy(buffer->OnGetContents(), buffer_desc.size);
1014 };
1015
1016 if (!impeller_context->GetCommandQueue()
1017 ->Submit({command_buffer}, completion)
1018 .ok()) {
1019 FML_LOG(ERROR) << "Failed to submit commands.";
1020 }
1021 latch.Wait();
1022 return std::make_pair(
1023 sk_data, ToScreenshotFormat(texture->GetTextureDescriptor().format));
1024}
1025#endif
1026
1027std::pair<sk_sp<SkData>, Rasterizer::ScreenshotFormat>
1028Rasterizer::ScreenshotLayerTreeAsImage(
1029 flutter::LayerTree* tree,
1030 flutter::CompositorContext& compositor_context,
1031 bool compressed) {
1032#if IMPELLER_SUPPORTS_RENDERING
1033 if (delegate_.GetSettings().enable_impeller) {
1034 return ScreenshotLayerTreeAsImageImpeller(GetAiksContext(), tree,
1035 compositor_context, compressed);
1036 }
1037#endif // IMPELLER_SUPPORTS_RENDERING
1038
1039#if SLIMPELLER
1040 FML_LOG(FATAL) << "Impeller opt-out unavailable.";
1041 return {nullptr, ScreenshotFormat::kUnknown};
1042#else // SLIMPELLER
1043 GrDirectContext* surface_context = GetGrContext();
1044 // Attempt to create a snapshot surface depending on whether we have access
1045 // to a valid GPU rendering context.
1046 std::unique_ptr<OffscreenSurface> snapshot_surface =
1047 std::make_unique<OffscreenSurface>(surface_context, tree->frame_size());
1048
1049 if (!snapshot_surface->IsValid()) {
1050 FML_LOG(ERROR) << "Screenshot: unable to create snapshot surface";
1051 return {nullptr, ScreenshotFormat::kUnknown};
1052 }
1053
1054 // Draw the current layer tree into the snapshot surface.
1055 DlCanvas* canvas = snapshot_surface->GetCanvas();
1056
1057 // snapshot_surface->makeImageSnapshot needs the GL context to be set if the
1058 // render context is GL. frame->Raster() pops the gl context in platforms
1059 // that gl context switching are used. (For example, older iOS that uses GL)
1060 // We reset the GL context using the context switch.
1061 auto context_switch = surface_->MakeRenderContextCurrent();
1062 if (!context_switch->GetResult()) {
1063 FML_LOG(ERROR) << "Screenshot: unable to make image screenshot";
1064 return {nullptr, ScreenshotFormat::kUnknown};
1065 }
1066
1067 RenderFrameForScreenshot(compositor_context, canvas, tree, surface_context,
1068 nullptr);
1069
1070 return std::make_pair(snapshot_surface->GetRasterData(compressed),
1071 ScreenshotFormat::kUnknown);
1072#endif // !SLIMPELLER
1073}
1074
1075Rasterizer::Screenshot Rasterizer::ScreenshotLastLayerTree(
1077 bool base64_encode) {
1078 if (delegate_.GetSettings().enable_impeller &&
1079 type == ScreenshotType::SkiaPicture) {
1080 FML_DCHECK(false);
1081 FML_LOG(ERROR) << "Last layer tree cannot be screenshotted as a "
1082 "SkiaPicture when using Impeller.";
1083 return {};
1084 }
1085 // TODO(dkwingsmt): Support screenshotting all last layer trees
1086 // when the shell protocol supports multi-views.
1087 // https://github.com/flutter/flutter/issues/135534
1088 // https://github.com/flutter/flutter/issues/135535
1089 auto* layer_tree = GetLastLayerTree(kFlutterImplicitViewId);
1090 if (layer_tree == nullptr) {
1091 FML_LOG(ERROR) << "Last layer tree was null when screenshotting.";
1092 return {};
1093 }
1094
1095 std::pair<sk_sp<SkData>, ScreenshotFormat> data{nullptr,
1096 ScreenshotFormat::kUnknown};
1097 std::string format;
1098
1099 switch (type) {
1100 case ScreenshotType::SkiaPicture:
1101 format = "ScreenshotType::SkiaPicture";
1102 data.first =
1103 ScreenshotLayerTreeAsPicture(layer_tree, *compositor_context_);
1104 break;
1105 case ScreenshotType::UncompressedImage:
1106 format = "ScreenshotType::UncompressedImage";
1107 data =
1108 ScreenshotLayerTreeAsImage(layer_tree, *compositor_context_, false);
1109 break;
1110 case ScreenshotType::CompressedImage:
1111 format = "ScreenshotType::CompressedImage";
1112 data = ScreenshotLayerTreeAsImage(layer_tree, *compositor_context_, true);
1113 break;
1114 case ScreenshotType::SurfaceData: {
1115 Surface::SurfaceData surface_data = surface_->GetSurfaceData();
1116 format = surface_data.pixel_format;
1117 data.first = surface_data.data;
1118 break;
1119 }
1120 }
1121
1122 if (data.first == nullptr) {
1123 FML_LOG(ERROR) << "Screenshot data was null.";
1124 return {};
1125 }
1126
1127 if (base64_encode) {
1128 size_t b64_size = Base64::EncodedSize(data.first->size());
1129 auto b64_data = SkData::MakeUninitialized(b64_size);
1130 Base64::Encode(data.first->data(), data.first->size(),
1131 b64_data->writable_data());
1132 return Rasterizer::Screenshot{b64_data, layer_tree->frame_size(), format,
1133 data.second};
1134 }
1135
1136 return Rasterizer::Screenshot{data.first, layer_tree->frame_size(), format,
1137 data.second};
1138}
1139
1140void Rasterizer::SetNextFrameCallback(const fml::closure& callback) {
1141 next_frame_callback_ = callback;
1142}
1143
1144void Rasterizer::SetExternalViewEmbedder(
1145 const std::shared_ptr<ExternalViewEmbedder>& view_embedder) {
1146 external_view_embedder_ = view_embedder;
1147}
1148
1149void Rasterizer::SetSnapshotSurfaceProducer(
1150 std::unique_ptr<SnapshotSurfaceProducer> producer) {
1151 snapshot_surface_producer_ = std::move(producer);
1152}
1153
1154fml::RefPtr<fml::RasterThreadMerger> Rasterizer::GetRasterThreadMerger() {
1155 return raster_thread_merger_;
1156}
1157
1158void Rasterizer::FireNextFrameCallbackIfPresent() {
1159 if (!next_frame_callback_) {
1160 return;
1161 }
1162 // It is safe for the callback to set a new callback.
1163 auto callback = next_frame_callback_;
1164 next_frame_callback_ = nullptr;
1165 callback();
1166}
1167
1168void Rasterizer::SetResourceCacheMaxBytes(size_t max_bytes, bool from_user) {
1169#if !SLIMPELLER
1170 user_override_resource_cache_bytes_ |= from_user;
1171
1172 if (!from_user && user_override_resource_cache_bytes_) {
1173 // We should not update the setting here if a user has explicitly set a
1174 // value for this over the flutter/skia channel.
1175 return;
1176 }
1177
1178 max_cache_bytes_ = max_bytes;
1179 if (!surface_) {
1180 return;
1181 }
1182
1183 GrDirectContext* context = surface_->GetContext();
1184 if (context) {
1185 auto context_switch = surface_->MakeRenderContextCurrent();
1186 if (!context_switch->GetResult()) {
1187 return;
1188 }
1189
1190 context->setResourceCacheLimit(max_bytes);
1191 }
1192#endif // !SLIMPELLER
1193}
1194
1195std::optional<size_t> Rasterizer::GetResourceCacheMaxBytes() const {
1196#if SLIMPELLER
1197 return std::nullopt;
1198#else // SLIMPELLER
1199 if (!surface_) {
1200 return std::nullopt;
1201 }
1202 GrDirectContext* context = surface_->GetContext();
1203 if (context) {
1204 return context->getResourceCacheLimit();
1205 }
1206 return std::nullopt;
1207#endif // SLIMPELLER
1208}
1209
1210Rasterizer::Screenshot::Screenshot() {}
1211
1212Rasterizer::Screenshot::Screenshot(sk_sp<SkData> p_data,
1213 DlISize p_size,
1214 const std::string& p_format,
1215 ScreenshotFormat p_pixel_format)
1216 : data(std::move(p_data)),
1217 frame_size(p_size),
1218 format(p_format),
1219 pixel_format(p_pixel_format) {}
1220
1221Rasterizer::Screenshot::Screenshot(const Screenshot& other) = default;
1222
1224
1225} // namespace flutter
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)
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot data
Definition switch_defs.h:36
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
std::shared_ptr< ContextGLES > context
std::shared_ptr< PipelineGLES > pipeline
std::shared_ptr< CommandBuffer > command_buffer
impeller::ShaderType type
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
#define TRACE_EVENT0(category_group, name)