9 #include <unordered_map>
12 #include "display_list/effects/dl_color_source.h"
13 #include "display_list/effects/dl_image_filter.h"
14 #include "flutter/fml/logging.h"
15 #include "flutter/fml/trace_event.h"
52 static bool UseColorSourceContents(
53 const std::shared_ptr<VerticesGeometry>& vertices,
57 if (vertices->HasVertexColors()) {
60 if (vertices->HasTextureCoordinates() && !paint.color_source) {
63 return !vertices->HasTextureCoordinates();
66 static void SetClipScissor(std::optional<Rect> clip_coverage,
68 Point global_pass_position) {
72 if (clip_coverage.has_value()) {
73 clip_coverage = clip_coverage->
Shift(-global_pass_position);
76 scissor = scissor.Intersection(
IRect::MakeSize(pass.GetRenderTargetSize()))
79 pass.SetScissor(scissor);
82 static void ApplyFramebufferBlend(Entity& entity) {
83 auto src_contents = entity.GetContents();
84 auto contents = std::make_shared<FramebufferBlendContents>();
85 contents->SetChildContents(src_contents);
86 contents->SetBlendMode(entity.GetBlendMode());
87 entity.SetContents(std::move(contents));
93 static std::shared_ptr<Contents> CreateContentsForSubpassTarget(
95 const std::shared_ptr<Texture>& target,
96 const Matrix& effect_transform) {
98 contents->SetTexture(target);
99 contents->SetLabel(
"Subpass");
101 contents->SetOpacity(paint.color.alpha);
102 contents->SetDeferApplyingOpacity(
true);
104 return paint.WithFiltersForSubpassTarget(std::move(contents),
108 static const constexpr RenderTarget::AttachmentConfig kDefaultStencilConfig =
109 RenderTarget::AttachmentConfig{
115 static std::unique_ptr<EntityPassTarget> CreateRenderTarget(
116 ContentContext& renderer,
118 const Color& clear_color) {
119 const std::shared_ptr<Context>& context = renderer.GetContext();
127 if (context->GetCapabilities()->SupportsOffscreenMSAA()) {
128 target = renderer.GetRenderTargetCache()->CreateOffscreenMSAA(
134 RenderTarget::AttachmentConfigMSAA{
139 .clear_color = clear_color},
140 kDefaultStencilConfig);
142 target = renderer.GetRenderTargetCache()->CreateOffscreen(
147 RenderTarget::AttachmentConfig{
151 .clear_color = clear_color,
153 kDefaultStencilConfig
157 return std::make_unique<EntityPassTarget>(
158 target, renderer.GetDeviceCapabilities().SupportsReadFromResolve(),
159 renderer.GetDeviceCapabilities().SupportsImplicitResolvingMSAA());
167 bool requires_readback)
168 : renderer_(renderer),
169 render_target_(render_target),
170 is_onscreen_(is_onscreen),
171 requires_readback_(requires_readback),
173 Rect::MakeSize(render_target.GetRenderTargetSize()))) {
174 Initialize(std::nullopt);
181 bool requires_readback,
183 : renderer_(renderer),
184 render_target_(render_target),
185 is_onscreen_(is_onscreen),
186 requires_readback_(requires_readback),
188 Rect::MakeSize(render_target.GetRenderTargetSize()))) {
189 Initialize(cull_rect);
196 bool requires_readback,
198 : renderer_(renderer),
199 render_target_(render_target),
200 is_onscreen_(is_onscreen),
201 requires_readback_(requires_readback),
203 Rect::MakeSize(render_target.GetRenderTargetSize()))) {
209 void Canvas::Initialize(std::optional<Rect> cull_rect) {
210 initial_cull_rect_ = cull_rect;
217 void Canvas::Reset() {
219 transform_stack_ = {};
231 transform_stack_.back().transform = {};
239 return transform_stack_.back().transform;
262 Point Canvas::GetGlobalPassPosition()
const {
263 if (save_layer_state_.empty()) {
266 return save_layer_state_.back().coverage.GetOrigin();
270 size_t Canvas::GetClipHeightFloor()
const {
271 if (transform_stack_.size() > 1) {
272 return transform_stack_[transform_stack_.size() - 2].clip_height;
278 return transform_stack_.size();
281 bool Canvas::IsSkipping()
const {
282 return transform_stack_.back().skipping;
300 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
304 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
314 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
317 bool Canvas::AttemptDrawBlurredRRect(
const Rect& rect,
319 const Paint& paint) {
344 Color rrect_color = paint.
color;
377 (!rrect_color.IsOpaque() ||
379 Rect render_bounds = rect;
393 rrect_paint.color = rrect_color.WithAlpha(1);
395 rrect_paint.color = rrect_color;
401 auto draw_blurred_rrect = [
this, &rect, &corner_radii, &rrect_paint]() {
402 auto contents = std::make_shared<SolidRRectBlurContents>();
404 contents->SetColor(rrect_paint.color);
405 contents->SetSigma(rrect_paint.mask_blur_descriptor->sigma);
406 contents->SetRRect(rect, corner_radii);
408 Entity blurred_rrect_entity;
410 blurred_rrect_entity.SetBlendMode(rrect_paint.blend_mode);
412 rrect_paint.mask_blur_descriptor = std::nullopt;
413 blurred_rrect_entity.SetContents(
414 rrect_paint.WithFilters(std::move(contents)));
415 AddRenderEntityToCurrentPass(blurred_rrect_entity);
418 switch (rrect_paint.mask_blur_descriptor->style) {
420 draw_blurred_rrect();
425 draw_blurred_rrect();
429 entity.SetBlendMode(rrect_paint.blend_mode);
431 RoundRectGeometry geom(rect, corner_radii);
432 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, rrect_paint,
437 RoundRectGeometry geom(rect, corner_radii);
439 draw_blurred_rrect();
443 RoundRectGeometry geom(rect, corner_radii);
445 draw_blurred_rrect();
464 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint,
474 if (AttemptDrawBlurredRRect(rect, {}, paint)) {
483 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
504 if (AttemptDrawBlurredRRect(rect, rect.
GetSize() * 0.5f, paint)) {
513 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
518 auto& radii = round_rect.
GetRadii();
519 if (radii.AreAllCornersSame()) {
520 if (AttemptDrawBlurredRRect(rect, radii.top_left, paint)) {
530 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
545 const Paint& paint) {
546 Size half_size(radius, radius);
547 if (AttemptDrawBlurredRRect(
549 {radius, radius}, paint)) {
559 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
562 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
583 FML_DCHECK(current_depth_ <= transform_stack_.back().clip_depth)
584 << current_depth_ <<
" <=? " << transform_stack_.back().clip_depth;
585 uint32_t clip_depth = transform_stack_.back().clip_depth;
587 const Matrix clip_transform =
591 std::optional<Rect> clip_coverage = geometry.
GetCoverage(clip_transform);
592 if (!clip_coverage.has_value()) {
597 clip_coverage.value(),
606 GetGlobalPassPosition(),
608 GetClipHeightFloor(),
614 *render_passes_.back().inline_pass_context->GetRenderPass(),
615 GetGlobalPassPosition());
618 ++transform_stack_.back().clip_height;
619 ++transform_stack_.back().num_clips;
636 *render_passes_.back().inline_pass_context->GetRenderPass()
643 renderer_, *render_passes_.back().inline_pass_context->GetRenderPass(),
662 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
674 const auto dest = source.Shift(
offset);
689 auto size = image->GetSize();
691 if (size.IsEmpty()) {
695 std::optional<Rect> clipped_source =
697 if (!clipped_source) {
700 if (*clipped_source != source) {
710 texture_contents->SetTexture(image);
711 texture_contents->SetSourceRect(*clipped_source);
712 texture_contents->SetStrictSourceRect(src_rect_constraint ==
714 texture_contents->SetSamplerDescriptor(sampler);
715 texture_contents->SetOpacity(paint.
color.
alpha);
716 texture_contents->SetDeferApplyingOpacity(paint.
HasColorFilter());
724 AddRenderEntityToCurrentPass(entity);
732 AddRenderEntityToCurrentPass(entity);
735 size_t Canvas::GetClipHeight()
const {
736 return transform_stack_.back().clip_height;
741 const Paint& paint) {
754 if (UseColorSourceContents(vertices, paint)) {
755 AddRenderEntityWithFiltersToCurrentPass(entity, vertices.get(), paint);
761 auto contents = std::make_shared<VerticesSimpleBlendContents>();
762 contents->SetBlendMode(blend_mode);
764 contents->SetGeometry(vertices);
766 AddRenderEntityToCurrentPass(entity);
773 paint.
color_source->type() == flutter::DlColorSourceType::kImage) {
774 const flutter::DlImageColorSource* image_color_source =
776 FML_DCHECK(image_color_source &&
777 image_color_source->image()->impeller_texture());
778 auto texture = image_color_source->image()->impeller_texture();
780 image_color_source->horizontal_tile_mode());
783 auto sampler_descriptor =
785 auto effect_transform = image_color_source->matrix();
787 auto contents = std::make_shared<VerticesSimpleBlendContents>();
788 contents->SetBlendMode(blend_mode);
790 contents->SetGeometry(vertices);
791 contents->SetEffectTransform(effect_transform);
792 contents->SetTexture(texture);
793 contents->SetTileMode(x_tile_mode, y_tile_mode);
794 contents->SetSamplerDescriptor(sampler_descriptor);
797 AddRenderEntityToCurrentPass(entity);
801 auto src_paint = paint;
804 std::shared_ptr<ColorSourceContents> src_contents =
805 src_paint.CreateContents();
806 src_contents->SetGeometry(vertices.get());
814 auto size = src_contents->GetColorSourceSize();
815 if (size.has_value()) {
818 auto cvg = vertices->GetCoverage(
Matrix{});
819 FML_CHECK(cvg.has_value());
820 auto texture_coverage = vertices->GetTextureCoordinateCoverge();
821 if (texture_coverage.has_value()) {
824 texture_coverage->GetSize().Max({1, 1}));
826 src_coverage = cvg.value();
829 src_contents = src_paint.CreateContents();
832 src_contents->SetGeometry(clip_geometry_.back().get());
834 auto contents = std::make_shared<VerticesSimpleBlendContents>();
835 contents->SetBlendMode(blend_mode);
837 contents->SetGeometry(vertices);
838 contents->SetLazyTextureCoverage(src_coverage);
839 contents->SetLazyTexture([src_contents,
845 src_contents->RenderToSnapshot(renderer, {},
Rect::Round(src_coverage));
846 return snapshot.has_value() ? snapshot->texture :
nullptr;
849 AddRenderEntityToCurrentPass(entity);
853 const Paint& paint) {
861 AddRenderEntityToCurrentPass(entity);
867 void Canvas::SetupRenderPass() {
873 if (!stencil_attachment.has_value() || !depth_attachment.has_value()) {
878 *renderer_.
GetContext()->GetResourceAllocator(),
880 renderer_.
GetContext()->GetCapabilities()->SupportsOffscreenMSAA(),
881 "ImpellerOnscreen", kDefaultStencilConfig);
893 if (requires_readback_) {
894 auto entity_pass_target =
895 CreateRenderTarget(renderer_,
898 render_passes_.push_back(
899 LazyRenderingConfig(renderer_, std::move(entity_pass_target)));
901 auto entity_pass_target = std::make_unique<EntityPassTarget>(
906 render_passes_.push_back(
907 LazyRenderingConfig(renderer_, std::move(entity_pass_target)));
911 void Canvas::SkipUntilMatchingRestore(
size_t total_content_depth) {
912 auto entry = CanvasStackEntry{};
913 entry.skipping =
true;
914 entry.clip_depth = current_depth_ + total_content_depth;
915 transform_stack_.push_back(entry);
920 return SkipUntilMatchingRestore(total_content_depth);
924 entry.
transform = transform_stack_.back().transform;
925 entry.clip_depth = current_depth_ + total_content_depth;
926 entry.distributed_opacity = transform_stack_.back().distributed_opacity;
927 FML_DCHECK(entry.clip_depth <= transform_stack_.back().clip_depth)
928 << entry.clip_depth <<
" <=? " << transform_stack_.back().clip_depth
929 <<
" after allocating " << total_content_depth;
930 entry.clip_height = transform_stack_.back().clip_height;
932 transform_stack_.push_back(entry);
943 if (!maybe_current_clip_coverage.has_value()) {
947 auto current_clip_coverage = maybe_current_clip_coverage.value();
951 std::optional<Rect> maybe_coverage_limit =
953 Size(render_passes_.back()
954 .inline_pass_context->GetTexture()
958 if (!maybe_coverage_limit.has_value() || maybe_coverage_limit->IsEmpty()) {
962 return maybe_coverage_limit->Intersection(
967 std::optional<Rect> bounds,
968 const flutter::DlImageFilter* backdrop_filter,
970 uint32_t total_content_depth,
971 bool can_distribute_opacity,
972 std::optional<int64_t> backdrop_id) {
973 TRACE_EVENT0(
"flutter",
"Canvas::saveLayer");
975 return SkipUntilMatchingRestore(total_content_depth);
979 if (!maybe_coverage_limit.has_value()) {
980 return SkipUntilMatchingRestore(total_content_depth);
982 auto coverage_limit = maybe_coverage_limit.value();
984 if (can_distribute_opacity && !backdrop_filter &&
987 Save(total_content_depth);
988 transform_stack_.back().distributed_opacity *= paint.
color.
alpha;
992 std::shared_ptr<FilterContents> filter_contents = paint.
WithImageFilter(
993 Rect(), transform_stack_.back().transform,
998 transform_stack_.back().transform,
1003 !!backdrop_filter ||
1008 if (!maybe_subpass_coverage.has_value()) {
1009 return SkipUntilMatchingRestore(total_content_depth);
1012 auto subpass_coverage = maybe_subpass_coverage.value();
1023 bool did_round_out =
false;
1024 Point coverage_origin_adjustment =
Point{0, 0};
1028 did_round_out =
true;
1032 coverage_origin_adjustment =
1033 Point(subpass_coverage.GetLeftTop().x -
1034 std::floor(subpass_coverage.GetLeftTop().x),
1035 subpass_coverage.GetLeftTop().y -
1036 std::floor(subpass_coverage.GetLeftTop().y));
1039 return SkipUntilMatchingRestore(total_content_depth);
1047 ->GetMaximumRenderPassAttachmentSize());
1050 std::shared_ptr<FilterContents> backdrop_filter_contents;
1052 if (backdrop_filter) {
1053 local_position = subpass_coverage.GetOrigin() - GetGlobalPassPosition();
1055 [backdrop_filter = backdrop_filter](
1058 auto filter =
WrapInput(backdrop_filter, input);
1059 filter->SetEffectTransform(effect_transform);
1060 filter->SetRenderingMode(rendering_mode);
1064 std::shared_ptr<Texture> input_texture;
1069 bool will_cache_backdrop_texture =
false;
1074 size_t backdrop_count = 1;
1075 if (backdrop_id.has_value()) {
1076 std::unordered_map<int64_t, BackdropData>::iterator backdrop_data_it =
1077 backdrop_data_.find(backdrop_id.value());
1078 if (backdrop_data_it != backdrop_data_.end()) {
1079 backdrop_data = &backdrop_data_it->second;
1080 will_cache_backdrop_texture =
1082 backdrop_count = backdrop_data_it->second.backdrop_count;
1086 if (!will_cache_backdrop_texture || !backdrop_data->
texture_slot) {
1087 backdrop_count_ -= backdrop_count;
1093 const bool should_use_onscreen =
1095 backdrop_count_ == 0 && render_passes_.size() == 1u;
1096 input_texture = FlipBackdrop(
1097 GetGlobalPassPosition(),
1098 will_cache_backdrop_texture,
1101 if (!input_texture) {
1106 if (will_cache_backdrop_texture) {
1113 backdrop_filter_contents = backdrop_filter_proc(
1115 transform_stack_.back().transform.Basis(),
1118 transform_stack_.back().transform.HasTranslation()
1122 if (will_cache_backdrop_texture) {
1123 FML_DCHECK(backdrop_data);
1130 backdrop_filter_contents->RenderToSnapshot(renderer_, {});
1133 std::optional<Snapshot> maybe_snapshot =
1135 if (maybe_snapshot.has_value()) {
1136 Snapshot snapshot = maybe_snapshot.value();
1138 subpass_coverage.Shift(-GetGlobalPassPosition()));
1141 contents->SetTexture(snapshot.
texture);
1142 contents->SetSourceRect(scaled);
1152 backdrop_entity.
Render(renderer_, GetCurrentRenderPass());
1160 Paint paint_copy = paint;
1161 paint_copy.
color.
alpha *= transform_stack_.back().distributed_opacity;
1162 transform_stack_.back().distributed_opacity = 1.0;
1164 render_passes_.push_back(
1166 CreateRenderTarget(renderer_,
1171 paint_copy, subpass_coverage.Shift(-coverage_origin_adjustment)});
1174 entry.
transform = transform_stack_.back().transform;
1175 entry.
clip_depth = current_depth_ + total_content_depth;
1176 FML_DCHECK(entry.
clip_depth <= transform_stack_.back().clip_depth)
1177 << entry.
clip_depth <<
" <=? " << transform_stack_.back().clip_depth
1178 <<
" after allocating " << total_content_depth;
1179 entry.
clip_height = transform_stack_.back().clip_height;
1182 transform_stack_.emplace_back(entry);
1189 clip_coverage_stack_.
PushSubpass(subpass_coverage, GetClipHeight());
1191 if (!backdrop_filter_contents) {
1197 backdrop_entity.
SetContents(std::move(backdrop_filter_contents));
1200 backdrop_entity.
SetClipDepth(std::numeric_limits<uint32_t>::max());
1201 backdrop_entity.
Render(renderer_, GetCurrentRenderPass());
1205 FML_DCHECK(transform_stack_.size() > 0);
1206 if (transform_stack_.size() == 1) {
1223 FML_DCHECK(current_depth_ <= transform_stack_.back().clip_depth)
1224 << current_depth_ <<
" <=? " << transform_stack_.back().clip_depth;
1225 current_depth_ = transform_stack_.back().clip_depth;
1228 transform_stack_.pop_back();
1232 if (transform_stack_.back().rendering_mode ==
1234 transform_stack_.back().rendering_mode ==
1236 auto lazy_render_pass = std::move(render_passes_.back());
1237 render_passes_.pop_back();
1239 lazy_render_pass.inline_pass_context->GetRenderPass();
1242 save_layer_state_.pop_back();
1243 auto global_pass_position = GetGlobalPassPosition();
1245 std::shared_ptr<Contents> contents = CreateContentsForSubpassTarget(
1246 save_layer_state.
paint,
1247 lazy_render_pass.inline_pass_context->GetTexture(),
1249 transform_stack_.back().transform
1252 lazy_render_pass.inline_pass_context->EndPass();
1259 Point subpass_texture_position;
1260 if (transform_stack_.back().did_round_out) {
1263 subpass_texture_position =
1268 subpass_texture_position =
1282 ApplyFramebufferBlend(element_entity);
1293 auto input_texture = FlipBackdrop(GetGlobalPassPosition());
1294 if (!input_texture) {
1304 contents->SetCoverageHint(element_entity.
GetCoverage());
1312 *render_passes_.back().inline_pass_context->GetRenderPass()
1315 transform_stack_.pop_back();
1323 size_t num_clips = transform_stack_.back().num_clips;
1324 transform_stack_.pop_back();
1326 if (num_clips > 0) {
1337 *render_passes_.back().inline_pass_context->GetRenderPass(),
1338 GetGlobalPassPosition()
1348 const Paint& paint) {
1353 auto text_contents = std::make_shared<TextContents>();
1354 text_contents->SetTextFrame(text_frame);
1357 text_contents->SetColor(paint.
color);
1358 text_contents->SetOffset(position);
1359 text_contents->SetTextProperties(paint.
color,
1379 AddRenderEntityToCurrentPass(entity,
false);
1382 void Canvas::AddRenderEntityWithFiltersToCurrentPass(
Entity& entity,
1386 std::shared_ptr<ColorSourceContents> contents = paint.
CreateContents();
1389 contents->SetGeometry(geometry);
1391 AddRenderEntityToCurrentPass(entity, reuse_depth);
1399 if (needs_color_filter &&
1400 contents->ApplyColorFilter([&](Color color) -> Color {
1401 if (paint.color_filter) {
1402 color = GetCPUColorFilterProc(paint.color_filter)(color);
1405 color = color.ApplyColorMatrix(kColorInversion);
1409 needs_color_filter =
false;
1413 contents->SetGeometry(geometry);
1419 RectGeometry out_rect(
Rect{});
1421 contents, needs_color_filter ? paint.
color_filter :
nullptr,
1422 needs_color_filter ? paint.
invert_colors :
false, &out_rect);
1424 AddRenderEntityToCurrentPass(entity, reuse_depth);
1428 std::shared_ptr<Contents> contents_copy = std::move(contents);
1432 if (needs_color_filter &&
1434 paint.
color_source->type() != flutter::DlColorSourceType::kImage)) {
1448 std::shared_ptr<FilterContents> filter =
WrapInput(
1452 AddRenderEntityToCurrentPass(entity, reuse_depth);
1457 AddRenderEntityToCurrentPass(entity, reuse_depth);
1460 void Canvas::AddRenderEntityToCurrentPass(Entity& entity,
bool reuse_depth) {
1465 entity.SetTransform(
1466 Matrix::MakeTranslation(Vector3(-GetGlobalPassPosition())) *
1467 entity.GetTransform());
1468 entity.SetInheritedOpacity(transform_stack_.back().distributed_opacity);
1469 if (entity.GetBlendMode() == BlendMode::kSourceOver &&
1470 entity.GetContents()->IsOpaque(entity.GetTransform())) {
1471 entity.SetBlendMode(BlendMode::kSource);
1477 if (render_passes_.back().IsApplyingClearColor()) {
1478 std::optional<Color> maybe_color = entity.AsBackgroundColor(
1479 render_passes_.back().inline_pass_context->GetTexture()->GetSize());
1480 if (maybe_color.has_value()) {
1481 Color color = maybe_color.value();
1482 RenderTarget& render_target = render_passes_.back()
1483 .inline_pass_context->GetPassTarget()
1485 ColorAttachment attachment = render_target.GetColorAttachment(0);
1488 attachment.clear_color = attachment.clear_color.Unpremultiply()
1489 .Blend(color, entity.GetBlendMode())
1491 render_target.SetColorAttachment(attachment, 0u);
1502 FML_DCHECK(current_depth_ <= transform_stack_.back().clip_depth)
1503 << current_depth_ <<
" <=? " << transform_stack_.back().clip_depth;
1504 entity.SetClipDepth(current_depth_);
1506 if (entity.GetBlendMode() > Entity::kLastPipelineBlendMode) {
1507 if (renderer_.GetDeviceCapabilities().SupportsFramebufferFetch()) {
1508 ApplyFramebufferBlend(entity);
1519 auto input_texture = FlipBackdrop(GetGlobalPassPosition());
1520 if (!input_texture) {
1528 auto element_coverage_hint = entity.GetContents()->GetCoverageHint();
1529 entity.GetContents()->SetCoverageHint(Rect::Intersection(
1530 element_coverage_hint, clip_coverage_stack_.CurrentClipCoverage()));
1532 FilterInput::Vector inputs = {
1533 FilterInput::Make(input_texture, entity.GetTransform().Invert()),
1534 FilterInput::Make(entity.GetContents())};
1536 ColorFilterContents::MakeBlend(entity.GetBlendMode(), inputs);
1537 entity.SetContents(std::move(contents));
1538 entity.SetBlendMode(BlendMode::kSource);
1542 const std::shared_ptr<RenderPass>& result =
1543 render_passes_.back().inline_pass_context->GetRenderPass();
1551 entity.Render(renderer_, *result);
1554 RenderPass& Canvas::GetCurrentRenderPass()
const {
1555 return *render_passes_.back().inline_pass_context->GetRenderPass();
1558 void Canvas::SetBackdropData(
1559 std::unordered_map<int64_t, BackdropData> backdrop_data,
1560 size_t backdrop_count) {
1561 backdrop_data_ = std::move(backdrop_data);
1562 backdrop_count_ = backdrop_count;
1565 std::shared_ptr<Texture> Canvas::FlipBackdrop(
Point global_pass_position,
1566 bool should_remove_texture,
1567 bool should_use_onscreen) {
1569 render_passes_.pop_back();
1585 <<
"Failed to end the current render pass in order to read from "
1586 "the backdrop texture and apply an advanced blend or backdrop "
1597 const std::shared_ptr<Texture>& input_texture =
1600 if (!input_texture) {
1601 VALIDATION_LOG <<
"Failed to fetch the color texture in order to "
1602 "apply an advanced blend or backdrop filter.";
1605 render_passes_.push_back(LazyRenderingConfig(
1611 if (should_use_onscreen) {
1612 ColorAttachment color0 = render_target_.GetColorAttachment(0);
1616 color0.
load_action = color0.resolve_texture !=
nullptr
1617 ? LoadAction::kDontCare
1618 : LoadAction::kLoad;
1619 render_target_.SetColorAttachment(color0, 0);
1621 auto entity_pass_target = std::make_unique<EntityPassTarget>(
1623 renderer_.GetDeviceCapabilities().SupportsReadFromResolve(),
1624 renderer_.GetDeviceCapabilities().SupportsImplicitResolvingMSAA()
1626 render_passes_.push_back(
1627 LazyRenderingConfig(renderer_, std::move(entity_pass_target)));
1628 requires_readback_ =
false;
1630 render_passes_.push_back(LazyRenderingConfig(
1635 if (should_remove_texture) {
1636 render_passes_.back().entity_pass_target->RemoveSecondary();
1639 RenderPass& current_render_pass =
1640 *render_passes_.back().inline_pass_context->GetRenderPass();
1649 Rect size_rect = Rect::MakeSize(input_texture->GetSize());
1650 auto msaa_backdrop_contents = TextureContents::MakeRect(size_rect);
1651 msaa_backdrop_contents->SetStencilEnabled(
false);
1652 msaa_backdrop_contents->SetLabel(
"MSAA backdrop");
1653 msaa_backdrop_contents->SetSourceRect(size_rect);
1654 msaa_backdrop_contents->SetTexture(input_texture);
1656 Entity msaa_backdrop_entity;
1657 msaa_backdrop_entity.SetContents(std::move(msaa_backdrop_contents));
1658 msaa_backdrop_entity.SetBlendMode(BlendMode::kSource);
1659 msaa_backdrop_entity.SetClipDepth(std::numeric_limits<uint32_t>::max());
1660 if (!msaa_backdrop_entity.Render(renderer_, current_render_pass)) {
1667 auto& replay_entities = clip_coverage_stack_.GetReplayEntities();
1668 for (
const auto& replay : replay_entities) {
1669 if (replay.clip_depth <= current_depth_) {
1673 SetClipScissor(replay.clip_coverage, current_render_pass,
1674 global_pass_position);
1675 if (!replay.clip_contents.Render(renderer_, current_render_pass,
1676 replay.clip_depth)) {
1681 return input_texture;
1684 bool Canvas::SupportsBlitToOnscreen()
const {
1685 return renderer_.GetContext()
1687 ->SupportsTextureToTextureBlits() &&
1688 renderer_.GetContext()->GetBackendType() !=
1689 Context::BackendType::kOpenGLES;
1692 bool Canvas::BlitToOnscreen(
bool is_onscreen) {
1693 auto command_buffer = renderer_.GetContext()->CreateCommandBuffer();
1694 command_buffer->SetLabel(
"EntityPass Root Command Buffer");
1695 auto offscreen_target = render_passes_.back()
1696 .inline_pass_context->GetPassTarget()
1699 if (SupportsBlitToOnscreen()) {
1700 auto blit_pass = command_buffer->CreateBlitPass();
1701 blit_pass->AddCopy(offscreen_target.GetRenderTargetTexture(),
1702 render_target_.GetRenderTargetTexture());
1703 if (!blit_pass->EncodeCommands()) {
1708 auto render_pass = command_buffer->CreateRenderPass(render_target_);
1709 render_pass->SetLabel(
"EntityPass Root Render Pass");
1712 auto size_rect = Rect::MakeSize(offscreen_target.GetRenderTargetSize());
1713 auto contents = TextureContents::MakeRect(size_rect);
1714 contents->SetTexture(offscreen_target.GetRenderTargetTexture());
1715 contents->SetSourceRect(size_rect);
1716 contents->SetLabel(
"Root pass blit");
1719 entity.SetContents(contents);
1720 entity.SetBlendMode(BlendMode::kSource);
1722 if (!entity.Render(renderer_, *render_pass)) {
1728 if (!render_pass->EncodeCommands()) {
1735 return renderer_.GetContext()->SubmitOnscreen(std::move(command_buffer));
1737 return renderer_.GetContext()->EnqueueCommandBuffer(
1738 std::move(command_buffer));
1742 void Canvas::EndReplay() {
1743 FML_DCHECK(render_passes_.size() == 1u);
1744 render_passes_.back().inline_pass_context->GetRenderPass();
1745 render_passes_.back().inline_pass_context->EndPass(
1746 !requires_readback_ && is_onscreen_);
1747 backdrop_data_.clear();
1752 if (requires_readback_) {
1753 BlitToOnscreen(is_onscreen_);
1756 if (!renderer_.GetContext()->FlushCommandBuffers()) {
1760 render_passes_.clear();
1761 renderer_.GetRenderTargetCache()->End();
1762 clip_geometry_.clear();
1765 Initialize(initial_cull_rect_);
void ClipGeometry(const Geometry &geometry, Entity::ClipOperation clip_op, bool is_aa=true)
static constexpr uint32_t kMaxDepth
Canvas(ContentContext &renderer, const RenderTarget &render_target, bool is_onscreen, bool requires_readback)
std::optional< Rect > GetLocalCoverageLimit() const
Return the culling bounds of the current render target, or nullopt if there is no coverage.
void SaveLayer(const Paint &paint, std::optional< Rect > bounds=std::nullopt, const flutter::DlImageFilter *backdrop_filter=nullptr, ContentBoundsPromise bounds_promise=ContentBoundsPromise::kUnknown, uint32_t total_content_depth=kMaxDepth, bool can_distribute_opacity=false, std::optional< int64_t > backdrop_id=std::nullopt)
const Matrix & GetCurrentTransform() const
void DrawVertices(const std::shared_ptr< VerticesGeometry > &vertices, BlendMode blend_mode, const Paint &paint)
void DrawOval(const Rect &rect, const Paint &paint)
void DrawImageRect(const std::shared_ptr< Texture > &image, Rect source, Rect dest, const Paint &paint, const SamplerDescriptor &sampler={}, SourceRectConstraint src_rect_constraint=SourceRectConstraint::kFast)
void RestoreToCount(size_t count)
size_t GetSaveCount() const
void Concat(const Matrix &transform)
void Transform(const Matrix &transform)
std::function< std::shared_ptr< FilterContents >(FilterInput::Ref, const Matrix &effect_transform, Entity::RenderingMode rendering_mode)> BackdropFilterProc
void PreConcat(const Matrix &transform)
void Rotate(Radians radians)
void DrawPoints(const Point points[], uint32_t count, Scalar radius, const Paint &paint, PointStyle point_style)
void DrawTextFrame(const std::shared_ptr< TextFrame > &text_frame, Point position, const Paint &paint)
void DrawImage(const std::shared_ptr< Texture > &image, Point offset, const Paint &paint, const SamplerDescriptor &sampler={})
void DrawPaint(const Paint &paint)
void DrawRoundRect(const RoundRect &rect, const Paint &paint)
void Skew(Scalar sx, Scalar sy)
void Scale(const Vector2 &scale)
void DrawPath(const Path &path, const Paint &paint)
void Save(uint32_t total_content_depth=kMaxDepth)
void DrawRect(const Rect &rect, const Paint &paint)
void DrawAtlas(const std::shared_ptr< AtlasContents > &atlas_contents, const Paint &paint)
void DrawLine(const Point &p0, const Point &p1, const Paint &paint, bool reuse_depth=false)
void Translate(const Vector3 &offset)
void DrawCircle(const Point ¢er, Scalar radius, const Paint &paint)
virtual bool SupportsImplicitResolvingMSAA() const =0
Whether the context backend supports multisampled rendering to the on-screen surface without requirin...
virtual bool SupportsFramebufferFetch() const =0
Whether the context backend is able to support pipelines with shaders that read from the framebuffer ...
virtual bool SupportsReadFromResolve() const =0
Whether the context backend supports binding the current RenderPass attachments. This is supported if...
void SetGeometry(GeometryResult geometry)
Set the pre-tessellated clip geometry.
void SetClipOperation(Entity::ClipOperation clip_op)
bool Render(const ContentContext &renderer, RenderPass &pass, uint32_t clip_depth) const
static std::shared_ptr< ColorFilterContents > MakeBlend(BlendMode blend_mode, FilterInput::Vector inputs, std::optional< Color > foreground_color=std::nullopt)
the [inputs] are expected to be in the order of dst, src.
const Capabilities & GetDeviceCapabilities() const
const std::shared_ptr< RenderTargetAllocator > & GetRenderTargetCache() const
std::shared_ptr< Context > GetContext() const
A geometry that implements "drawPaint" like behavior by covering the entire render pass area.
void SetTransform(const Matrix &transform)
Set the global transform matrix for this Entity.
std::optional< Rect > GetCoverage() const
@ kSubpassPrependSnapshotTransform
@ kSubpassAppendSnapshotTransform
const std::shared_ptr< Contents > & GetContents() const
void SetClipDepth(uint32_t clip_depth)
BlendMode GetBlendMode() const
void SetContents(std::shared_ptr< Contents > contents)
void SetBlendMode(BlendMode blend_mode)
bool Render(const ContentContext &renderer, RenderPass &parent_pass) const
const Matrix & GetTransform() const
Get the global transform matrix for this Entity.
static constexpr BlendMode kLastPipelineBlendMode
static bool IsBlendModeDestructive(BlendMode blend_mode)
Returns true if the blend mode is "destructive", meaning that even fully transparent source colors wo...
A class that tracks all clips that have been recorded in the current entity pass stencil.
std::optional< Rect > CurrentClipCoverage() const
void PushSubpass(std::optional< Rect > subpass_coverage, size_t clip_height)
ReplayResult & GetLastReplayResult()
ClipStateResult RecordClip(const ClipContents &clip_contents, Matrix transform, Point global_pass_position, uint32_t clip_depth, size_t clip_height_floor, bool is_aa)
ClipStateResult RecordRestore(Point global_pass_position, size_t restore_height)
A geometry that is created from a filled path object.
@ kNormal
Blurred inside and outside.
@ kOuter
Nothing inside, blurred outside.
@ kInner
Blurred inside, nothing outside.
@ kSolid
Solid inside, blurred outside.
static std::unique_ptr< Geometry > MakeRect(const Rect &rect)
virtual GeometryResult GetPositionBuffer(const ContentContext &renderer, const Entity &entity, RenderPass &pass) const =0
virtual bool CanApplyMaskFilter() const
virtual std::optional< Rect > GetCoverage(const Matrix &transform) const =0
virtual bool IsAxisAlignedRect() const
PathBuilder & AddRect(Rect rect)
Path TakePath(FillType fill=FillType::kNonZero)
PathBuilder & AddRoundRect(RoundRect rect)
PathBuilder & SetBounds(Rect bounds)
Set the bounding box that will be used by Path.GetBoundingBox in place of performing the computation.
PathBuilder & AddOval(const Rect &rect)
PathBuilder & SetConvexity(Convexity value)
Paths are lightweight objects that describe a collection of linear, quadratic, or cubic segments....
A geometry class specialized for Canvas::DrawPoints.
ColorAttachment GetColorAttachment(size_t index) const
Get the color attachment at [index].
RenderTarget & SetColorAttachment(const ColorAttachment &attachment, size_t index)
ISize GetRenderTargetSize() const
const std::optional< DepthAttachment > & GetDepthAttachment() const
const std::optional< StencilAttachment > & GetStencilAttachment() const
void SetupDepthStencilAttachments(const Context &context, Allocator &allocator, ISize size, bool msaa, std::string_view label="Offscreen", RenderTarget::AttachmentConfig stencil_attachment_config=RenderTarget::kDefaultStencilAttachmentConfig, const std::shared_ptr< Texture > &depth_stencil_texture=nullptr)
A geometry that is created from a stroked path object.
static std::shared_ptr< TextureContents > MakeRect(Rect destination)
A common case factory that marks the texture contents as having a destination rectangle....
ISize subpass_size
The output size of the down-sampling pass.
impeller::SamplerDescriptor ToSamplerDescriptor(const flutter::DlImageSampling options)
std::shared_ptr< ColorFilterContents > WrapWithGPUColorFilter(const flutter::DlColorFilter *filter, const std::shared_ptr< FilterInput > &input, ColorFilterContents::AbsorbOpacity absorb_opacity)
SourceRectConstraint
Controls the behavior of the source rectangle given to DrawImageRect.
@ kStrict
Sample only within the source rectangle. May be slower.
std::shared_ptr< FilterContents > WrapInput(const flutter::DlImageFilter *filter, const FilterInput::Ref &input)
Generate a new FilterContents using this filter's configuration.
constexpr float kEhCloseEnough
std::shared_ptr< ColorFilterContents > WrapWithInvertColors(const std::shared_ptr< FilterInput > &input, ColorFilterContents::AbsorbOpacity absorb_opacity)
@ kRound
Points are drawn as squares.
ColorFilterProc GetCPUColorFilterProc(const flutter::DlColorFilter *filter)
@ kMayClipContents
The caller claims the bounds are a subset of an estimate of the reasonably tight bounds but likely cl...
@ kContainsContents
The caller claims the bounds are a reasonably tight estimate of the coverage of the contents and shou...
static constexpr const ColorMatrix kColorInversion
A color matrix which inverts colors.
std::optional< Rect > ComputeSaveLayerCoverage(const Rect &content_coverage, const Matrix &effect_transform, const Rect &coverage_limit, const std::shared_ptr< FilterContents > &image_filter, bool flood_output_coverage, bool flood_input_coverage)
Compute the coverage of a subpass in the global coordinate space.
std::shared_ptr< Texture > texture
std::shared_ptr< Texture > texture_slot
std::optional< Snapshot > shared_filter_snapshot
Entity::RenderingMode rendering_mode
static constexpr Color BlackTransparent()
static constexpr Color White()
constexpr Color WithAlpha(Scalar new_alpha) const
Color ApplyColorMatrix(const ColorMatrix &color_matrix) const
A color filter that transforms colors through a 4x5 color matrix.
ClipContents clip_contents
std::unique_ptr< InlinePassContext > inline_pass_context
std::unique_ptr< EntityPassTarget > entity_pass_target
A 4x4 matrix using column-major storage.
static constexpr Matrix MakeTranslation(const Vector3 &t)
static constexpr Matrix MakeSkew(Scalar sx, Scalar sy)
static constexpr Matrix MakeTranslateScale(const Vector3 &s, const Vector3 &t)
static Matrix MakeRotationZ(Radians r)
static constexpr Matrix MakeScale(const Vector3 &s)
std::shared_ptr< Contents > WithFilters(std::shared_ptr< Contents > input) const
Wrap this paint's configured filters to the given contents.
const flutter::DlColorFilter * color_filter
const flutter::DlColorSource * color_source
const flutter::DlImageFilter * image_filter
std::shared_ptr< Contents > WithMaskBlur(std::shared_ptr< Contents > input, bool is_solid_color, const Matrix &ctm) const
static bool CanApplyOpacityPeephole(const Paint &paint)
Whether or not a save layer with the provided paint can perform the opacity peephole optimization.
std::optional< MaskBlurDescriptor > mask_blur_descriptor
std::shared_ptr< FilterContents > WithImageFilter(const FilterInput::Variant &input, const Matrix &effect_transform, Entity::RenderingMode rendering_mode) const
std::shared_ptr< ColorSourceContents > CreateContents() const
bool HasColorFilter() const
Whether this paint has a color filter that can apply opacity.
constexpr const RoundingRadii & GetRadii() const
constexpr const Rect & GetBounds() const
Represents a texture and its intended draw transform/sampler configuration.
Matrix transform
The transform that should be applied to this texture for rendering.
std::shared_ptr< Texture > texture
SamplerDescriptor sampler_descriptor
constexpr TRect< T > Expand(T left, T top, T right, T bottom) const
Returns a rectangle with expanded edges. Negative expansion results in shrinking.
constexpr auto GetBottom() const
constexpr TRect TransformBounds(const Matrix &transform) const
Creates a new bounding box that contains this transformed rectangle.
constexpr auto GetTop() const
constexpr Type GetHeight() const
Returns the height of the rectangle, equivalent to |GetSize().height|.
constexpr TPoint< Type > GetOrigin() const
Returns the upper left corner of the rectangle as specified by the left/top or x/y values when it was...
constexpr std::optional< TRect > Intersection(const TRect &o) const
constexpr bool IsEmpty() const
Returns true if either of the width or height are 0, negative, or NaN.
constexpr static TRect MakeOriginSize(const TPoint< Type > &origin, const TSize< Type > &size)
constexpr auto GetLeft() const
constexpr TSize< Type > GetSize() const
Returns the size of the rectangle which may be negative in either width or height and may have been c...
Round(const TRect< U > &r)
RoundOut(const TRect< U > &r)
constexpr auto GetRight() const
constexpr bool IsSquare() const
Returns true if width and height are equal and neither is NaN.
constexpr static TRect MakeXYWH(Type x, Type y, Type width, Type height)
constexpr TRect< T > Shift(T dx, T dy) const
Returns a new rectangle translated by the given offset.
constexpr static TRect MakeSize(const TSize< U > &size)
constexpr Type GetWidth() const
Returns the width of the rectangle, equivalent to |GetSize().width|.
constexpr Point GetCenter() const
Get the center point as a |Point|.
constexpr static TRect MakeLTRB(Type left, Type top, Type right, Type bottom)
constexpr static TRect MakeMaximum()