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