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