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::MakeSkiaSnapshot(sk_sp<DisplayList> display_list,
439 DlISize picture_size,
440 std::function<void(sk_sp<SkImage>)> callback,
441 SnapshotPixelFormat pixel_format) {
442 return snapshot_controller_->MakeSkiaSnapshot(
443 display_list, picture_size, std::move(callback), pixel_format);
444}
445
446sk_sp<SkImage> Rasterizer::MakeSkiaSnapshotSync(
447 sk_sp<DisplayList> display_list,
448 DlISize picture_size,
449 SnapshotPixelFormat pixel_format) {
450 return snapshot_controller_->MakeSkiaSnapshotSync(std::move(display_list),
451 picture_size, pixel_format);
452}
453
454void Rasterizer::MakeImpellerSnapshot(
455 sk_sp<DisplayList> display_list,
456 DlISize picture_size,
457 std::function<void(std::shared_ptr<impeller::Texture>)> callback,
458 SnapshotPixelFormat pixel_format) {
459 return snapshot_controller_->MakeImpellerSnapshot(
460 display_list, picture_size, std::move(callback), pixel_format);
461}
462
463std::shared_ptr<impeller::Texture> Rasterizer::MakeImpellerSnapshotSync(
464 sk_sp<DisplayList> display_list,
465 DlISize picture_size,
466 SnapshotPixelFormat pixel_format) {
467 return snapshot_controller_->MakeImpellerSnapshotSync(
468 std::move(display_list), picture_size, pixel_format);
469}
470
471sk_sp<SkImage> Rasterizer::ConvertToRasterImage(sk_sp<SkImage> image) {
472 TRACE_EVENT0("flutter", __FUNCTION__);
473 return snapshot_controller_->ConvertToRasterImage(image);
474}
475
476sk_sp<SkImage> Rasterizer::MakeSkiaTextureImage(
477 sk_sp<SkImage> image,
478 SnapshotPixelFormat pixel_format) {
479 TRACE_EVENT0("flutter", __FUNCTION__);
480 return snapshot_controller_->MakeSkiaTextureImage(image, pixel_format);
481}
482
483std::shared_ptr<impeller::Texture> Rasterizer::MakeImpellerTextureImage(
484 sk_sp<SkImage> image,
485 SnapshotPixelFormat pixel_format) {
486 TRACE_EVENT0("flutter", __FUNCTION__);
487 return snapshot_controller_->MakeImpellerTextureImage(image, pixel_format);
488}
489
490// |SnapshotDelegate|
491void Rasterizer::CacheRuntimeStage(
492 const std::shared_ptr<impeller::RuntimeStage>& runtime_stage) {
493 if (snapshot_controller_) {
494 snapshot_controller_->CacheRuntimeStage(runtime_stage);
495 }
496}
497
498// |SnapshotDelegate|
499bool Rasterizer::MakeRenderContextCurrent() {
500 return snapshot_controller_->MakeRenderContextCurrent();
501}
502
503fml::Milliseconds Rasterizer::GetFrameBudget() const {
504 return delegate_.GetFrameBudget();
505};
506
507Rasterizer::DoDrawResult Rasterizer::DoDraw(
508 std::unique_ptr<FrameTimingsRecorder> frame_timings_recorder,
509 std::vector<std::unique_ptr<LayerTreeTask>> tasks) {
510 TRACE_EVENT_WITH_FRAME_NUMBER(frame_timings_recorder, "flutter",
511 "Rasterizer::DoDraw", /*flow_id_count=*/0,
512 /*flow_ids=*/nullptr);
513 FML_DCHECK(delegate_.GetTaskRunners()
514 .GetRasterTaskRunner()
515 ->RunsTasksOnCurrentThread());
516 frame_timings_recorder->AssertInState(FrameTimingsRecorder::State::kBuildEnd);
517
518 if (tasks.empty()) {
519 return DoDrawResult{DoDrawStatus::kDone};
520 }
521 if (!surface_) {
522 return DoDrawResult{DoDrawStatus::kNotSetUp};
523 }
524
525#if !SLIMPELLER
526 PersistentCache* persistent_cache = PersistentCache::GetCacheForProcess();
527 persistent_cache->ResetStoredNewShaders();
528#endif // !SLIMPELLER
529
530 DoDrawResult result =
531 DrawToSurfaces(*frame_timings_recorder, std::move(tasks));
532
533 FML_DCHECK(result.status != DoDrawStatus::kEnqueuePipeline);
534 if (result.status == DoDrawStatus::kGpuUnavailable) {
535 return DoDrawResult{DoDrawStatus::kGpuUnavailable};
536 }
537
538#if !SLIMPELLER
539 if (persistent_cache->IsDumpingSkp() &&
540 persistent_cache->StoredNewShaders()) {
541 auto screenshot =
542 ScreenshotLastLayerTree(ScreenshotType::SkiaPicture, false);
543 persistent_cache->DumpSkp(*screenshot.data);
544 }
545#endif // !SLIMPELLER
546
547 // TODO(liyuqian): in Fuchsia, the rasterization doesn't finish when
548 // Rasterizer::DoDraw finishes. Future work is needed to adapt the timestamp
549 // for Fuchsia to capture SceneUpdateContext::ExecutePaintTasks.
550 delegate_.OnFrameRasterized(frame_timings_recorder->GetRecordedTime());
551
552// SceneDisplayLag events are disabled on Fuchsia.
553// see: https://github.com/flutter/flutter/issues/56598
554#if !defined(OS_FUCHSIA)
555 const fml::TimePoint raster_finish_time =
556 frame_timings_recorder->GetRasterEndTime();
557 fml::TimePoint frame_target_time =
558 frame_timings_recorder->GetVsyncTargetTime();
559 if (raster_finish_time > frame_target_time) {
560 fml::TimePoint latest_frame_target_time =
561 delegate_.GetLatestFrameTargetTime();
562 const auto frame_budget_millis = delegate_.GetFrameBudget().count();
563 if (latest_frame_target_time < raster_finish_time) {
564 latest_frame_target_time =
565 latest_frame_target_time +
566 fml::TimeDelta::FromMillisecondsF(frame_budget_millis);
567 }
568 const auto frame_lag =
569 (latest_frame_target_time - frame_target_time).ToMillisecondsF();
570 const int vsync_transitions_missed = round(frame_lag / frame_budget_millis);
572 "flutter", // category
573 "SceneDisplayLag", // name
574 raster_finish_time, // begin_time
575 latest_frame_target_time, // end_time
576 "frame_target_time", // arg_key_1
577 frame_target_time, // arg_val_1
578 "current_frame_target_time", // arg_key_2
579 latest_frame_target_time, // arg_val_2
580 "vsync_transitions_missed", // arg_key_3
581 vsync_transitions_missed // arg_val_3
582 );
583 }
584#endif
585
586 // Pipeline pressure is applied from a couple of places:
587 // rasterizer: When there are more items as of the time of Consume.
588 // animator (via shell): Frame gets produces every vsync.
589 // Enqueing here is to account for the following scenario:
590 // T = 1
591 // - one item (A) in the pipeline
592 // - rasterizer starts (and merges the threads)
593 // - pipeline consume result says no items to process
594 // T = 2
595 // - animator produces (B) to the pipeline
596 // - applies pipeline pressure via platform thread.
597 // T = 3
598 // - rasterizes finished (and un-merges the threads)
599 // - |Draw| for B yields as its on the wrong thread.
600 // This enqueue ensures that we attempt to consume from the right
601 // thread one more time after un-merge.
602 if (raster_thread_merger_) {
603 if (raster_thread_merger_->DecrementLease() ==
605 return DoDrawResult{
606 .status = DoDrawStatus::kEnqueuePipeline,
607 .resubmitted_item = std::move(result.resubmitted_item),
608 };
609 }
610 }
611
612 return result;
613}
614
615Rasterizer::DoDrawResult Rasterizer::DrawToSurfaces(
616 FrameTimingsRecorder& frame_timings_recorder,
617 std::vector<std::unique_ptr<LayerTreeTask>> tasks) {
618 TRACE_EVENT0("flutter", "Rasterizer::DrawToSurfaces");
620 frame_timings_recorder.AssertInState(FrameTimingsRecorder::State::kBuildEnd);
621
622 DoDrawResult result{
623 .status = DoDrawStatus::kDone,
624 };
625 if (surface_->AllowsDrawingWhenGpuDisabled()) {
626 result.resubmitted_item =
627 DrawToSurfacesUnsafe(frame_timings_recorder, std::move(tasks));
628 } else {
629 delegate_.GetIsGpuDisabledSyncSwitch()->Execute(
631 .SetIfTrue([&] {
632 result.status = DoDrawStatus::kGpuUnavailable;
633 frame_timings_recorder.RecordRasterStart(fml::TimePoint::Now());
634 frame_timings_recorder.RecordRasterEnd();
635 })
636 .SetIfFalse([&] {
637 result.resubmitted_item = DrawToSurfacesUnsafe(
638 frame_timings_recorder, std::move(tasks));
639 }));
640 }
641 frame_timings_recorder.AssertInState(FrameTimingsRecorder::State::kRasterEnd);
642
643 return result;
644}
645
646std::unique_ptr<FrameItem> Rasterizer::DrawToSurfacesUnsafe(
647 FrameTimingsRecorder& frame_timings_recorder,
648 std::vector<std::unique_ptr<LayerTreeTask>> tasks) {
649 compositor_context_->ui_time().SetLapTime(
650 frame_timings_recorder.GetBuildDuration());
651
652 // First traverse: Filter out discarded trees
653 auto task_iter = tasks.begin();
654 while (task_iter != tasks.end()) {
655 LayerTreeTask& task = **task_iter;
656 if (delegate_.ShouldDiscardLayerTree(task.view_id, *task.layer_tree)) {
657 EnsureViewRecord(task.view_id).last_draw_status =
658 DrawSurfaceStatus::kDiscarded;
659 task_iter = tasks.erase(task_iter);
660 } else {
661 ++task_iter;
662 }
663 }
664 if (tasks.empty()) {
665 frame_timings_recorder.RecordRasterStart(fml::TimePoint::Now());
666 frame_timings_recorder.RecordRasterEnd();
667 return nullptr;
668 }
669
670 if (external_view_embedder_) {
671 FML_DCHECK(!external_view_embedder_->GetUsedThisFrame());
672 external_view_embedder_->SetUsedThisFrame(true);
673 external_view_embedder_->BeginFrame(surface_->GetContext(),
674 raster_thread_merger_);
675 }
676
677 std::optional<fml::TimePoint> presentation_time = std::nullopt;
678 // TODO (https://github.com/flutter/flutter/issues/105596): this can be in
679 // the past and might need to get snapped to future as this frame could
680 // have been resubmitted. `presentation_time` on SubmitInfo is not set
681 // in this case.
682 {
683 const auto vsync_target_time = frame_timings_recorder.GetVsyncTargetTime();
684 if (vsync_target_time > fml::TimePoint::Now()) {
685 presentation_time = vsync_target_time;
686 }
687 }
688
689 frame_timings_recorder.RecordRasterStart(fml::TimePoint::Now());
690
691 // Second traverse: draw all layer trees.
692 std::vector<std::unique_ptr<LayerTreeTask>> resubmitted_tasks;
693 for (std::unique_ptr<LayerTreeTask>& task : tasks) {
694 int64_t view_id = task->view_id;
695 std::unique_ptr<LayerTree> layer_tree = std::move(task->layer_tree);
696 float device_pixel_ratio = task->device_pixel_ratio;
697
698 DrawSurfaceStatus status = DrawToSurfaceUnsafe(
699 view_id, *layer_tree, device_pixel_ratio, presentation_time);
700 FML_DCHECK(status != DrawSurfaceStatus::kDiscarded);
701
702 auto& view_record = EnsureViewRecord(task->view_id);
703 view_record.last_draw_status = status;
704 if (status == DrawSurfaceStatus::kSuccess) {
705 view_record.last_successful_task = std::make_unique<LayerTreeTask>(
706 view_id, std::move(layer_tree), device_pixel_ratio);
707 } else if (status == DrawSurfaceStatus::kRetry) {
708 resubmitted_tasks.push_back(std::make_unique<LayerTreeTask>(
709 view_id, std::move(layer_tree), device_pixel_ratio));
710 }
711 }
712 // TODO(dkwingsmt): Pass in raster cache(s) for all views.
713 // See https://github.com/flutter/flutter/issues/135530, item 4.
714 frame_timings_recorder.RecordRasterEnd(
715 NOT_SLIMPELLER(&compositor_context_->raster_cache()));
716
717 FireNextFrameCallbackIfPresent();
718
719#if !SLIMPELLER
720 if (surface_->GetContext()) {
721 surface_->GetContext()->performDeferredCleanup(kSkiaCleanupExpiration);
722 }
723#endif // !SLIMPELLER
724
725 if (resubmitted_tasks.empty()) {
726 return nullptr;
727 } else {
728 return std::make_unique<FrameItem>(
729 std::move(resubmitted_tasks),
730 frame_timings_recorder.CloneUntil(
731 FrameTimingsRecorder::State::kBuildEnd));
732 }
733}
734
735/// \see Rasterizer::DrawToSurfaces
736DrawSurfaceStatus Rasterizer::DrawToSurfaceUnsafe(
737 int64_t view_id,
738 flutter::LayerTree& layer_tree,
739 float device_pixel_ratio,
740 std::optional<fml::TimePoint> presentation_time) {
742
743 DlCanvas* embedder_root_canvas = nullptr;
744 if (external_view_embedder_) {
745 external_view_embedder_->PrepareFlutterView(layer_tree.frame_size(),
746 device_pixel_ratio);
747 // TODO(dkwingsmt): Add view ID here.
748 embedder_root_canvas = external_view_embedder_->GetRootCanvas();
749 }
750
751 // On Android, the external view embedder deletes surfaces in `BeginFrame`.
752 //
753 // Deleting a surface also clears the GL context. Therefore, acquire the
754 // frame after calling `BeginFrame` as this operation resets the GL context.
755 auto frame = surface_->AcquireFrame(layer_tree.frame_size());
756 if (frame == nullptr) {
757 return DrawSurfaceStatus::kFailed;
758 }
759
760 // If the external view embedder has specified an optional root surface, the
761 // root surface transformation is set by the embedder instead of
762 // having to apply it here.
763 DlMatrix root_surface_transformation =
764 embedder_root_canvas ? DlMatrix() : surface_->GetRootTransformation();
765
766 auto root_surface_canvas =
767 embedder_root_canvas ? embedder_root_canvas : frame->Canvas();
768 auto compositor_frame = compositor_context_->AcquireFrame(
769 surface_->GetContext(), // skia GrContext
770 root_surface_canvas, // root surface canvas
771 external_view_embedder_.get(), // external view embedder
772 root_surface_transformation, // root surface transformation
773 true, // instrumentation enabled
774 frame->framebuffer_info()
775 .supports_readback, // surface supports pixel reads
776 raster_thread_merger_, // thread merger
777 surface_->GetAiksContext().get() // aiks context
778 );
779 if (compositor_frame) {
780 NOT_SLIMPELLER(compositor_context_->raster_cache().BeginFrame());
781
782 std::unique_ptr<FrameDamage> damage;
783 // when leaf layer tracing is enabled we wish to repaint the whole frame
784 // for accurate performance metrics.
785 if (frame->framebuffer_info().supports_partial_repaint) {
786 // Disable partial repaint if external_view_embedder_ SubmitFlutterView is
787 // involved - ExternalViewEmbedder unconditionally clears the entire
788 // surface and also partial repaint with platform view present is
789 // something that still need to be figured out.
790 bool force_full_repaint =
791 external_view_embedder_ &&
792 (!raster_thread_merger_ || raster_thread_merger_->IsMerged());
793
794 damage = std::make_unique<FrameDamage>();
795 auto existing_damage = frame->framebuffer_info().existing_damage;
796 if (existing_damage.has_value() && !force_full_repaint) {
797 damage->SetPreviousLayerTree(GetLastLayerTree(view_id));
798 damage->AddAdditionalDamage(existing_damage.value());
799 damage->SetClipAlignment(
800 frame->framebuffer_info().horizontal_clip_alignment,
801 frame->framebuffer_info().vertical_clip_alignment);
802 }
803 }
804
805 bool ignore_raster_cache = true;
806 if (surface_->EnableRasterCache()) {
807 ignore_raster_cache = false;
808 }
809
810 RasterStatus frame_status =
811 compositor_frame->Raster(layer_tree, // layer tree
812 ignore_raster_cache, // ignore raster cache
813 damage.get() // frame damage
814 );
815 if (frame_status == RasterStatus::kSkipAndRetry) {
816 return DrawSurfaceStatus::kRetry;
817 }
818
819 SurfaceFrame::SubmitInfo submit_info;
820 submit_info.presentation_time = presentation_time;
821 if (damage) {
822 submit_info.frame_damage = damage->GetFrameDamage();
823 submit_info.buffer_damage = damage->GetBufferDamage();
824 }
825
826 frame->set_submit_info(submit_info);
827
828 if (external_view_embedder_ &&
829 (!raster_thread_merger_ || raster_thread_merger_->IsMerged())) {
830 FML_DCHECK(!frame->IsSubmitted());
831 external_view_embedder_->SubmitFlutterView(
832 view_id, surface_->GetContext(), surface_->GetAiksContext(),
833 std::move(frame));
834 } else {
835 frame->Submit();
836 }
837
838#if !SLIMPELLER
839 // Do not update raster cache metrics for kResubmit because that status
840 // indicates that the frame was not actually painted.
841 if (frame_status != RasterStatus::kResubmit) {
842 compositor_context_->raster_cache().EndFrame();
843 }
844#endif // !SLIMPELLER
845
846 if (frame_status == RasterStatus::kResubmit) {
847 return DrawSurfaceStatus::kRetry;
848 } else {
849 FML_CHECK(frame_status == RasterStatus::kSuccess);
850 return DrawSurfaceStatus::kSuccess;
851 }
852 }
853
854 return DrawSurfaceStatus::kFailed;
855}
856
857Rasterizer::ViewRecord& Rasterizer::EnsureViewRecord(int64_t view_id) {
858 return view_records_[view_id];
859}
860
861static sk_sp<SkData> ScreenshotLayerTreeAsPicture(
862 flutter::LayerTree* tree,
863 flutter::CompositorContext& compositor_context) {
864#if SLIMPELLER
865 return nullptr;
866#else // SLIMPELLER
867 FML_DCHECK(tree != nullptr);
868 SkPictureRecorder recorder;
869 recorder.beginRecording(
870 SkRect::MakeWH(tree->frame_size().width, tree->frame_size().height));
871
872 DlMatrix root_surface_transformation;
873 DlSkCanvasAdapter canvas(recorder.getRecordingCanvas());
874
875 // TODO(amirh): figure out how to take a screenshot with embedded UIView.
876 // https://github.com/flutter/flutter/issues/23435
877 auto frame = compositor_context.AcquireFrame(nullptr, &canvas, nullptr,
878 root_surface_transformation,
879 false, true, nullptr, nullptr);
880 frame->Raster(*tree, true, nullptr);
881
882#if defined(OS_FUCHSIA)
883 SkSerialProcs procs = {0};
884 procs.fImageProc = SerializeImageWithoutData;
885 procs.fTypefaceProc = SerializeTypefaceWithoutData;
886#else
887 SkSerialProcs procs = {0};
888 procs.fTypefaceProc = SerializeTypefaceWithData;
889 procs.fImageProc = [](SkImage* img, void*) -> SkSerialReturnType {
890 return SkPngEncoder::Encode(nullptr, img, SkPngEncoder::Options{});
891 };
892#endif
893
894 return recorder.finishRecordingAsPicture()->serialize(&procs);
895#endif // SLIMPELLER
896}
897
899 flutter::CompositorContext& compositor_context,
900 DlCanvas* canvas,
901 flutter::LayerTree* tree,
902 GrDirectContext* surface_context,
903 const std::shared_ptr<impeller::AiksContext>& aiks_context) {
904 // There is no root surface transformation for the screenshot layer. Reset
905 // the matrix to identity.
906 DlMatrix root_surface_transformation;
907
908 auto frame = compositor_context.AcquireFrame(
909 /*gr_context=*/surface_context,
910 /*canvas=*/canvas,
911 /*view_embedder=*/nullptr,
912 /*root_surface_transformation=*/root_surface_transformation,
913 /*instrumentation_enabled=*/false,
914 /*surface_supports_readback=*/true,
915 /*raster_thread_merger=*/nullptr,
916 /*aiks_context=*/aiks_context.get());
917 canvas->Clear(DlColor::kTransparent());
918 frame->Raster(*tree, true, nullptr);
919 canvas->Flush();
920}
921
922#if IMPELLER_SUPPORTS_RENDERING
923Rasterizer::ScreenshotFormat ToScreenshotFormat(impeller::PixelFormat format) {
924 switch (format) {
956 FML_DCHECK(false);
957 return Rasterizer::ScreenshotFormat::kUnknown;
959 return Rasterizer::ScreenshotFormat::kR8G8B8A8UNormInt;
961 return Rasterizer::ScreenshotFormat::kB8G8R8A8UNormInt;
963 return Rasterizer::ScreenshotFormat::kR16G16B16A16Float;
964 }
965}
966
967static std::pair<sk_sp<SkData>, Rasterizer::ScreenshotFormat>
968ScreenshotLayerTreeAsImageImpeller(
969 const std::shared_ptr<impeller::AiksContext>& aiks_context,
970 flutter::LayerTree* tree,
971 flutter::CompositorContext& compositor_context,
972 bool compressed) {
973 if (compressed) {
974 FML_LOG(ERROR) << "Compressed screenshots not supported for Impeller";
975 return {nullptr, Rasterizer::ScreenshotFormat::kUnknown};
976 }
977
978 DisplayListBuilder builder(DlRect::MakeSize(tree->frame_size()));
979
980 RenderFrameForScreenshot(compositor_context, &builder, tree, nullptr,
981 aiks_context);
982
983 std::shared_ptr<impeller::Texture> texture = impeller::DisplayListToTexture(
984 builder.Build(), impeller::ISize(tree->frame_size()), *aiks_context);
985 if (!texture) {
986 FML_LOG(ERROR) << "Failed to render to texture";
987 return {nullptr, Rasterizer::ScreenshotFormat::kUnknown};
988 }
989
992 buffer_desc.size =
993 texture->GetTextureDescriptor().GetByteSizeOfBaseMipLevel();
994 auto impeller_context = aiks_context->GetContext();
995 auto buffer =
996 impeller_context->GetResourceAllocator()->CreateBuffer(buffer_desc);
997 auto command_buffer = impeller_context->CreateCommandBuffer();
998 command_buffer->SetLabel("BlitTextureToBuffer Command Buffer");
999 auto pass = command_buffer->CreateBlitPass();
1000 pass->AddCopy(texture, buffer);
1001 pass->EncodeCommands();
1003 sk_sp<SkData> sk_data;
1004 auto completion = [buffer, &buffer_desc, &sk_data,
1005 &latch](impeller::CommandBuffer::Status status) {
1006 fml::ScopedCleanupClosure cleanup([&latch]() { latch.Signal(); });
1008 FML_LOG(ERROR) << "Failed to complete blit pass.";
1009 return;
1010 }
1011 sk_data = SkData::MakeWithCopy(buffer->OnGetContents(), buffer_desc.size);
1012 };
1013
1014 if (!impeller_context->GetCommandQueue()
1015 ->Submit({command_buffer}, completion)
1016 .ok()) {
1017 FML_LOG(ERROR) << "Failed to submit commands.";
1018 }
1019 latch.Wait();
1020 return std::make_pair(
1021 sk_data, ToScreenshotFormat(texture->GetTextureDescriptor().format));
1022}
1023#endif
1024
1025std::pair<sk_sp<SkData>, Rasterizer::ScreenshotFormat>
1026Rasterizer::ScreenshotLayerTreeAsImage(
1027 flutter::LayerTree* tree,
1028 flutter::CompositorContext& compositor_context,
1029 bool compressed) {
1030#if IMPELLER_SUPPORTS_RENDERING
1031 if (delegate_.GetSettings().enable_impeller) {
1032 return ScreenshotLayerTreeAsImageImpeller(GetAiksContext(), tree,
1033 compositor_context, compressed);
1034 }
1035#endif // IMPELLER_SUPPORTS_RENDERING
1036
1037#if SLIMPELLER
1038 FML_LOG(FATAL) << "Impeller opt-out unavailable.";
1039 return {nullptr, ScreenshotFormat::kUnknown};
1040#else // SLIMPELLER
1041 GrDirectContext* surface_context = GetGrContext();
1042 // Attempt to create a snapshot surface depending on whether we have access
1043 // to a valid GPU rendering context.
1044 std::unique_ptr<OffscreenSurface> snapshot_surface =
1045 std::make_unique<OffscreenSurface>(surface_context, tree->frame_size());
1046
1047 if (!snapshot_surface->IsValid()) {
1048 FML_LOG(ERROR) << "Screenshot: unable to create snapshot surface";
1049 return {nullptr, ScreenshotFormat::kUnknown};
1050 }
1051
1052 // Draw the current layer tree into the snapshot surface.
1053 DlCanvas* canvas = snapshot_surface->GetCanvas();
1054
1055 // snapshot_surface->makeImageSnapshot needs the GL context to be set if the
1056 // render context is GL. frame->Raster() pops the gl context in platforms
1057 // that gl context switching are used. (For example, older iOS that uses GL)
1058 // We reset the GL context using the context switch.
1059 auto context_switch = surface_->MakeRenderContextCurrent();
1060 if (!context_switch->GetResult()) {
1061 FML_LOG(ERROR) << "Screenshot: unable to make image screenshot";
1062 return {nullptr, ScreenshotFormat::kUnknown};
1063 }
1064
1065 RenderFrameForScreenshot(compositor_context, canvas, tree, surface_context,
1066 nullptr);
1067
1068 return std::make_pair(snapshot_surface->GetRasterData(compressed),
1069 ScreenshotFormat::kUnknown);
1070#endif // !SLIMPELLER
1071}
1072
1073Rasterizer::Screenshot Rasterizer::ScreenshotLastLayerTree(
1075 bool base64_encode) {
1076 if (delegate_.GetSettings().enable_impeller &&
1077 type == ScreenshotType::SkiaPicture) {
1078 FML_DCHECK(false);
1079 FML_LOG(ERROR) << "Last layer tree cannot be screenshotted as a "
1080 "SkiaPicture when using Impeller.";
1081 return {};
1082 }
1083 // TODO(dkwingsmt): Support screenshotting all last layer trees
1084 // when the shell protocol supports multi-views.
1085 // https://github.com/flutter/flutter/issues/135534
1086 // https://github.com/flutter/flutter/issues/135535
1087 auto* layer_tree = GetLastLayerTree(kFlutterImplicitViewId);
1088 if (layer_tree == nullptr) {
1089 FML_LOG(ERROR) << "Last layer tree was null when screenshotting.";
1090 return {};
1091 }
1092
1093 std::pair<sk_sp<SkData>, ScreenshotFormat> data{nullptr,
1094 ScreenshotFormat::kUnknown};
1095 std::string format;
1096
1097 switch (type) {
1098 case ScreenshotType::SkiaPicture:
1099 format = "ScreenshotType::SkiaPicture";
1100 data.first =
1101 ScreenshotLayerTreeAsPicture(layer_tree, *compositor_context_);
1102 break;
1103 case ScreenshotType::UncompressedImage:
1104 format = "ScreenshotType::UncompressedImage";
1105 data =
1106 ScreenshotLayerTreeAsImage(layer_tree, *compositor_context_, false);
1107 break;
1108 case ScreenshotType::CompressedImage:
1109 format = "ScreenshotType::CompressedImage";
1110 data = ScreenshotLayerTreeAsImage(layer_tree, *compositor_context_, true);
1111 break;
1112 case ScreenshotType::SurfaceData: {
1113 Surface::SurfaceData surface_data = surface_->GetSurfaceData();
1114 format = surface_data.pixel_format;
1115 data.first = surface_data.data;
1116 break;
1117 }
1118 }
1119
1120 if (data.first == nullptr) {
1121 FML_LOG(ERROR) << "Screenshot data was null.";
1122 return {};
1123 }
1124
1125 if (base64_encode) {
1126 size_t b64_size = Base64::EncodedSize(data.first->size());
1127 auto b64_data = SkData::MakeUninitialized(b64_size);
1128 Base64::Encode(data.first->data(), data.first->size(),
1129 b64_data->writable_data());
1130 return Rasterizer::Screenshot{b64_data, layer_tree->frame_size(), format,
1131 data.second};
1132 }
1133
1134 return Rasterizer::Screenshot{data.first, layer_tree->frame_size(), format,
1135 data.second};
1136}
1137
1138void Rasterizer::SetNextFrameCallback(const fml::closure& callback) {
1139 next_frame_callback_ = callback;
1140}
1141
1142void Rasterizer::SetExternalViewEmbedder(
1143 const std::shared_ptr<ExternalViewEmbedder>& view_embedder) {
1144 external_view_embedder_ = view_embedder;
1145}
1146
1147void Rasterizer::SetSnapshotSurfaceProducer(
1148 std::unique_ptr<SnapshotSurfaceProducer> producer) {
1149 snapshot_surface_producer_ = std::move(producer);
1150}
1151
1152fml::RefPtr<fml::RasterThreadMerger> Rasterizer::GetRasterThreadMerger() {
1153 return raster_thread_merger_;
1154}
1155
1156void Rasterizer::FireNextFrameCallbackIfPresent() {
1157 if (!next_frame_callback_) {
1158 return;
1159 }
1160 // It is safe for the callback to set a new callback.
1161 auto callback = next_frame_callback_;
1162 next_frame_callback_ = nullptr;
1163 callback();
1164}
1165
1166void Rasterizer::SetResourceCacheMaxBytes(size_t max_bytes, bool from_user) {
1167#if !SLIMPELLER
1168 user_override_resource_cache_bytes_ |= from_user;
1169
1170 if (!from_user && user_override_resource_cache_bytes_) {
1171 // We should not update the setting here if a user has explicitly set a
1172 // value for this over the flutter/skia channel.
1173 return;
1174 }
1175
1176 max_cache_bytes_ = max_bytes;
1177 if (!surface_) {
1178 return;
1179 }
1180
1181 GrDirectContext* context = surface_->GetContext();
1182 if (context) {
1183 auto context_switch = surface_->MakeRenderContextCurrent();
1184 if (!context_switch->GetResult()) {
1185 return;
1186 }
1187
1188 context->setResourceCacheLimit(max_bytes);
1189 }
1190#endif // !SLIMPELLER
1191}
1192
1193std::optional<size_t> Rasterizer::GetResourceCacheMaxBytes() const {
1194#if SLIMPELLER
1195 return std::nullopt;
1196#else // SLIMPELLER
1197 if (!surface_) {
1198 return std::nullopt;
1199 }
1200 GrDirectContext* context = surface_->GetContext();
1201 if (context) {
1202 return context->getResourceCacheLimit();
1203 }
1204 return std::nullopt;
1205#endif // SLIMPELLER
1206}
1207
1208Rasterizer::Screenshot::Screenshot() {}
1209
1210Rasterizer::Screenshot::Screenshot(sk_sp<SkData> p_data,
1211 DlISize p_size,
1212 const std::string& p_format,
1213 ScreenshotFormat p_pixel_format)
1214 : data(std::move(p_data)),
1215 frame_size(p_size),
1216 format(p_format),
1217 pixel_format(p_pixel_format) {}
1218
1219Rasterizer::Screenshot::Screenshot(const Screenshot& other) = default;
1220
1222
1223} // 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)