9 #include <unordered_map>
12 #include "display_list/dl_vertices.h"
13 #include "display_list/effects/color_filters/dl_blend_color_filter.h"
14 #include "display_list/effects/color_filters/dl_matrix_color_filter.h"
15 #include "display_list/effects/dl_color_filter.h"
16 #include "display_list/effects/dl_color_source.h"
17 #include "display_list/effects/dl_image_filter.h"
18 #include "display_list/image/dl_image.h"
19 #include "flutter/fml/logging.h"
20 #include "flutter/fml/trace_event.h"
65 constexpr
Scalar kAntialiasPadding = 1.0f;
67 bool IsPipelineBlendOrMatrixFilter(
const flutter::DlColorFilter* filter) {
68 return filter->type() == flutter::DlColorFilterType::kMatrix ||
69 (filter->type() == flutter::DlColorFilterType::kBlend &&
73 static bool UseColorSourceContents(
74 const std::shared_ptr<VerticesGeometry>& vertices,
78 if (vertices->HasVertexColors()) {
81 if (vertices->HasTextureCoordinates() && !paint.color_source) {
84 return !vertices->HasTextureCoordinates();
87 static void SetClipScissor(std::optional<Rect> clip_coverage,
89 Point global_pass_position) {
93 if (clip_coverage.has_value()) {
94 clip_coverage = clip_coverage->Shift(-global_pass_position);
101 pass.SetScissor(scissor);
104 static void ApplyFramebufferBlend(Entity& entity) {
105 auto src_contents = entity.GetContents();
106 auto contents = std::make_shared<FramebufferBlendContents>();
107 contents->SetChildContents(src_contents);
108 contents->SetBlendMode(entity.GetBlendMode());
109 entity.SetContents(std::move(contents));
115 static std::shared_ptr<Contents> CreateContentsForSubpassTarget(
117 const std::shared_ptr<Texture>& target,
118 const Matrix& effect_transform) {
120 contents->SetTexture(target);
121 contents->SetLabel(
"Subpass");
123 contents->SetOpacity(paint.color.alpha);
124 contents->SetDeferApplyingOpacity(
true);
126 return paint.WithFiltersForSubpassTarget(std::move(contents),
130 static const constexpr RenderTarget::AttachmentConfig kDefaultStencilConfig =
131 RenderTarget::AttachmentConfig{
137 static std::unique_ptr<EntityPassTarget> CreateRenderTarget(
138 ContentContext& renderer,
140 const Color& clear_color) {
141 const std::shared_ptr<Context>& context = renderer.GetContext();
149 if (context->GetCapabilities()->SupportsOffscreenMSAA()) {
150 target = renderer.GetRenderTargetCache()->CreateOffscreenMSAA(
156 RenderTarget::AttachmentConfigMSAA{
161 .clear_color = clear_color},
162 kDefaultStencilConfig);
164 target = renderer.GetRenderTargetCache()->CreateOffscreen(
169 RenderTarget::AttachmentConfig{
173 .clear_color = clear_color,
175 kDefaultStencilConfig
179 return std::make_unique<EntityPassTarget>(
181 renderer.GetDeviceCapabilities().SupportsReadFromResolve(),
182 renderer.GetDeviceCapabilities().SupportsImplicitResolvingMSAA()
191 : rect_(rect), corner_radius_(corner_radius) {}
196 auto contents = std::make_shared<SolidRRectBlurContents>();
197 contents->SetSigma(sigma);
198 contents->SetShape(rect_, corner_radius_);
203 return geom_.emplace(rect_,
Size(corner_radius_));
208 const Scalar corner_radius_;
210 std::optional<RoundRectGeometry> geom_;
216 : rect_(rect), corner_radius_(corner_radius) {}
221 auto contents = std::make_shared<SolidRSuperellipseBlurContents>();
222 contents->SetSigma(sigma);
223 contents->SetShape(rect_, corner_radius_);
228 return geom_.emplace(rect_, corner_radius_);
233 const Scalar corner_radius_;
235 std::optional<RoundSuperellipseGeometry> geom_;
255 std::shared_ptr<ShadowVertices> shadow_vertices,
259 shadow_vertices_(
std::move(shadow_vertices)) {}
262 return shadow_vertices_->GetBounds().value_or(
Rect());
276 return source_geometry_.emplace(source_);
282 const std::shared_ptr<ShadowVertices> shadow_vertices_;
285 std::optional<FillPathFromSourceGeometry> source_geometry_;
291 bool requires_readback)
292 : renderer_(renderer),
293 render_target_(render_target),
294 is_onscreen_(is_onscreen),
295 requires_readback_(requires_readback),
297 Rect::MakeSize(render_target.GetRenderTargetSize()))) {
298 Initialize(std::nullopt);
305 bool requires_readback,
307 : renderer_(renderer),
308 render_target_(render_target),
309 is_onscreen_(is_onscreen),
310 requires_readback_(requires_readback),
312 Rect::MakeSize(render_target.GetRenderTargetSize()))) {
313 Initialize(cull_rect);
320 bool requires_readback,
322 : renderer_(renderer),
323 render_target_(render_target),
324 is_onscreen_(is_onscreen),
325 requires_readback_(requires_readback),
327 Rect::MakeSize(render_target.GetRenderTargetSize()))) {
333 void Canvas::Initialize(std::optional<Rect> cull_rect) {
334 initial_cull_rect_ = cull_rect;
341 void Canvas::Reset() {
343 transform_stack_ = {};
355 transform_stack_.back().transform = {};
363 return transform_stack_.back().transform;
386 Point Canvas::GetGlobalPassPosition()
const {
387 if (save_layer_state_.empty()) {
390 return save_layer_state_.back().coverage.GetOrigin();
394 size_t Canvas::GetClipHeightFloor()
const {
395 if (transform_stack_.size() > 1) {
396 return transform_stack_[transform_stack_.size() - 2].clip_height;
402 return transform_stack_.size();
405 bool Canvas::IsSkipping()
const {
406 return transform_stack_.back().skipping;
418 if (IsShadowBlurDrawOperation(paint)) {
419 if (AttemptDrawBlurredPathSource(path, paint)) {
430 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
433 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
443 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
450 bool Canvas::AttemptColorFilterOptimization(
451 const std::shared_ptr<Texture>& image,
465 if (paint.
color_filter->type() == flutter::DlColorFilterType::kBlend) {
466 const flutter::DlBlendColorFilter* blend_filter =
468 DrawImageRectAtlasGeometry geometry = DrawImageRectAtlasGeometry(
473 blend_filter->mode(),
475 src_rect_constraint ==
478 auto atlas_contents = std::make_shared<AtlasContents>();
479 atlas_contents->SetGeometry(&geometry);
485 entity.SetContents(atlas_contents);
487 AddRenderEntityToCurrentPass(entity);
495 const flutter::DlMatrixColorFilter* matrix_filter =
498 DrawImageRectAtlasGeometry geometry = DrawImageRectAtlasGeometry(
505 src_rect_constraint ==
508 auto atlas_contents = std::make_shared<ColorFilterAtlasContents>();
509 atlas_contents->SetGeometry(&geometry);
512 matrix_filter->get_matrix(color_matrix.
array);
513 atlas_contents->SetMatrix(color_matrix);
518 entity.SetContents(atlas_contents);
520 AddRenderEntityToCurrentPass(entity);
525 bool Canvas::AttemptDrawAntialiasedCircle(
const Point& center,
527 const Paint& paint) {
528 if (paint.HasColorFilter() || paint.image_filter || paint.invert_colors ||
529 paint.color_source || paint.mask_blur_descriptor.has_value()) {
535 entity.SetBlendMode(paint.blend_mode);
538 std::unique_ptr<CircleGeometry> geom;
540 geom = std::make_unique<CircleGeometry>(center, radius, paint.stroke.width);
542 geom = std::make_unique<CircleGeometry>(center, radius);
544 geom->SetAntialiasPadding(kAntialiasPadding);
548 entity.SetContents(std::move(contents));
549 AddRenderEntityToCurrentPass(entity);
554 bool Canvas::IsShadowBlurDrawOperation(
const Paint& paint) {
559 if (paint.color_source) {
563 if (!paint.mask_blur_descriptor.has_value()) {
574 Radius radius = paint.mask_blur_descriptor->sigma;
582 bool Canvas::AttemptDrawBlurredPathSource(
const PathSource& source,
583 const Paint& paint) {
584 FML_DCHECK(IsShadowBlurDrawOperation);
590 if (paint.mask_blur_descriptor.has_value()) {
594 static constexpr
Scalar kSigmaScale = 2.8f;
596 Sigma sigma = paint.mask_blur_descriptor->sigma;
598 Scalar basis_scale = matrix.GetMaxBasisLengthXY();
599 Scalar device_radius = sigma.sigma * kSigmaScale * basis_scale;
600 std::shared_ptr<ShadowVertices> shadow_vertices =
603 if (shadow_vertices) {
604 PathBlurShape shape(source, std::move(shadow_vertices), sigma);
605 return AttemptDrawBlur(shape, paint);
611 Scalar Canvas::GetCommonRRectLikeRadius(
const RoundingRadii& radii) {
612 if (!radii.AreAllCornersSame()) {
615 const Size& corner_radii = radii.top_left;
617 return corner_radii.
width;
622 bool Canvas::AttemptDrawBlurredRRect(
const RoundRect& round_rect,
623 const Paint& paint) {
624 Scalar radius = GetCommonRRectLikeRadius(round_rect.GetRadii());
626 RoundRectPathSource source(round_rect);
627 return AttemptDrawBlurredPathSource(source, paint);
629 RRectBlurShape shape(round_rect.GetBounds(), radius);
630 return AttemptDrawBlur(shape, paint);
633 bool Canvas::AttemptDrawBlurredRSuperellipse(
const RoundSuperellipse& rse,
634 const Paint& paint) {
635 Scalar radius = GetCommonRRectLikeRadius(rse.GetRadii());
637 RoundSuperellipsePathSource source(rse);
638 return AttemptDrawBlurredPathSource(source, paint);
640 RSuperellipseBlurShape shape(rse.GetBounds(), radius);
641 return AttemptDrawBlur(shape, paint);
644 bool Canvas::AttemptDrawBlur(BlurShape& shape,
const Paint& paint) {
645 FML_DCHECK(IsShadowBlurDrawOperation(paint));
649 Color rrect_color = paint.color;
650 if (paint.invert_colors) {
653 if (paint.color_filter) {
657 Paint rrect_paint = {.mask_blur_descriptor = paint.mask_blur_descriptor};
659 if (!rrect_paint.mask_blur_descriptor.has_value()) {
686 if ((paint.mask_blur_descriptor->style !=
688 paint.image_filter) ||
691 Rect render_bounds = shape.GetBounds();
692 if (paint.mask_blur_descriptor->style !=
695 render_bounds.
Expand(paint.mask_blur_descriptor->sigma.sigma * 4.0);
701 .image_filter = paint.image_filter,
702 .blend_mode = paint.blend_mode,
705 rrect_paint.color = rrect_color.WithAlpha(1);
707 rrect_paint.color = rrect_color;
708 rrect_paint.blend_mode = paint.blend_mode;
709 rrect_paint.image_filter = paint.image_filter;
713 auto draw_blurred_rrect = [
this, &rrect_paint, &shape]() {
714 std::shared_ptr<SolidBlurContents> contents =
715 shape.BuildBlurContent(rrect_paint.mask_blur_descriptor->sigma);
716 FML_DCHECK(contents);
718 contents->SetColor(rrect_paint.color);
720 Entity blurred_rrect_entity;
722 blurred_rrect_entity.SetBlendMode(rrect_paint.blend_mode);
724 rrect_paint.mask_blur_descriptor = std::nullopt;
725 blurred_rrect_entity.SetContents(
726 rrect_paint.WithFilters(std::move(contents)));
727 AddRenderEntityToCurrentPass(blurred_rrect_entity);
730 switch (rrect_paint.mask_blur_descriptor->style) {
732 draw_blurred_rrect();
737 draw_blurred_rrect();
741 entity.SetBlendMode(rrect_paint.blend_mode);
743 const Geometry& geom = shape.BuildDrawGeometry();
744 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, rrect_paint,
749 const Geometry& geom = shape.BuildDrawGeometry();
751 draw_blurred_rrect();
755 const Geometry& geom = shape.BuildDrawGeometry();
757 draw_blurred_rrect();
775 auto geometry = std::make_unique<LineGeometry>(p0,
p1, paint.
stroke);
777 if ((renderer_.
GetContext()->GetFlags().antialiased_lines ||
778 renderer_.
GetContext()->GetFlags().use_sdfs) &&
783 AddRenderEntityToCurrentPass(entity, reuse_depth);
785 AddRenderEntityWithFiltersToCurrentPass(entity, geometry.get(), paint,
794 const Paint& paint) {
804 if (length > 0.0f && on_length >= 0.0f && off_length > 0.0f) {
810 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
817 if (IsShadowBlurDrawOperation(paint)) {
819 if (AttemptDrawBlur(shape, paint)) {
828 if (renderer_.
GetContext()->GetFlags().use_sdfs &&
830 Scalar expand_size = kAntialiasPadding;
844 const Geometry* geom = contents->GetGeometry();
846 AddRenderSDFEntityToCurrentPass(entity, geom, paint, std::move(contents));
852 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
855 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
871 if (IsShadowBlurDrawOperation(paint)) {
876 if (AttemptDrawBlur(shape, paint)) {
881 if (AttemptDrawBlurredPathSource(source, paint)) {
893 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
896 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
907 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
920 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
933 return DrawOval(oval_bounds, paint);
943 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
949 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
953 if (IsShadowBlurDrawOperation(paint)) {
954 if (AttemptDrawBlurredRRect(round_rect, paint)) {
967 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
977 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
980 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
986 const Paint& paint) {
993 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
996 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
1001 const Paint& paint) {
1002 if (IsShadowBlurDrawOperation(paint)) {
1003 if (AttemptDrawBlurredRSuperellipse(round_superellipse, paint)) {
1015 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
1018 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
1024 const Paint& paint) {
1025 if (IsShadowBlurDrawOperation(paint)) {
1027 center.
x + radius, center.
y + radius);
1029 if (AttemptDrawBlur(shape, paint)) {
1034 if (renderer_.
GetContext()->GetFlags().use_sdfs &&
1038 std::optional<CircleGeometry> geometry;
1040 geometry.emplace(center, radius, paint.
stroke.
width);
1042 geometry.emplace(center, radius);
1044 geometry->SetAntialiasPadding(1.0f);
1047 paint.
color, is_stroked, &geometry.value());
1053 const Geometry* geom = contents->GetGeometry();
1055 AddRenderSDFEntityToCurrentPass(entity, geom, paint, std::move(contents));
1059 if (AttemptDrawAntialiasedCircle(center, radius, paint)) {
1069 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
1072 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
1093 FML_DCHECK(current_depth_ <= transform_stack_.back().clip_depth)
1094 << current_depth_ <<
" <=? " << transform_stack_.back().clip_depth;
1095 uint32_t clip_depth = transform_stack_.back().clip_depth;
1097 const Matrix clip_transform =
1101 std::optional<Rect> clip_coverage = geometry.
GetCoverage(clip_transform);
1102 if (!clip_coverage.has_value()) {
1107 clip_coverage.value(),
1116 GetGlobalPassPosition(),
1118 GetClipHeightFloor(),
1125 *render_passes_.back().GetInlinePassContext()->GetRenderPass(),
1126 GetGlobalPassPosition());
1129 ++transform_stack_.back().clip_height;
1130 ++transform_stack_.back().num_clips;
1147 *render_passes_.back().GetInlinePassContext()->GetRenderPass()
1154 renderer_, *render_passes_.back().GetInlinePassContext()->GetRenderPass(),
1173 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
1200 ISize size = image->GetSize();
1205 std::optional<Rect> clipped_source =
1207 if (!clipped_source) {
1211 if (AttemptColorFilterOptimization(image, source, dest, paint, sampler,
1212 src_rect_constraint)) {
1216 if (*clipped_source != source) {
1226 texture_contents->SetTexture(image);
1227 texture_contents->SetSourceRect(*clipped_source);
1228 texture_contents->SetStrictSourceRect(src_rect_constraint ==
1230 texture_contents->SetSamplerDescriptor(sampler);
1231 texture_contents->SetOpacity(paint.
color.
alpha);
1232 texture_contents->SetDeferApplyingOpacity(paint.
HasColorFilter());
1240 AddRenderEntityToCurrentPass(entity);
1248 AddRenderEntityToCurrentPass(entity);
1251 size_t Canvas::GetClipHeight()
const {
1252 return transform_stack_.back().clip_height;
1257 const Paint& paint) {
1270 if (UseColorSourceContents(vertices, paint)) {
1271 AddRenderEntityWithFiltersToCurrentPass(entity, vertices.get(), paint);
1277 auto contents = std::make_shared<VerticesSimpleBlendContents>();
1278 contents->SetBlendMode(blend_mode);
1280 contents->SetGeometry(vertices);
1282 AddRenderEntityToCurrentPass(entity);
1289 paint.
color_source->type() == flutter::DlColorSourceType::kImage) {
1290 const flutter::DlImageColorSource* image_color_source =
1292 FML_DCHECK(image_color_source &&
1293 image_color_source->image()->impeller_texture());
1294 auto texture = image_color_source->image()->impeller_texture();
1296 image_color_source->horizontal_tile_mode());
1299 auto sampler_descriptor =
1301 auto effect_transform = image_color_source->matrix();
1303 auto contents = std::make_shared<VerticesSimpleBlendContents>();
1304 contents->SetBlendMode(blend_mode);
1306 contents->SetGeometry(vertices);
1307 contents->SetEffectTransform(effect_transform);
1308 contents->SetTexture(texture);
1309 contents->SetTileMode(x_tile_mode, y_tile_mode);
1310 contents->SetSamplerDescriptor(sampler_descriptor);
1313 AddRenderEntityToCurrentPass(entity);
1317 auto src_paint = paint;
1320 std::shared_ptr<ColorSourceContents> src_contents =
1321 src_paint.CreateContents(vertices.get());
1329 auto size = src_contents->GetColorSourceSize();
1330 if (size.has_value()) {
1333 auto cvg = vertices->GetCoverage(
Matrix{});
1334 FML_CHECK(cvg.has_value());
1335 auto texture_coverage = vertices->GetTextureCoordinateCoverage();
1336 if (texture_coverage.has_value()) {
1339 texture_coverage->GetSize().Max({1, 1}));
1342 src_coverage = cvg.value();
1346 src_contents = src_paint.CreateContents(clip_geometry_.back().get());
1348 auto contents = std::make_shared<VerticesSimpleBlendContents>();
1349 contents->SetBlendMode(blend_mode);
1351 contents->SetGeometry(vertices);
1352 contents->SetLazyTextureCoverage(src_coverage);
1353 contents->SetLazyTexture(
1354 [src_contents, src_coverage](
1359 auto snapshot = src_contents->RenderToSnapshot(
1360 renderer, {}, {.coverage_limit =
Rect::Round(src_coverage)});
1361 return snapshot.has_value() ? snapshot->texture :
nullptr;
1364 AddRenderEntityToCurrentPass(entity);
1368 const Paint& paint) {
1376 AddRenderEntityToCurrentPass(entity);
1382 void Canvas::SetupRenderPass() {
1388 if (!stencil_attachment.has_value() || !depth_attachment.has_value()) {
1393 *renderer_.
GetContext()->GetResourceAllocator(),
1395 renderer_.
GetContext()->GetCapabilities()->SupportsOffscreenMSAA() &&
1396 color0.
texture->GetTextureDescriptor().sample_count >
1398 "ImpellerOnscreen", kDefaultStencilConfig);
1410 if (requires_readback_) {
1411 auto entity_pass_target =
1412 CreateRenderTarget(renderer_,
1415 render_passes_.push_back(
1416 LazyRenderingConfig(renderer_, std::move(entity_pass_target)));
1418 auto entity_pass_target = std::make_unique<EntityPassTarget>(
1423 render_passes_.push_back(
1424 LazyRenderingConfig(renderer_, std::move(entity_pass_target)));
1428 void Canvas::SkipUntilMatchingRestore(
size_t total_content_depth) {
1429 auto entry = CanvasStackEntry{};
1430 entry.skipping =
true;
1431 entry.clip_depth = current_depth_ + total_content_depth;
1432 transform_stack_.push_back(entry);
1437 return SkipUntilMatchingRestore(total_content_depth);
1441 entry.
transform = transform_stack_.back().transform;
1442 entry.clip_depth = current_depth_ + total_content_depth;
1443 entry.distributed_opacity = transform_stack_.back().distributed_opacity;
1444 FML_DCHECK(entry.clip_depth <= transform_stack_.back().clip_depth)
1445 << entry.clip_depth <<
" <=? " << transform_stack_.back().clip_depth
1446 <<
" after allocating " << total_content_depth;
1447 entry.clip_height = transform_stack_.back().clip_height;
1449 transform_stack_.push_back(entry);
1456 return std::nullopt;
1459 std::optional<Rect> maybe_current_clip_coverage =
1461 if (!maybe_current_clip_coverage.has_value()) {
1462 return std::nullopt;
1465 Rect current_clip_coverage = maybe_current_clip_coverage.value();
1467 FML_CHECK(!render_passes_.empty());
1469 std::shared_ptr<Texture> back_texture =
1471 FML_CHECK(back_texture) <<
"Context is valid:"
1476 std::optional<Rect> maybe_coverage_limit =
1478 Size(back_texture->GetSize()))
1481 if (!maybe_coverage_limit.has_value() || maybe_coverage_limit->IsEmpty()) {
1482 return std::nullopt;
1485 return maybe_coverage_limit->Intersection(
1490 std::optional<Rect> bounds,
1491 const flutter::DlImageFilter* backdrop_filter,
1493 uint32_t total_content_depth,
1494 bool can_distribute_opacity,
1495 std::optional<int64_t> backdrop_id) {
1496 TRACE_EVENT0(
"flutter",
"Canvas::saveLayer");
1498 return SkipUntilMatchingRestore(total_content_depth);
1502 if (!maybe_coverage_limit.has_value()) {
1503 return SkipUntilMatchingRestore(total_content_depth);
1505 auto coverage_limit = maybe_coverage_limit.value();
1507 if (can_distribute_opacity && !backdrop_filter &&
1510 Save(total_content_depth);
1511 transform_stack_.back().distributed_opacity *= paint.
color.
alpha;
1515 std::shared_ptr<FilterContents> filter_contents = paint.
WithImageFilter(
1516 Rect(), transform_stack_.back().transform,
1521 transform_stack_.back().transform,
1526 !!backdrop_filter ||
1531 if (!maybe_subpass_coverage.has_value()) {
1532 return SkipUntilMatchingRestore(total_content_depth);
1535 auto subpass_coverage = maybe_subpass_coverage.value();
1546 bool did_round_out =
false;
1547 Point coverage_origin_adjustment =
Point{0, 0};
1551 did_round_out =
true;
1555 coverage_origin_adjustment =
1556 Point(subpass_coverage.GetLeftTop().x -
1557 std::floor(subpass_coverage.GetLeftTop().x),
1558 subpass_coverage.GetLeftTop().y -
1559 std::floor(subpass_coverage.GetLeftTop().y));
1562 return SkipUntilMatchingRestore(total_content_depth);
1570 ->GetMaximumRenderPassAttachmentSize());
1573 std::shared_ptr<FilterContents> backdrop_filter_contents;
1575 if (backdrop_filter) {
1576 local_position = subpass_coverage.GetOrigin() - GetGlobalPassPosition();
1578 [backdrop_filter = backdrop_filter](
1581 auto filter =
WrapInput(backdrop_filter, input);
1582 filter->SetEffectTransform(effect_transform);
1583 filter->SetRenderingMode(rendering_mode);
1587 std::shared_ptr<Texture> input_texture;
1592 bool will_cache_backdrop_texture =
false;
1597 size_t backdrop_count = 1;
1598 if (backdrop_id.has_value()) {
1599 std::unordered_map<int64_t, BackdropData>::iterator backdrop_data_it =
1600 backdrop_data_.find(backdrop_id.value());
1601 if (backdrop_data_it != backdrop_data_.end()) {
1602 backdrop_data = &backdrop_data_it->second;
1603 will_cache_backdrop_texture =
1605 backdrop_count = backdrop_data_it->second.backdrop_count;
1609 if (!will_cache_backdrop_texture || !backdrop_data->
texture_slot) {
1610 backdrop_count_ -= backdrop_count;
1616 const bool should_use_onscreen =
1618 backdrop_count_ == 0 && render_passes_.size() == 1u;
1619 input_texture = FlipBackdrop(
1620 GetGlobalPassPosition(),
1621 will_cache_backdrop_texture,
1624 if (!input_texture) {
1629 if (will_cache_backdrop_texture) {
1636 backdrop_filter_contents = backdrop_filter_proc(
1638 transform_stack_.back().transform.Basis(),
1641 transform_stack_.back().transform.HasTranslation()
1645 if (will_cache_backdrop_texture) {
1646 FML_DCHECK(backdrop_data);
1653 backdrop_filter_contents->RenderToSnapshot(renderer_, {}, {});
1656 std::optional<Snapshot> maybe_snapshot =
1658 if (maybe_snapshot.has_value()) {
1659 const Snapshot& snapshot = maybe_snapshot.value();
1661 subpass_coverage.Shift(-GetGlobalPassPosition()));
1664 contents->SetTexture(snapshot.
texture);
1665 contents->SetSourceRect(scaled);
1675 backdrop_entity.
Render(renderer_, GetCurrentRenderPass());
1683 Paint paint_copy = paint;
1684 paint_copy.
color.
alpha *= transform_stack_.back().distributed_opacity;
1685 transform_stack_.back().distributed_opacity = 1.0;
1687 render_passes_.push_back(
1689 CreateRenderTarget(renderer_,
1694 paint_copy, subpass_coverage.Shift(-coverage_origin_adjustment)});
1697 entry.
transform = transform_stack_.back().transform;
1698 entry.
clip_depth = current_depth_ + total_content_depth;
1699 FML_DCHECK(entry.
clip_depth <= transform_stack_.back().clip_depth)
1700 << entry.
clip_depth <<
" <=? " << transform_stack_.back().clip_depth
1701 <<
" after allocating " << total_content_depth;
1702 entry.
clip_height = transform_stack_.back().clip_height;
1705 transform_stack_.emplace_back(entry);
1712 clip_coverage_stack_.
PushSubpass(subpass_coverage, GetClipHeight());
1714 if (!backdrop_filter_contents) {
1720 backdrop_entity.
SetContents(std::move(backdrop_filter_contents));
1723 backdrop_entity.
SetClipDepth(std::numeric_limits<uint32_t>::max());
1724 backdrop_entity.
Render(renderer_, GetCurrentRenderPass());
1728 FML_DCHECK(transform_stack_.size() > 0);
1729 if (transform_stack_.size() == 1) {
1746 FML_DCHECK(current_depth_ <= transform_stack_.back().clip_depth)
1747 << current_depth_ <<
" <=? " << transform_stack_.back().clip_depth;
1748 current_depth_ = transform_stack_.back().clip_depth;
1751 transform_stack_.pop_back();
1755 if (transform_stack_.back().rendering_mode ==
1757 transform_stack_.back().rendering_mode ==
1759 auto lazy_render_pass = std::move(render_passes_.back());
1760 render_passes_.pop_back();
1762 lazy_render_pass.GetInlinePassContext()->GetRenderPass();
1765 save_layer_state_.pop_back();
1766 auto global_pass_position = GetGlobalPassPosition();
1768 std::shared_ptr<Contents> contents = CreateContentsForSubpassTarget(
1769 save_layer_state.
paint,
1770 lazy_render_pass.GetInlinePassContext()->GetTexture(),
1772 transform_stack_.back().transform
1775 lazy_render_pass.GetInlinePassContext()->EndPass();
1782 Point subpass_texture_position;
1783 if (transform_stack_.back().did_round_out) {
1786 subpass_texture_position =
1791 subpass_texture_position =
1805 ApplyFramebufferBlend(element_entity);
1816 auto input_texture = FlipBackdrop(GetGlobalPassPosition());
1817 if (!input_texture) {
1827 contents->SetCoverageHint(element_entity.
GetCoverage());
1835 *render_passes_.back().GetInlinePassContext()->GetRenderPass()
1838 transform_stack_.pop_back();
1846 size_t num_clips = transform_stack_.back().num_clips;
1847 transform_stack_.pop_back();
1849 if (num_clips > 0) {
1860 *render_passes_.back().GetInlinePassContext()->GetRenderPass(),
1861 GetGlobalPassPosition()
1869 bool Canvas::AttemptBlurredTextOptimization(
1870 const std::shared_ptr<TextFrame>& text_frame,
1871 const std::shared_ptr<TextContents>& text_contents,
1873 const Paint& paint) {
1887 std::shared_ptr<FilterContents> filter =
1892 std::optional<Glyph> maybe_glyph = text_frame->AsSingleGlyph();
1893 int64_t identifier = maybe_glyph.has_value()
1894 ? maybe_glyph.value().index
1895 :
reinterpret_cast<int64_t
>(text_frame.get());
1896 TextShadowCache::TextShadowCacheKey cache_key(
1899 maybe_glyph.has_value(),
1900 text_frame->GetFont(),
1905 renderer_, entity, filter, cache_key);
1906 if (result.has_value()) {
1907 AddRenderEntityToCurrentPass(result.value(),
false);
1921 const Paint& paint) {
1923 if (max_scale * text_frame->GetFont().GetMetrics().point_size >
1925 fml::StatusOr<flutter::DlPath> path = text_frame->GetPath();
1939 auto text_contents = std::make_shared<TextContents>();
1940 text_contents->SetTextFrame(text_frame);
1941 text_contents->SetPosition(position);
1944 text_contents->SetColor(paint.
color);
1945 text_contents->SetTextProperties(paint.
color,
1947 ? std::optional(paint.
stroke)
1952 if (AttemptBlurredTextOptimization(text_frame, text_contents, entity,
1958 AddRenderEntityToCurrentPass(entity,
false);
1961 void Canvas::AddRenderSDFEntityToCurrentPass(
1965 std::shared_ptr<ColorSourceContents> contents) {
1969 std::shared_ptr<Contents> color_source_contents =
1975 Paint new_paint = paint;
1977 AddRenderEntityWithFiltersToCurrentPass(entity, geom, new_paint,
1980 std::move(final_contents));
1982 AddRenderEntityWithFiltersToCurrentPass(entity, geom, paint,
1985 std::move(contents));
1989 void Canvas::AddRenderEntityWithFiltersToCurrentPass(
1991 const Geometry* geometry,
1994 std::shared_ptr<Contents> override_contents) {
1995 std::shared_ptr<ColorSourceContents> color_source_contents;
1996 std::shared_ptr<Contents> contents;
1997 if (override_contents) {
1998 contents = std::move(override_contents);
2000 color_source_contents = paint.CreateContents(geometry);
2001 contents = color_source_contents;
2004 if (!paint.color_filter && !paint.invert_colors && !paint.image_filter &&
2005 !paint.mask_blur_descriptor.has_value()) {
2006 entity.SetContents(std::move(contents));
2007 AddRenderEntityToCurrentPass(entity, reuse_depth);
2014 bool needs_color_filter = paint.color_filter || paint.invert_colors;
2015 if (needs_color_filter &&
2016 contents->ApplyColorFilter([&](Color color) -> Color {
2017 if (paint.color_filter) {
2018 color = GetCPUColorFilterProc(paint.color_filter)(color);
2020 if (paint.invert_colors) {
2021 color = color.ApplyColorMatrix(kColorInversion);
2025 needs_color_filter =
false;
2028 bool can_apply_mask_filter = geometry->CanApplyMaskFilter();
2030 if (can_apply_mask_filter && paint.mask_blur_descriptor.has_value()) {
2034 FML_DCHECK(color_source_contents) <<
"Mask blur is only supported when no "
2035 "override contents are provided.";
2036 FillRectGeometry out_rect(
Rect{});
2037 auto filter = paint.mask_blur_descriptor->CreateMaskBlur(
2038 paint, geometry, color_source_contents, needs_color_filter, &out_rect);
2039 entity.SetContents(std::move(filter));
2040 AddRenderEntityToCurrentPass(entity, reuse_depth);
2044 std::shared_ptr<Contents> contents_copy = std::move(contents);
2048 if (needs_color_filter &&
2049 (!paint.color_source ||
2050 paint.color_source->type() != flutter::DlColorSourceType::kImage)) {
2051 if (paint.color_filter) {
2056 if (paint.invert_colors) {
2063 if (paint.image_filter) {
2064 std::shared_ptr<FilterContents> filter =
WrapInput(
2067 entity.SetContents(filter);
2068 AddRenderEntityToCurrentPass(entity, reuse_depth);
2072 entity.SetContents(std::move(contents_copy));
2073 AddRenderEntityToCurrentPass(entity, reuse_depth);
2076 void Canvas::AddRenderEntityToCurrentPass(Entity& entity,
bool reuse_depth) {
2081 entity.SetTransform(
2082 Matrix::MakeTranslation(Vector3(-GetGlobalPassPosition())) *
2083 entity.GetTransform());
2084 entity.SetInheritedOpacity(transform_stack_.back().distributed_opacity);
2085 if (entity.GetBlendMode() == BlendMode::kSrcOver &&
2086 entity.GetContents()->IsOpaque(entity.GetTransform())) {
2087 entity.SetBlendMode(BlendMode::kSrc);
2093 if (render_passes_.back().IsApplyingClearColor()) {
2094 std::optional<Color> maybe_color = entity.AsBackgroundColor(
2095 render_passes_.back().GetInlinePassContext()->GetTexture()->GetSize());
2096 if (maybe_color.has_value()) {
2097 Color color = maybe_color.value();
2098 RenderTarget& render_target = render_passes_.back()
2099 .GetInlinePassContext()
2102 ColorAttachment attachment = render_target.GetColorAttachment(0);
2105 attachment.clear_color = attachment.clear_color.Unpremultiply()
2106 .Blend(color, entity.GetBlendMode())
2108 render_target.SetColorAttachment(attachment, 0u);
2119 FML_DCHECK(current_depth_ <= transform_stack_.back().clip_depth)
2120 << current_depth_ <<
" <=? " << transform_stack_.back().clip_depth;
2121 entity.SetClipDepth(current_depth_);
2123 if (entity.GetBlendMode() > Entity::kLastPipelineBlendMode) {
2124 if (renderer_.GetDeviceCapabilities().SupportsFramebufferFetch()) {
2125 ApplyFramebufferBlend(entity);
2136 auto input_texture = FlipBackdrop(GetGlobalPassPosition(),
2140 if (!input_texture) {
2148 auto element_coverage_hint = entity.GetContents()->GetCoverageHint();
2149 entity.GetContents()->SetCoverageHint(Rect::Intersection(
2150 element_coverage_hint, clip_coverage_stack_.CurrentClipCoverage()));
2152 FilterInput::Vector inputs = {
2153 FilterInput::Make(input_texture, entity.GetTransform().Invert()),
2154 FilterInput::Make(entity.GetContents())};
2156 ColorFilterContents::MakeBlend(entity.GetBlendMode(), inputs);
2157 entity.SetContents(std::move(contents));
2158 entity.SetBlendMode(BlendMode::kSrc);
2162 const std::shared_ptr<RenderPass>& result =
2163 render_passes_.back().GetInlinePassContext()->GetRenderPass();
2171 entity.Render(renderer_, *result);
2174 RenderPass& Canvas::GetCurrentRenderPass()
const {
2175 return *render_passes_.back().GetInlinePassContext()->GetRenderPass();
2178 void Canvas::SetBackdropData(
2179 std::unordered_map<int64_t, BackdropData> backdrop_data,
2180 size_t backdrop_count) {
2181 backdrop_data_ = std::move(backdrop_data);
2182 backdrop_count_ = backdrop_count;
2185 std::shared_ptr<Texture> Canvas::FlipBackdrop(
Point global_pass_position,
2186 bool should_remove_texture,
2187 bool should_use_onscreen,
2188 bool post_depth_increment) {
2190 render_passes_.pop_back();
2206 <<
"Failed to end the current render pass in order to read from "
2207 "the backdrop texture and apply an advanced blend or backdrop "
2212 render_passes_.emplace_back(std::move(rendering_config));
2216 const std::shared_ptr<Texture>& input_texture =
2219 if (!input_texture) {
2220 VALIDATION_LOG <<
"Failed to fetch the color texture in order to "
2221 "apply an advanced blend or backdrop filter.";
2224 render_passes_.emplace_back(std::move(rendering_config));
2228 if (should_use_onscreen) {
2229 ColorAttachment color0 = render_target_.GetColorAttachment(0);
2233 color0.
load_action = color0.resolve_texture !=
nullptr
2234 ? LoadAction::kDontCare
2235 : LoadAction::kLoad;
2236 render_target_.SetColorAttachment(color0, 0);
2238 auto entity_pass_target = std::make_unique<EntityPassTarget>(
2240 renderer_.GetDeviceCapabilities().SupportsReadFromResolve(),
2241 renderer_.GetDeviceCapabilities().SupportsImplicitResolvingMSAA()
2243 render_passes_.push_back(
2244 LazyRenderingConfig(renderer_, std::move(entity_pass_target)));
2245 requires_readback_ =
false;
2247 render_passes_.emplace_back(std::move(rendering_config));
2250 if (should_remove_texture) {
2251 render_passes_.back().GetEntityPassTarget()->RemoveSecondary();
2254 RenderPass& current_render_pass =
2255 *render_passes_.back().GetInlinePassContext()->GetRenderPass();
2264 Rect size_rect = Rect::MakeSize(input_texture->GetSize());
2265 auto msaa_backdrop_contents = TextureContents::MakeRect(size_rect);
2266 msaa_backdrop_contents->SetStencilEnabled(
false);
2267 msaa_backdrop_contents->SetLabel(
"MSAA backdrop");
2268 msaa_backdrop_contents->SetSourceRect(size_rect);
2269 msaa_backdrop_contents->SetTexture(input_texture);
2271 Entity msaa_backdrop_entity;
2272 msaa_backdrop_entity.SetContents(std::move(msaa_backdrop_contents));
2273 msaa_backdrop_entity.SetBlendMode(BlendMode::kSrc);
2274 msaa_backdrop_entity.SetClipDepth(std::numeric_limits<uint32_t>::max());
2275 if (!msaa_backdrop_entity.Render(renderer_, current_render_pass)) {
2282 auto& replay_entities = clip_coverage_stack_.GetReplayEntities();
2283 uint64_t current_depth =
2284 post_depth_increment ? current_depth_ - 1 : current_depth_;
2285 for (
const auto& replay : replay_entities) {
2286 if (replay.clip_depth <= current_depth) {
2290 SetClipScissor(replay.clip_coverage, current_render_pass,
2291 global_pass_position);
2292 if (!replay.clip_contents.Render(renderer_, current_render_pass,
2293 replay.clip_depth)) {
2298 return input_texture;
2301 bool Canvas::SupportsBlitToOnscreen()
const {
2302 return renderer_.GetContext()
2304 ->SupportsTextureToTextureBlits() &&
2305 renderer_.GetContext()->GetBackendType() ==
2306 Context::BackendType::kMetal;
2309 bool Canvas::BlitToOnscreen(
bool is_onscreen) {
2310 auto command_buffer = renderer_.GetContext()->CreateCommandBuffer();
2311 command_buffer->SetLabel(
"EntityPass Root Command Buffer");
2312 auto offscreen_target = render_passes_.back()
2313 .GetInlinePassContext()
2316 if (SupportsBlitToOnscreen()) {
2317 auto blit_pass = command_buffer->CreateBlitPass();
2318 blit_pass->AddCopy(offscreen_target.GetRenderTargetTexture(),
2319 render_target_.GetRenderTargetTexture());
2320 if (!blit_pass->EncodeCommands()) {
2325 auto render_pass = command_buffer->CreateRenderPass(render_target_);
2326 render_pass->SetLabel(
"EntityPass Root Render Pass");
2329 auto size_rect = Rect::MakeSize(offscreen_target.GetRenderTargetSize());
2330 auto contents = TextureContents::MakeRect(size_rect);
2331 contents->SetTexture(offscreen_target.GetRenderTargetTexture());
2332 contents->SetSourceRect(size_rect);
2333 contents->SetLabel(
"Root pass blit");
2336 entity.SetContents(contents);
2337 entity.SetBlendMode(BlendMode::kSrc);
2339 if (!entity.Render(renderer_, *render_pass)) {
2345 if (!render_pass->EncodeCommands()) {
2352 return renderer_.GetContext()->SubmitOnscreen(std::move(command_buffer));
2354 return renderer_.GetContext()->EnqueueCommandBuffer(
2355 std::move(command_buffer));
2359 bool Canvas::EnsureFinalMipmapGeneration()
const {
2360 if (!render_target_.GetRenderTargetTexture()->NeedsMipmapGeneration()) {
2363 std::shared_ptr<CommandBuffer> cmd_buffer =
2364 renderer_.GetContext()->CreateCommandBuffer();
2368 std::shared_ptr<BlitPass> blit_pass = cmd_buffer->CreateBlitPass();
2372 blit_pass->GenerateMipmap(render_target_.GetRenderTargetTexture());
2373 blit_pass->EncodeCommands();
2374 return renderer_.GetContext()->EnqueueCommandBuffer(std::move(cmd_buffer));
2377 void Canvas::EndReplay() {
2378 FML_DCHECK(render_passes_.size() == 1u);
2379 render_passes_.back().GetInlinePassContext()->GetRenderPass();
2380 render_passes_.back().GetInlinePassContext()->EndPass(
2381 !requires_readback_ && is_onscreen_);
2382 backdrop_data_.clear();
2387 if (requires_readback_) {
2388 BlitToOnscreen(is_onscreen_);
2390 if (!EnsureFinalMipmapGeneration()) {
2393 if (!renderer_.GetContext()->FlushCommandBuffers()) {
2397 render_passes_.clear();
2398 renderer_.GetRenderTargetCache()->End();
2399 clip_geometry_.clear();
2402 Initialize(initial_cull_rect_);
2405 LazyRenderingConfig::LazyRenderingConfig(
2407 std::unique_ptr<EntityPassTarget> p_entity_pass_target)
2408 : entity_pass_target_(
std::move(p_entity_pass_target)) {
2409 inline_pass_context_ =
2410 std::make_unique<InlinePassContext>(renderer, *entity_pass_target_);
2414 return !inline_pass_context_->IsActive();
2418 return entity_pass_target_.get();
2422 return inline_pass_context_.get();
A Geometry that produces fillable vertices representing the stroked outline of an |Arc| object using ...
std::shared_ptr< SolidBlurContents > BuildBlurContent(Sigma sigma) override
Rect GetBounds() const override
const Geometry & BuildDrawGeometry() override
PathBlurShape(const PathSource &source[[clang::lifetimebound]], std::shared_ptr< ShadowVertices > shadow_vertices, Sigma sigma)
Rect GetBounds() const override
RRectBlurShape(const Rect &rect, Scalar corner_radius)
std::shared_ptr< SolidBlurContents > BuildBlurContent(Sigma sigma) override
const Geometry & BuildDrawGeometry() override
const Geometry & BuildDrawGeometry() override
Rect GetBounds() const override
std::shared_ptr< SolidBlurContents > BuildBlurContent(Sigma sigma) override
RSuperellipseBlurShape(const Rect &rect, Scalar corner_radius)
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)
void DrawRoundSuperellipse(const RoundSuperellipse &rse, const Paint &paint)
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)
void DrawDashedLine(const Point &p0, const Point &p1, Scalar on_length, Scalar off_length, const Paint &paint)
void DrawDiffRoundRect(const RoundRect &outer, const RoundRect &inner, const Paint &paint)
void DrawPath(const flutter::DlPath &path, const Paint &paint)
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 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)
void DrawArc(const Arc &arc, 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...
static std::unique_ptr< CircleContents > Make(std::unique_ptr< CircleGeometry > geometry, Color color, bool stroked)
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
TextShadowCache & GetTextShadowCache() const
Tessellator & GetTessellator() const
std::shared_ptr< Context > GetContext() const
A geometry that implements "drawPaint" like behavior by covering the entire render pass area.
A Geometry class that can directly generate vertices (with or without texture coordinates) for filled...
A PathSource object that provides path iteration for any ellipse inscribed within a Rect bounds.
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 produces fillable vertices for the gap between a pair of |RoundRect| objects using th...
A Geometry that produces fillable vertices from a |DlPath| object using the |FillPathSourceGeometry| ...
void SetAntialiasPadding(Scalar padding)
A Geometry class that produces fillable vertices from any |RoundRect| object regardless of radii unif...
@ 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 std::optional< Rect > GetCoverage(const Matrix &transform) const =0
virtual bool IsAxisAlignedRect() const
bool EndPass(bool is_onscreen=false)
std::shared_ptr< Texture > GetTexture()
const std::shared_ptr< RenderPass > & GetRenderPass()
bool IsApplyingClearColor() const
Whether or not the clear color texture can still be updated.
EntityPassTarget * GetEntityPassTarget() const
InlinePassContext * GetInlinePassContext() const
static std::unique_ptr< LineContents > Make(std::unique_ptr< LineGeometry > geometry, Color color)
static Scalar ComputePixelHalfWidth(const Matrix &transform, Scalar width)
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 class that generates fillable vertices (with or without texture coordinates) directly from...
A Geometry class that generates fillable vertices (with or without texture coordinates) directly from...
static std::shared_ptr< ShadowVertices > MakeAmbientShadowVertices(Tessellator &tessellator, const PathSource &source, Scalar occluder_height, const Matrix &matrix)
static std::shared_ptr< ShadowVerticesContents > Make(const std::shared_ptr< ShadowVertices > &geometry)
A Geometry that produces fillable vertices representing the stroked outline of a |DlPath| object usin...
A Geometry that produces fillable vertices representing the stroked outline of a pair of nested |Roun...
A Geometry class that produces fillable vertices representing the stroked outline of an ellipse with ...
A Geometry that produces fillable vertices representing the stroked outline of a |DlPath| object usin...
A Geometry class that produces fillable vertices representing the stroked outline of any |Roundrect| ...
A Geometry class that produces fillable vertices representing the stroked outline of any |RoundSupere...
std::optional< Entity > Lookup(const ContentContext &renderer, const Entity &entity, const std::shared_ptr< FilterContents > &contents, const TextShadowCacheKey &)
Lookup the entity in the cache with the given filter/text contents, returning the new entity to rende...
static std::shared_ptr< TextureContents > MakeRect(Rect destination)
static std::unique_ptr< UberSDFContents > MakeRect(Color color, Scalar stroke_width, Join stroke_join, bool stroked, const FillRectGeometry *geometry)
static std::unique_ptr< UberSDFContents > MakeCircle(Color color, bool stroked, const CircleGeometry *geometry)
ISize subpass_size
The output size of the down-sampling pass.
impeller::SamplerDescriptor ToSamplerDescriptor(const flutter::DlImageSampling options)
Color ToColor(const flutter::DlColor &color)
static constexpr Scalar kMaxTextScale
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.
constexpr bool ScalarNearlyEqual(Scalar x, Scalar y, Scalar tolerance=kEhCloseEnough)
constexpr bool IncludeCenter() const
constexpr bool IsFullCircle() const
const Rect & GetOvalBounds() const
Return the bounds of the oval in which this arc is inscribed.
constexpr Degrees GetSweep() const
constexpr Degrees GetStart() const
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 Khaki()
static constexpr Color White()
constexpr Color WithAlpha(Scalar new_alpha) const
ClipContents clip_contents
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)
Scalar GetMaxBasisLengthXY() const
Return the maximum scale applied specifically to either the X axis or Y axis unit vectors (the bases)...
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< ColorSourceContents > CreateContents(const Geometry *geometry) 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
bool HasColorFilter() const
Whether this paint has a color filter that can apply opacity.
constexpr const RoundingRadii & GetRadii() const
constexpr const Rect & GetBounds() const
constexpr const RoundingRadii & GetRadii() const
constexpr const Rect & GetBounds() const
constexpr bool AreAllCornersSame(Scalar tolerance=kEhCloseEnough) const
In filters that use Gaussian distributions, "sigma" is a size of one standard deviation in terms of t...
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 Type GetDistance(const TPoint &p) const
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()
constexpr bool IsEmpty() const
Returns true if either of the width or height are 0, negative, or NaN.
std::vector< Point > points