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"
74 constexpr
Scalar kAntialiasPadding = 1.0f;
76 bool IsPipelineBlendOrMatrixFilter(
const flutter::DlColorFilter* filter) {
77 return filter->type() == flutter::DlColorFilterType::kMatrix ||
78 (filter->type() == flutter::DlColorFilterType::kBlend &&
82 static bool UseColorSourceContents(
83 const std::shared_ptr<VerticesGeometry>& vertices,
87 if (vertices->HasVertexColors()) {
90 if (vertices->HasTextureCoordinates() && !paint.color_source) {
93 return !vertices->HasTextureCoordinates();
96 static void SetClipScissor(std::optional<Rect> clip_coverage,
98 Point global_pass_position) {
102 if (clip_coverage.has_value()) {
103 clip_coverage = clip_coverage->Shift(-global_pass_position);
110 pass.SetScissor(scissor);
113 static void ApplyFramebufferBlend(Entity& entity) {
114 auto src_contents = entity.GetContents();
115 auto contents = std::make_shared<FramebufferBlendContents>();
116 contents->SetChildContents(src_contents);
117 contents->SetBlendMode(entity.GetBlendMode());
118 entity.SetContents(std::move(contents));
124 static std::shared_ptr<Contents> CreateContentsForSubpassTarget(
125 const ContentContext& renderer,
127 const std::shared_ptr<Texture>& target,
128 const Matrix& effect_transform) {
130 contents->SetTexture(target);
131 contents->SetLabel(
"Subpass");
133 contents->SetOpacity(paint.color.alpha);
134 contents->SetDeferApplyingOpacity(
true);
136 return paint.WithFiltersForSubpassTarget(renderer, std::move(contents),
140 static const constexpr RenderTarget::AttachmentConfig kDefaultStencilConfig =
141 RenderTarget::AttachmentConfig{
147 static std::unique_ptr<EntityPassTarget> CreateRenderTarget(
148 ContentContext& renderer,
150 const Color& clear_color) {
151 const std::shared_ptr<Context>&
context = renderer.GetContext();
159 if (
context->GetCapabilities()->SupportsOffscreenMSAA()) {
160 target = renderer.GetRenderTargetCache()->CreateOffscreenMSAA(
166 RenderTarget::AttachmentConfigMSAA{
171 .clear_color = clear_color},
172 kDefaultStencilConfig);
174 target = renderer.GetRenderTargetCache()->CreateOffscreen(
179 RenderTarget::AttachmentConfig{
183 .clear_color = clear_color,
185 kDefaultStencilConfig
189 return std::make_unique<EntityPassTarget>(
191 renderer.GetDeviceCapabilities().SupportsReadFromResolve(),
192 renderer.GetDeviceCapabilities().SupportsImplicitResolvingMSAA()
203 static std::pair<Rect, Color> ExpandRectToPixelMinimum(
const Rect& rect,
207 std::optional<Rect> expanded =
208 rect.ExpandToMinTransformedSize({1.0f, 1.0f},
transform);
211 return {
Rect(), color};
216 return {expanded.value(), color};
220 Scalar alpha_scaling = rect.Area() / expanded->Area();
223 return {
Rect(), color};
225 return {expanded.value(), color.WithAlpha(color.alpha * alpha_scaling)};
233 : rect_(rect), corner_radius_(corner_radius) {}
238 auto contents = std::make_shared<SolidRRectBlurContents>();
239 contents->SetSigma(sigma);
240 contents->SetShape(rect_, corner_radius_);
245 return geom_.emplace(rect_,
Size(corner_radius_));
250 const Scalar corner_radius_;
252 std::optional<RoundRectGeometry> geom_;
258 : rect_(rect), corner_radius_(corner_radius) {}
263 auto contents = std::make_shared<SolidRSuperellipseBlurContents>();
264 contents->SetSigma(sigma);
265 contents->SetShape(rect_, corner_radius_);
270 return geom_.emplace(rect_, corner_radius_);
275 const Scalar corner_radius_;
277 std::optional<RoundSuperellipseGeometry> geom_;
297 std::shared_ptr<ShadowVertices> shadow_vertices,
301 shadow_vertices_(
std::move(shadow_vertices)) {}
304 return shadow_vertices_->GetBounds().value_or(
Rect());
318 return source_geometry_.emplace(source_);
324 const std::shared_ptr<ShadowVertices> shadow_vertices_;
327 std::optional<FillPathFromSourceGeometry> source_geometry_;
333 bool requires_readback)
334 : renderer_(renderer),
335 render_target_(render_target),
336 is_onscreen_(is_onscreen),
337 requires_readback_(requires_readback),
339 Rect::MakeSize(render_target.GetRenderTargetSize()))) {
340 Initialize(std::nullopt);
347 bool requires_readback,
349 : renderer_(renderer),
350 render_target_(render_target),
351 is_onscreen_(is_onscreen),
352 requires_readback_(requires_readback),
354 Rect::MakeSize(render_target.GetRenderTargetSize()))) {
355 Initialize(cull_rect);
362 bool requires_readback,
364 : renderer_(renderer),
365 render_target_(render_target),
366 is_onscreen_(is_onscreen),
367 requires_readback_(requires_readback),
369 Rect::MakeSize(render_target.GetRenderTargetSize()))) {
375 void Canvas::Initialize(std::optional<Rect> cull_rect) {
376 initial_cull_rect_ = cull_rect;
383 void Canvas::Reset() {
385 transform_stack_ = {};
397 transform_stack_.back().transform = {};
405 return transform_stack_.back().transform;
428 Point Canvas::GetGlobalPassPosition()
const {
429 if (save_layer_state_.empty()) {
432 return save_layer_state_.back().coverage.GetOrigin();
436 size_t Canvas::GetClipHeightFloor()
const {
437 if (transform_stack_.size() > 1) {
438 return transform_stack_[transform_stack_.size() - 2].clip_height;
444 return transform_stack_.size();
447 bool Canvas::IsSkipping()
const {
448 return transform_stack_.back().skipping;
460 if (IsShadowBlurDrawOperation(paint)) {
461 if (AttemptDrawBlurredPathSource(path, paint)) {
472 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
475 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
485 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
492 bool Canvas::AttemptColorFilterOptimization(
493 const std::shared_ptr<Texture>& image,
507 if (paint.
color_filter->type() == flutter::DlColorFilterType::kBlend) {
508 const flutter::DlBlendColorFilter* blend_filter =
510 DrawImageRectAtlasGeometry geometry = DrawImageRectAtlasGeometry(
515 blend_filter->mode(),
517 src_rect_constraint ==
520 auto atlas_contents = std::make_shared<AtlasContents>();
521 atlas_contents->SetGeometry(&geometry);
527 entity.SetContents(atlas_contents);
529 AddRenderEntityToCurrentPass(entity);
537 const flutter::DlMatrixColorFilter* matrix_filter =
540 DrawImageRectAtlasGeometry geometry = DrawImageRectAtlasGeometry(
547 src_rect_constraint ==
550 auto atlas_contents = std::make_shared<ColorFilterAtlasContents>();
551 atlas_contents->SetGeometry(&geometry);
554 matrix_filter->get_matrix(color_matrix.
array);
555 atlas_contents->SetMatrix(color_matrix);
560 entity.SetContents(atlas_contents);
562 AddRenderEntityToCurrentPass(entity);
567 bool Canvas::AttemptDrawAntialiasedCircle(
const Point& center,
569 const Paint& paint) {
570 if (paint.HasColorFilter() || paint.image_filter || paint.invert_colors ||
571 paint.color_source || paint.mask_blur_descriptor.has_value()) {
577 entity.SetBlendMode(paint.blend_mode);
580 std::unique_ptr<CircleGeometry> geom;
582 geom = std::make_unique<CircleGeometry>(center, radius, paint.stroke.width);
584 geom = std::make_unique<CircleGeometry>(center, radius);
586 geom->SetAntialiasPadding(kAntialiasPadding);
590 entity.SetContents(std::move(contents));
591 AddRenderEntityToCurrentPass(entity);
596 bool Canvas::IsShadowBlurDrawOperation(
const Paint& paint) {
601 if (paint.color_source) {
605 if (!paint.mask_blur_descriptor.has_value()) {
616 Radius radius = paint.mask_blur_descriptor->sigma;
624 bool Canvas::AttemptDrawBlurredPathSource(
const PathSource& source,
625 const Paint& paint) {
626 FML_DCHECK(IsShadowBlurDrawOperation);
632 if (paint.mask_blur_descriptor.has_value()) {
636 static constexpr
Scalar kSigmaScale = 2.8f;
638 Sigma sigma = paint.mask_blur_descriptor->sigma;
640 Scalar basis_scale = matrix.GetMaxBasisLengthXY();
641 Scalar device_radius = sigma.sigma * kSigmaScale * basis_scale;
642 std::shared_ptr<ShadowVertices> shadow_vertices =
645 if (shadow_vertices) {
646 PathBlurShape shape(source, std::move(shadow_vertices), sigma);
647 return AttemptDrawBlur(shape, paint);
653 Scalar Canvas::GetCommonRRectLikeRadius(
const RoundingRadii& radii) {
654 if (!radii.AreAllCornersSame()) {
657 const Size& corner_radii = radii.top_left;
659 return corner_radii.
width;
664 bool Canvas::AttemptDrawBlurredRRect(
const RoundRect& round_rect,
665 const Paint& paint) {
666 Scalar radius = GetCommonRRectLikeRadius(round_rect.GetRadii());
668 RoundRectPathSource source(round_rect);
669 return AttemptDrawBlurredPathSource(source, paint);
671 RRectBlurShape shape(round_rect.GetBounds(), radius);
672 return AttemptDrawBlur(shape, paint);
675 bool Canvas::AttemptDrawBlurredRSuperellipse(
const RoundSuperellipse& rse,
676 const Paint& paint) {
677 Scalar radius = GetCommonRRectLikeRadius(rse.GetRadii());
679 RoundSuperellipsePathSource source(rse);
680 return AttemptDrawBlurredPathSource(source, paint);
682 RSuperellipseBlurShape shape(rse.GetBounds(), radius);
683 return AttemptDrawBlur(shape, paint);
686 bool Canvas::AttemptDrawBlur(BlurShape& shape,
const Paint& paint) {
687 FML_DCHECK(IsShadowBlurDrawOperation(paint));
691 Color rrect_color = paint.color;
692 if (paint.invert_colors) {
695 if (paint.color_filter) {
699 Paint rrect_paint = {.mask_blur_descriptor = paint.mask_blur_descriptor};
701 if (!rrect_paint.mask_blur_descriptor.has_value()) {
728 if ((paint.mask_blur_descriptor->style !=
730 paint.image_filter) ||
733 Rect render_bounds = shape.GetBounds();
734 if (paint.mask_blur_descriptor->style !=
737 render_bounds.
Expand(paint.mask_blur_descriptor->sigma.sigma * 4.0);
743 .image_filter = paint.image_filter,
744 .blend_mode = paint.blend_mode,
747 rrect_paint.color = rrect_color.WithAlpha(1);
749 rrect_paint.color = rrect_color;
750 rrect_paint.blend_mode = paint.blend_mode;
751 rrect_paint.image_filter = paint.image_filter;
755 auto draw_blurred_rrect = [
this, &rrect_paint, &shape]() {
756 std::shared_ptr<SolidBlurContents> contents =
757 shape.BuildBlurContent(rrect_paint.mask_blur_descriptor->sigma);
758 FML_DCHECK(contents);
760 contents->SetColor(rrect_paint.color);
762 Entity blurred_rrect_entity;
764 blurred_rrect_entity.SetBlendMode(rrect_paint.blend_mode);
766 rrect_paint.mask_blur_descriptor = std::nullopt;
767 blurred_rrect_entity.SetContents(
768 rrect_paint.WithFilters(renderer_, std::move(contents)));
769 AddRenderEntityToCurrentPass(blurred_rrect_entity);
772 switch (rrect_paint.mask_blur_descriptor->style) {
774 draw_blurred_rrect();
779 draw_blurred_rrect();
783 entity.SetBlendMode(rrect_paint.blend_mode);
785 const Geometry& geom = shape.BuildDrawGeometry();
786 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, rrect_paint,
791 const Geometry& geom = shape.BuildDrawGeometry();
793 draw_blurred_rrect();
797 const Geometry& geom = shape.BuildDrawGeometry();
799 draw_blurred_rrect();
809 bool Canvas::AttemptDrawLineSDF(
const Point& p0,
813 if (!(renderer_.
GetContext()->GetFlags().use_sdfs ||
814 renderer_.
GetContext()->GetFlags().antialiased_lines) ||
821 Paint rect_paint = paint;
824 Scalar line_length = p0.GetDistance(
p1);
825 if (line_length == 0.0f && paint.stroke.cap ==
Cap::kButt) {
829 Scalar half_stroke_width = paint.stroke.width * 0.5f;
830 Scalar half_length = line_length * 0.5f;
836 half_length += half_stroke_width;
841 Point(half_length, half_stroke_width));
848 line_length > 0.0f ? ((
p1 - p0) / line_length) :
Point(1.0f, 0.0f);
850 Point center = (p0 +
p1) * 0.5f;
853 u.x, u.y, 0.0f, 0.0f,
855 perp.x, perp.y, 0.0f, 0.0f,
857 0.0f, 0.0f, 1.0f, 0.0f,
859 center.x, center.y, 0.0f, 1.0f);
863 auto [expanded, alpha_scaled_color] = ExpandRectToPixelMinimum(
867 paint.stroke.width != 0.0f);
869 if (expanded.IsEmpty()) {
874 rect_paint.color = alpha_scaled_color;
878 UberSDFParameters params;
892 AddRenderSDFEntityToCurrentPass(paint, params, reuse_depth,
893 rect_to_line_transform);
901 if (AttemptDrawLineSDF(p0,
p1, paint, reuse_depth)) {
909 auto geometry = std::make_unique<LineGeometry>(p0,
p1, paint.
stroke);
911 AddRenderEntityWithFiltersToCurrentPass(entity, geometry.get(), paint,
919 const Paint& paint) {
929 if (length > 0.0f && on_length >= 0.0f && off_length > 0.0f) {
935 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
946 if (IsShadowBlurDrawOperation(paint)) {
948 if (AttemptDrawBlur(shape, paint)) {
953 if (renderer_.
GetContext()->GetFlags().use_sdfs &&
955 Rect effective_rect = rect;
961 auto [expanded, alpha_scaled_color] = ExpandRectToPixelMinimum(
964 if (expanded.IsEmpty()) {
969 effective_rect = expanded;
970 effective_color = alpha_scaled_color;
977 AddRenderSDFEntityToCurrentPass(paint, params);
987 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
990 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
1006 if (IsShadowBlurDrawOperation(paint)) {
1011 if (AttemptDrawBlur(shape, paint)) {
1016 if (AttemptDrawBlurredPathSource(source, paint)) {
1026 if (renderer_.
GetContext()->GetFlags().use_sdfs &&
1036 AddRenderSDFEntityToCurrentPass(paint, params);
1042 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
1045 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
1056 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
1069 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
1082 return DrawOval(oval_bounds, paint);
1092 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
1098 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
1106 if (IsShadowBlurDrawOperation(paint)) {
1107 if (AttemptDrawBlurredRRect(round_rect, paint)) {
1114 if (renderer_.
GetContext()->GetFlags().use_sdfs &&
1122 auto [expanded, alpha_scaled_color] = ExpandRectToPixelMinimum(
1125 if (expanded.IsEmpty()) {
1131 effective_color = alpha_scaled_color;
1139 ? std::make_optional(paint.
stroke)
1141 AddRenderSDFEntityToCurrentPass(paint, params);
1153 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
1163 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
1166 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
1172 const Paint& paint) {
1179 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
1182 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
1187 const Paint& paint) {
1188 if (IsShadowBlurDrawOperation(paint)) {
1189 if (AttemptDrawBlurredRSuperellipse(round_superellipse, paint)) {
1198 if (renderer_.
GetContext()->GetFlags().use_sdfs &&
1203 if (round_superellipse_params.all_corners_same) {
1207 round_superellipse_params,
1210 AddRenderSDFEntityToCurrentPass(paint, params);
1216 round_superellipse_params,
1219 const Geometry* geom = contents->GetGeometry();
1222 std::shared_ptr<Contents> color_source_contents =
1224 std::shared_ptr<Contents> final_contents =
1229 Paint new_paint = paint;
1231 AddRenderEntityWithFiltersToCurrentPass(entity, geom, new_paint,
1234 std::move(final_contents));
1236 AddRenderEntityWithFiltersToCurrentPass(entity, geom, paint,
1239 std::move(contents));
1248 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
1251 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
1257 const Paint& paint) {
1258 if (IsShadowBlurDrawOperation(paint)) {
1261 if (AttemptDrawBlur(shape, paint)) {
1266 if (renderer_.
GetContext()->GetFlags().use_sdfs &&
1269 paint.
color, center, radius,
1271 AddRenderSDFEntityToCurrentPass(paint, params);
1275 if (AttemptDrawAntialiasedCircle(center, radius, paint)) {
1285 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
1288 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
1309 FML_DCHECK(current_depth_ <= transform_stack_.back().clip_depth)
1310 << current_depth_ <<
" <=? " << transform_stack_.back().clip_depth;
1311 uint32_t clip_depth = transform_stack_.back().clip_depth;
1313 const Matrix clip_transform =
1317 std::optional<Rect> clip_coverage = geometry.
GetCoverage(clip_transform);
1318 if (!clip_coverage.has_value()) {
1323 clip_coverage.value(),
1332 GetGlobalPassPosition(),
1334 GetClipHeightFloor(),
1341 *render_passes_.back().GetInlinePassContext()->GetRenderPass(),
1342 GetGlobalPassPosition());
1345 ++transform_stack_.back().clip_height;
1346 ++transform_stack_.back().num_clips;
1363 *render_passes_.back().GetInlinePassContext()->GetRenderPass()
1370 renderer_, *render_passes_.back().GetInlinePassContext()->GetRenderPass(),
1389 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
1416 ISize size = image->GetSize();
1421 std::optional<Rect> clipped_source =
1423 if (!clipped_source) {
1427 if (AttemptColorFilterOptimization(image, source, dest, paint, sampler,
1428 src_rect_constraint)) {
1432 if (*clipped_source != source) {
1442 texture_contents->SetTexture(image);
1443 texture_contents->SetSourceRect(*clipped_source);
1444 texture_contents->SetStrictSourceRect(src_rect_constraint ==
1446 texture_contents->SetSamplerDescriptor(sampler);
1447 texture_contents->SetOpacity(paint.
color.
alpha);
1448 texture_contents->SetDeferApplyingOpacity(paint.
HasColorFilter());
1456 paint.
WithFilters(renderer_, std::move(texture_contents)));
1457 AddRenderEntityToCurrentPass(entity);
1466 AddRenderEntityToCurrentPass(entity);
1469 size_t Canvas::GetClipHeight()
const {
1470 return transform_stack_.back().clip_height;
1475 const Paint& paint) {
1488 if (UseColorSourceContents(vertices, paint)) {
1489 AddRenderEntityWithFiltersToCurrentPass(entity, vertices.get(), paint);
1495 auto contents = std::make_shared<VerticesSimpleBlendContents>();
1496 contents->SetBlendMode(blend_mode);
1498 contents->SetGeometry(vertices);
1500 AddRenderEntityToCurrentPass(entity);
1507 paint.
color_source->type() == flutter::DlColorSourceType::kImage) {
1508 const flutter::DlImageColorSource* image_color_source =
1510 FML_DCHECK(image_color_source);
1512 image_color_source->image()->asImpellerImage()->GetCachedTexture(
1514 FML_DCHECK(texture);
1516 image_color_source->horizontal_tile_mode());
1519 auto sampler_descriptor =
1521 auto effect_transform = image_color_source->matrix();
1523 auto contents = std::make_shared<VerticesSimpleBlendContents>();
1524 contents->SetBlendMode(blend_mode);
1526 contents->SetGeometry(vertices);
1527 contents->SetEffectTransform(effect_transform);
1528 contents->SetTexture(texture);
1529 contents->SetTileMode(x_tile_mode, y_tile_mode);
1530 contents->SetSamplerDescriptor(sampler_descriptor);
1533 AddRenderEntityToCurrentPass(entity);
1537 auto src_paint = paint;
1540 std::shared_ptr<ColorSourceContents> src_contents =
1541 src_paint.CreateContents(renderer_, vertices.get());
1549 auto size = src_contents->GetColorSourceSize();
1550 if (size.has_value()) {
1553 auto cvg = vertices->GetCoverage(
Matrix{});
1554 FML_CHECK(cvg.has_value());
1555 auto texture_coverage = vertices->GetTextureCoordinateCoverage();
1556 if (texture_coverage.has_value()) {
1559 texture_coverage->GetSize().Max({1, 1}));
1562 src_coverage = cvg.value();
1567 src_paint.CreateContents(renderer_, clip_geometry_.back().get());
1569 auto contents = std::make_shared<VerticesSimpleBlendContents>();
1570 contents->SetBlendMode(blend_mode);
1572 contents->SetGeometry(vertices);
1573 contents->SetLazyTextureCoverage(src_coverage);
1574 contents->SetLazyTexture(
1575 [src_contents, src_coverage](
1580 auto snapshot = src_contents->RenderToSnapshot(
1581 renderer, {}, {.coverage_limit =
Rect::Round(src_coverage)});
1582 return snapshot.has_value() ? snapshot->texture :
nullptr;
1585 AddRenderEntityToCurrentPass(entity);
1589 const Paint& paint) {
1597 AddRenderEntityToCurrentPass(entity);
1603 void Canvas::SetupRenderPass() {
1609 if (!stencil_attachment.has_value() || !depth_attachment.has_value()) {
1614 *renderer_.
GetContext()->GetResourceAllocator(),
1616 renderer_.
GetContext()->GetCapabilities()->SupportsOffscreenMSAA() &&
1617 color0.
texture->GetTextureDescriptor().sample_count >
1619 "ImpellerOnscreen", kDefaultStencilConfig);
1631 if (requires_readback_) {
1632 auto entity_pass_target =
1633 CreateRenderTarget(renderer_,
1636 render_passes_.push_back(
1637 LazyRenderingConfig(renderer_, std::move(entity_pass_target)));
1639 auto entity_pass_target = std::make_unique<EntityPassTarget>(
1644 render_passes_.push_back(
1645 LazyRenderingConfig(renderer_, std::move(entity_pass_target)));
1649 void Canvas::SkipUntilMatchingRestore(
size_t total_content_depth) {
1650 auto entry = CanvasStackEntry{};
1651 entry.skipping =
true;
1652 entry.clip_depth = current_depth_ + total_content_depth;
1653 transform_stack_.push_back(entry);
1658 return SkipUntilMatchingRestore(total_content_depth);
1662 entry.
transform = transform_stack_.back().transform;
1663 entry.clip_depth = current_depth_ + total_content_depth;
1664 entry.distributed_opacity = transform_stack_.back().distributed_opacity;
1665 FML_DCHECK(entry.clip_depth <= transform_stack_.back().clip_depth)
1666 << entry.clip_depth <<
" <=? " << transform_stack_.back().clip_depth
1667 <<
" after allocating " << total_content_depth;
1668 entry.clip_height = transform_stack_.back().clip_height;
1670 transform_stack_.push_back(entry);
1677 return std::nullopt;
1680 std::optional<Rect> maybe_current_clip_coverage =
1682 if (!maybe_current_clip_coverage.has_value()) {
1683 return std::nullopt;
1686 Rect current_clip_coverage = maybe_current_clip_coverage.value();
1688 FML_CHECK(!render_passes_.empty());
1690 std::shared_ptr<Texture> back_texture =
1692 FML_CHECK(back_texture) <<
"Context is valid:"
1697 std::optional<Rect> maybe_coverage_limit =
1699 Size(back_texture->GetSize()))
1702 if (!maybe_coverage_limit.has_value() || maybe_coverage_limit->IsEmpty()) {
1703 return std::nullopt;
1706 return maybe_coverage_limit->Intersection(
1711 std::optional<Rect> bounds,
1712 const flutter::DlImageFilter* backdrop_filter,
1714 uint32_t total_content_depth,
1715 bool can_distribute_opacity,
1716 std::optional<int64_t> backdrop_id) {
1717 TRACE_EVENT0(
"flutter",
"Canvas::saveLayer");
1719 return SkipUntilMatchingRestore(total_content_depth);
1723 if (!maybe_coverage_limit.has_value()) {
1724 return SkipUntilMatchingRestore(total_content_depth);
1726 auto coverage_limit = maybe_coverage_limit.value();
1728 if (can_distribute_opacity && !backdrop_filter &&
1731 Save(total_content_depth);
1732 transform_stack_.back().distributed_opacity *= paint.
color.
alpha;
1736 std::shared_ptr<FilterContents> filter_contents = paint.
WithImageFilter(
1737 renderer_,
Rect(), transform_stack_.back().transform,
1742 transform_stack_.back().transform,
1747 !!backdrop_filter ||
1752 if (!maybe_subpass_coverage.has_value()) {
1753 return SkipUntilMatchingRestore(total_content_depth);
1756 auto subpass_coverage = maybe_subpass_coverage.value();
1767 bool did_round_out =
false;
1768 Point coverage_origin_adjustment =
Point{0, 0};
1772 did_round_out =
true;
1776 coverage_origin_adjustment =
1777 Point(subpass_coverage.GetLeftTop().x -
1778 std::floor(subpass_coverage.GetLeftTop().x),
1779 subpass_coverage.GetLeftTop().y -
1780 std::floor(subpass_coverage.GetLeftTop().y));
1783 return SkipUntilMatchingRestore(total_content_depth);
1791 ->GetMaximumRenderPassAttachmentSize());
1794 std::shared_ptr<FilterContents> backdrop_filter_contents;
1796 if (backdrop_filter) {
1797 local_position = subpass_coverage.GetOrigin() - GetGlobalPassPosition();
1799 std::shared_ptr<Texture> input_texture;
1804 bool will_cache_backdrop_texture =
false;
1809 size_t backdrop_count = 1;
1810 if (backdrop_id.has_value()) {
1811 std::unordered_map<int64_t, BackdropData>::iterator backdrop_data_it =
1812 backdrop_data_.find(backdrop_id.value());
1813 if (backdrop_data_it != backdrop_data_.end()) {
1814 backdrop_data = &backdrop_data_it->second;
1815 will_cache_backdrop_texture =
1817 backdrop_count = backdrop_data_it->second.backdrop_count;
1821 if (!will_cache_backdrop_texture || !backdrop_data->
texture_slot) {
1822 backdrop_count_ -= backdrop_count;
1828 const bool should_use_onscreen =
1830 backdrop_count_ == 0 && render_passes_.size() == 1u;
1831 input_texture = FlipBackdrop(
1832 GetGlobalPassPosition(),
1833 will_cache_backdrop_texture,
1836 if (!input_texture) {
1841 if (will_cache_backdrop_texture) {
1848 backdrop_filter_contents =
1851 backdrop_filter_contents->SetEffectTransform(
1852 transform_stack_.back().transform.Basis());
1853 backdrop_filter_contents->SetRenderingMode(
1854 transform_stack_.back().transform.HasTranslation()
1858 if (will_cache_backdrop_texture) {
1859 FML_DCHECK(backdrop_data);
1866 backdrop_filter_contents->RenderToSnapshot(renderer_, {}, {});
1869 std::optional<Snapshot> maybe_snapshot =
1871 if (maybe_snapshot.has_value()) {
1872 const Snapshot& snapshot = maybe_snapshot.value();
1874 subpass_coverage.Shift(-GetGlobalPassPosition()));
1877 contents->SetTexture(snapshot.
texture);
1878 contents->SetSourceRect(scaled);
1888 backdrop_entity.
Render(renderer_, GetCurrentRenderPass());
1896 Paint paint_copy = paint;
1897 paint_copy.
color.
alpha *= transform_stack_.back().distributed_opacity;
1898 transform_stack_.back().distributed_opacity = 1.0;
1900 render_passes_.push_back(
1902 CreateRenderTarget(renderer_,
1907 paint_copy, subpass_coverage.Shift(-coverage_origin_adjustment)});
1910 entry.
transform = transform_stack_.back().transform;
1911 entry.
clip_depth = current_depth_ + total_content_depth;
1912 FML_DCHECK(entry.
clip_depth <= transform_stack_.back().clip_depth)
1913 << entry.
clip_depth <<
" <=? " << transform_stack_.back().clip_depth
1914 <<
" after allocating " << total_content_depth;
1915 entry.
clip_height = transform_stack_.back().clip_height;
1918 transform_stack_.emplace_back(entry);
1925 clip_coverage_stack_.
PushSubpass(subpass_coverage, GetClipHeight());
1927 if (!backdrop_filter_contents) {
1933 backdrop_entity.
SetContents(std::move(backdrop_filter_contents));
1936 backdrop_entity.
SetClipDepth(std::numeric_limits<uint32_t>::max());
1937 backdrop_entity.
Render(renderer_, GetCurrentRenderPass());
1941 FML_DCHECK(transform_stack_.size() > 0);
1942 if (transform_stack_.size() == 1) {
1959 FML_DCHECK(current_depth_ <= transform_stack_.back().clip_depth)
1960 << current_depth_ <<
" <=? " << transform_stack_.back().clip_depth;
1961 current_depth_ = transform_stack_.back().clip_depth;
1964 transform_stack_.pop_back();
1968 if (transform_stack_.back().rendering_mode ==
1970 transform_stack_.back().rendering_mode ==
1972 auto lazy_render_pass = std::move(render_passes_.back());
1973 render_passes_.pop_back();
1975 lazy_render_pass.GetInlinePassContext()->GetRenderPass();
1978 save_layer_state_.pop_back();
1979 auto global_pass_position = GetGlobalPassPosition();
1981 std::shared_ptr<Contents> contents = CreateContentsForSubpassTarget(
1982 renderer_, save_layer_state.
paint,
1983 lazy_render_pass.GetInlinePassContext()->GetTexture(),
1985 transform_stack_.back().transform
1988 lazy_render_pass.GetInlinePassContext()->EndPass();
1995 Point subpass_texture_position;
1996 if (transform_stack_.back().did_round_out) {
1999 subpass_texture_position =
2004 subpass_texture_position =
2018 ApplyFramebufferBlend(element_entity);
2029 auto input_texture = FlipBackdrop(GetGlobalPassPosition());
2030 if (!input_texture) {
2040 contents->SetCoverageHint(element_entity.
GetCoverage());
2048 *render_passes_.back().GetInlinePassContext()->GetRenderPass()
2051 transform_stack_.pop_back();
2059 size_t num_clips = transform_stack_.back().num_clips;
2060 transform_stack_.pop_back();
2062 if (num_clips > 0) {
2073 *render_passes_.back().GetInlinePassContext()->GetRenderPass(),
2074 GetGlobalPassPosition()
2082 bool Canvas::AttemptBlurredTextOptimization(
2083 const std::shared_ptr<TextFrame>& text_frame,
2084 const std::shared_ptr<TextContents>& text_contents,
2086 const Paint& paint) {
2100 std::shared_ptr<FilterContents> filter =
2105 std::optional<Glyph> maybe_glyph = text_frame->AsSingleGlyph();
2106 int64_t identifier = maybe_glyph.has_value()
2107 ? maybe_glyph.value().index
2108 :
reinterpret_cast<int64_t
>(text_frame.get());
2109 TextShadowCache::TextShadowCacheKey cache_key(
2112 maybe_glyph.has_value(),
2113 text_frame->GetFont(),
2118 renderer_, entity, filter, cache_key);
2119 if (result.has_value()) {
2120 AddRenderEntityToCurrentPass(result.value(),
false);
2134 const Paint& paint) {
2136 if (max_scale * text_frame->GetFont().GetMetrics().point_size >
2138 fml::StatusOr<flutter::DlPath> path = text_frame->GetPath();
2152 auto text_contents = std::make_shared<TextContents>();
2153 text_contents->SetTextFrame(text_frame);
2154 text_contents->SetPosition(position);
2157 text_contents->SetColor(paint.
color);
2158 text_contents->SetTextProperties(paint.
color, paint.
GetStroke());
2162 if (AttemptBlurredTextOptimization(text_frame, text_contents, entity,
2168 AddRenderEntityToCurrentPass(entity,
false);
2171 void Canvas::AddRenderSDFEntityToCurrentPass(
2175 const std::optional<Matrix>& shape_transform) {
2177 if (shape_transform.has_value()) {
2191 auto geometry = std::make_unique<UberSDFGeometry>(params);
2193 const Geometry* geom = contents->GetGeometry();
2198 std::shared_ptr<ColorSourceContents> color_source_contents =
2204 Paint new_paint = paint;
2206 AddRenderEntityWithFiltersToCurrentPass(entity, geom, new_paint,
2209 std::move(final_contents));
2211 AddRenderEntityWithFiltersToCurrentPass(entity, geom, paint, reuse_depth,
2213 std::move(contents));
2217 void Canvas::AddRenderEntityWithFiltersToCurrentPass(
2219 const Geometry* geometry,
2222 std::shared_ptr<Contents> override_contents) {
2223 std::shared_ptr<ColorSourceContents> color_source_contents;
2224 std::shared_ptr<Contents> contents;
2225 if (override_contents) {
2226 contents = std::move(override_contents);
2228 color_source_contents = paint.CreateContents(renderer_, geometry);
2229 contents = color_source_contents;
2232 if (!paint.color_filter && !paint.invert_colors && !paint.image_filter &&
2233 !paint.mask_blur_descriptor.has_value()) {
2234 entity.SetContents(std::move(contents));
2235 AddRenderEntityToCurrentPass(entity, reuse_depth);
2242 bool needs_color_filter = paint.color_filter || paint.invert_colors;
2243 if (needs_color_filter &&
2244 contents->ApplyColorFilter([&](Color color) -> Color {
2245 if (paint.color_filter) {
2246 color = GetCPUColorFilterProc(paint.color_filter)(color);
2248 if (paint.invert_colors) {
2249 color = color.ApplyColorMatrix(kColorInversion);
2253 needs_color_filter =
false;
2256 bool can_apply_mask_filter = geometry->CanApplyMaskFilter();
2258 if (can_apply_mask_filter && paint.mask_blur_descriptor.has_value()) {
2262 FML_DCHECK(color_source_contents) <<
"Mask blur is only supported when no "
2263 "override contents are provided.";
2264 FillRectGeometry out_rect(
Rect{});
2265 auto filter = paint.mask_blur_descriptor->CreateMaskBlur(
2266 paint, renderer_, geometry, color_source_contents, needs_color_filter,
2268 entity.SetContents(std::move(filter));
2269 AddRenderEntityToCurrentPass(entity, reuse_depth);
2273 std::shared_ptr<Contents> contents_copy = std::move(contents);
2277 if (needs_color_filter &&
2278 (!paint.color_source ||
2279 paint.color_source->type() != flutter::DlColorSourceType::kImage)) {
2280 if (paint.color_filter) {
2285 if (paint.invert_colors) {
2292 if (paint.image_filter) {
2293 std::shared_ptr<FilterContents> filter =
2294 WrapInput(renderer_, paint.image_filter,
2297 entity.SetContents(filter);
2298 AddRenderEntityToCurrentPass(entity, reuse_depth);
2302 entity.SetContents(std::move(contents_copy));
2303 AddRenderEntityToCurrentPass(entity, reuse_depth);
2306 void Canvas::AddRenderEntityToCurrentPass(Entity& entity,
bool reuse_depth) {
2311 entity.SetTransform(
2312 Matrix::MakeTranslation(Vector3(-GetGlobalPassPosition())) *
2313 entity.GetTransform());
2314 entity.SetInheritedOpacity(transform_stack_.back().distributed_opacity);
2315 if (entity.GetBlendMode() == BlendMode::kSrcOver &&
2316 entity.GetContents()->IsOpaque(entity.GetTransform())) {
2317 entity.SetBlendMode(BlendMode::kSrc);
2323 if (render_passes_.back().IsApplyingClearColor()) {
2324 std::optional<Color> maybe_color = entity.AsBackgroundColor(
2325 render_passes_.back().GetInlinePassContext()->GetTexture()->GetSize());
2326 if (maybe_color.has_value()) {
2327 Color color = maybe_color.value();
2328 RenderTarget& render_target = render_passes_.back()
2329 .GetInlinePassContext()
2332 ColorAttachment attachment = render_target.GetColorAttachment(0);
2335 attachment.clear_color = attachment.clear_color.Unpremultiply()
2336 .Blend(color, entity.GetBlendMode())
2338 render_target.SetColorAttachment(attachment, 0u);
2349 FML_DCHECK(current_depth_ <= transform_stack_.back().clip_depth)
2350 << current_depth_ <<
" <=? " << transform_stack_.back().clip_depth;
2351 entity.SetClipDepth(current_depth_);
2353 if (entity.GetBlendMode() > Entity::kLastPipelineBlendMode) {
2354 if (renderer_.GetDeviceCapabilities().SupportsFramebufferFetch()) {
2355 ApplyFramebufferBlend(entity);
2366 auto input_texture = FlipBackdrop(GetGlobalPassPosition(),
2370 if (!input_texture) {
2378 auto element_coverage_hint = entity.GetContents()->GetCoverageHint();
2379 entity.GetContents()->SetCoverageHint(Rect::Intersection(
2380 element_coverage_hint, clip_coverage_stack_.CurrentClipCoverage()));
2382 FilterInput::Vector inputs = {
2383 FilterInput::Make(input_texture, entity.GetTransform().Invert()),
2384 FilterInput::Make(entity.GetContents())};
2386 ColorFilterContents::MakeBlend(entity.GetBlendMode(), inputs);
2387 entity.SetContents(std::move(contents));
2388 entity.SetBlendMode(BlendMode::kSrc);
2392 const std::shared_ptr<RenderPass>& result =
2393 render_passes_.back().GetInlinePassContext()->GetRenderPass();
2401 entity.Render(renderer_, *result);
2404 RenderPass& Canvas::GetCurrentRenderPass()
const {
2405 return *render_passes_.back().GetInlinePassContext()->GetRenderPass();
2408 void Canvas::SetBackdropData(
2409 std::unordered_map<int64_t, BackdropData> backdrop_data,
2410 size_t backdrop_count) {
2411 backdrop_data_ = std::move(backdrop_data);
2412 backdrop_count_ = backdrop_count;
2415 std::shared_ptr<Texture> Canvas::FlipBackdrop(
Point global_pass_position,
2416 bool should_remove_texture,
2417 bool should_use_onscreen,
2418 bool post_depth_increment) {
2420 render_passes_.pop_back();
2436 <<
"Failed to end the current render pass in order to read from "
2437 "the backdrop texture and apply an advanced blend or backdrop "
2442 render_passes_.emplace_back(std::move(rendering_config));
2446 const std::shared_ptr<Texture>& input_texture =
2449 if (!input_texture) {
2450 VALIDATION_LOG <<
"Failed to fetch the color texture in order to "
2451 "apply an advanced blend or backdrop filter.";
2454 render_passes_.emplace_back(std::move(rendering_config));
2458 if (should_use_onscreen) {
2459 ColorAttachment color0 = render_target_.GetColorAttachment(0);
2463 color0.
load_action = color0.resolve_texture !=
nullptr
2464 ? LoadAction::kDontCare
2465 : LoadAction::kLoad;
2466 render_target_.SetColorAttachment(color0, 0);
2468 auto entity_pass_target = std::make_unique<EntityPassTarget>(
2470 renderer_.GetDeviceCapabilities().SupportsReadFromResolve(),
2471 renderer_.GetDeviceCapabilities().SupportsImplicitResolvingMSAA()
2473 render_passes_.push_back(
2474 LazyRenderingConfig(renderer_, std::move(entity_pass_target)));
2475 requires_readback_ =
false;
2477 render_passes_.emplace_back(std::move(rendering_config));
2480 if (should_remove_texture) {
2481 render_passes_.back().GetEntityPassTarget()->RemoveSecondary();
2484 RenderPass& current_render_pass =
2485 *render_passes_.back().GetInlinePassContext()->GetRenderPass();
2494 Rect size_rect = Rect::MakeSize(input_texture->GetSize());
2495 auto msaa_backdrop_contents = TextureContents::MakeRect(size_rect);
2496 msaa_backdrop_contents->SetStencilEnabled(
false);
2497 msaa_backdrop_contents->SetLabel(
"MSAA backdrop");
2498 msaa_backdrop_contents->SetSourceRect(size_rect);
2499 msaa_backdrop_contents->SetTexture(input_texture);
2501 Entity msaa_backdrop_entity;
2502 msaa_backdrop_entity.SetContents(std::move(msaa_backdrop_contents));
2503 msaa_backdrop_entity.SetBlendMode(BlendMode::kSrc);
2504 msaa_backdrop_entity.SetClipDepth(std::numeric_limits<uint32_t>::max());
2505 if (!msaa_backdrop_entity.Render(renderer_, current_render_pass)) {
2512 auto& replay_entities = clip_coverage_stack_.GetReplayEntities();
2513 uint64_t current_depth =
2514 post_depth_increment ? current_depth_ - 1 : current_depth_;
2515 for (
const auto& replay : replay_entities) {
2516 if (replay.clip_depth <= current_depth) {
2520 SetClipScissor(replay.clip_coverage, current_render_pass,
2521 global_pass_position);
2522 if (!replay.clip_contents.Render(renderer_, current_render_pass,
2523 replay.clip_depth)) {
2528 return input_texture;
2531 bool Canvas::SupportsBlitToOnscreen()
const {
2532 return renderer_.GetContext()
2534 ->SupportsTextureToTextureBlits() &&
2535 renderer_.GetContext()->GetBackendType() ==
2536 Context::BackendType::kMetal;
2539 bool Canvas::BlitToOnscreen(
bool is_onscreen) {
2540 auto command_buffer = renderer_.GetContext()->CreateCommandBuffer();
2542 auto offscreen_target = render_passes_.back()
2543 .GetInlinePassContext()
2546 if (SupportsBlitToOnscreen()) {
2548 blit_pass->AddCopy(offscreen_target.GetRenderTargetTexture(),
2549 render_target_.GetRenderTargetTexture());
2550 if (!blit_pass->EncodeCommands()) {
2556 render_pass->SetLabel(
"EntityPass Root Render Pass");
2559 auto size_rect = Rect::MakeSize(offscreen_target.GetRenderTargetSize());
2560 auto contents = TextureContents::MakeRect(size_rect);
2561 contents->SetTexture(offscreen_target.GetRenderTargetTexture());
2562 contents->SetSourceRect(size_rect);
2563 contents->SetLabel(
"Root pass blit");
2566 entity.SetContents(contents);
2567 entity.SetBlendMode(BlendMode::kSrc);
2582 return renderer_.GetContext()->SubmitOnscreen(std::move(
command_buffer));
2584 return renderer_.GetContext()->EnqueueCommandBuffer(
2589 bool Canvas::EnsureFinalMipmapGeneration()
const {
2590 if (!render_target_.GetRenderTargetTexture()->NeedsMipmapGeneration()) {
2593 std::shared_ptr<CommandBuffer> cmd_buffer =
2594 renderer_.GetContext()->CreateCommandBuffer();
2598 std::shared_ptr<BlitPass> blit_pass = cmd_buffer->CreateBlitPass();
2602 blit_pass->GenerateMipmap(render_target_.GetRenderTargetTexture());
2603 blit_pass->EncodeCommands();
2604 return renderer_.GetContext()->EnqueueCommandBuffer(std::move(cmd_buffer));
2607 void Canvas::EndReplay() {
2608 FML_DCHECK(render_passes_.size() == 1u);
2609 render_passes_.back().GetInlinePassContext()->GetRenderPass();
2610 render_passes_.back().GetInlinePassContext()->EndPass(
2611 !requires_readback_ && is_onscreen_);
2612 backdrop_data_.clear();
2617 if (requires_readback_) {
2618 BlitToOnscreen(is_onscreen_);
2620 if (!EnsureFinalMipmapGeneration()) {
2623 if (!renderer_.GetContext()->FlushCommandBuffers()) {
2627 render_passes_.clear();
2628 renderer_.GetRenderTargetCache()->End();
2629 clip_geometry_.clear();
2632 Initialize(initial_cull_rect_);
2635 bool Canvas::IsCompatibleWithSDFRendering(
const Paint& paint) {
2644 case BlendMode::kClear:
2645 case BlendMode::kSrc:
2646 case BlendMode::kSrcIn:
2647 case BlendMode::kDstIn:
2648 case BlendMode::kSrcOut:
2649 case BlendMode::kDstATop:
2650 case BlendMode::kPlus:
2651 case BlendMode::kModulate:
2654 case BlendMode::kDst:
2655 case BlendMode::kSrcOver:
2656 case BlendMode::kDstOver:
2657 case BlendMode::kDstOut:
2658 case BlendMode::kSrcATop:
2659 case BlendMode::kXor:
2660 case BlendMode::kScreen:
2661 case BlendMode::kOverlay:
2662 case BlendMode::kDarken:
2663 case BlendMode::kLighten:
2664 case BlendMode::kColorDodge:
2665 case BlendMode::kColorBurn:
2666 case BlendMode::kHardLight:
2667 case BlendMode::kSoftLight:
2668 case BlendMode::kDifference:
2669 case BlendMode::kExclusion:
2670 case BlendMode::kMultiply:
2671 case BlendMode::kHue:
2672 case BlendMode::kSaturation:
2673 case BlendMode::kColor:
2674 case BlendMode::kLuminosity:
2679 LazyRenderingConfig::LazyRenderingConfig(
2681 std::unique_ptr<EntityPassTarget> p_entity_pass_target)
2682 : entity_pass_target_(
std::move(p_entity_pass_target)) {
2683 inline_pass_context_ =
2684 std::make_unique<InlinePassContext>(renderer, *entity_pass_target_);
2688 return !inline_pass_context_->IsActive();
2692 return entity_pass_target_.get();
2696 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)
static bool IsCompatibleWithSDFRendering(const Paint &paint)
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)
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.
static std::unique_ptr< ComplexRoundedSuperellipseContents > Make(Color color, const Rect &bounds, const RoundSuperellipseParam &round_superellipse_params, std::optional< StrokeParameters > stroke)
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| ...
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
The coverage rectangle of this geometry, transformed by the transform argument.
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
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 > Make(const UberSDFParameters ¶ms, std::unique_ptr< Geometry > 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.
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)
std::shared_ptr< FilterContents > WrapInput(const ContentContext &renderer, const flutter::DlImageFilter *filter, const FilterInput::Ref &input)
Generate a new FilterContents using this filter's configuration.
@ 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)
std::shared_ptr< ContextGLES > context
std::shared_ptr< RenderPass > render_pass
std::shared_ptr< CommandBuffer > command_buffer
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 MakeColumn(Scalar m0, Scalar m1, Scalar m2, Scalar m3, Scalar m4, Scalar m5, Scalar m6, Scalar m7, Scalar m8, Scalar m9, Scalar m10, Scalar m11, Scalar m12, Scalar m13, Scalar m14, Scalar m15)
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< FilterContents > WithImageFilter(const ContentContext &renderer, const FilterInput::Variant &input, const Matrix &effect_transform, Entity::RenderingMode rendering_mode) const
std::optional< StrokeParameters > GetStroke() const
Return an optional StrokeParameters if this Paint is a stroked Paint, otherwise return a nullopt.
const flutter::DlColorFilter * color_filter
const flutter::DlColorSource * color_source
const flutter::DlImageFilter * image_filter
std::shared_ptr< Contents > WithFilters(const ContentContext &renderer, std::shared_ptr< Contents > input) const
Wrap this paint's configured filters to the given contents.
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< ColorSourceContents > CreateContents(const ContentContext &renderer, const Geometry *geometry, const std::optional< Matrix > &geometry_transform=std::nullopt) const
Create a ColorSourceContents representing this paint's shader/colors.
bool HasColorFilter() const
Whether this paint has a color filter that can apply opacity.
constexpr const RoundingRadii & GetRadii() const
constexpr bool IsEmpty() const
constexpr const Rect & GetBounds() const
constexpr const RoundingRadii & GetRadii() const
constexpr const Rect & GetBounds() const
static RoundSuperellipseParam MakeBoundsRadii(const Rect &bounds, const RoundingRadii &radii)
constexpr bool AreAllCornersCircular() const
constexpr bool AreAllCornersSame(Scalar tolerance=kEhCloseEnough) const
constexpr static RoundingRadii MakeRadius(Scalar radius)
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 TPoint PerpendicularRight() 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 static TRect MakeCircleBounds(const TPoint< Type > ¢er, Type radius)
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 MakeEllipseBounds(const TPoint< Type > ¢er, const TSize< Type > &radii)
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.
Parameters for rendering shapes using the UberSDF shader.
Color color
The color used for filling or stroking the shape.
static UberSDFParameters MakeCircle(Color color, const Point ¢er, Scalar radius, std::optional< StrokeParameters > stroke)
Creates UberSDFParameters for a circle.
static UberSDFParameters MakeOval(Color color, const Rect &bounds, std::optional< StrokeParameters > stroke)
Creates UberSDFParameters for an Oval.
static UberSDFParameters MakeRoundedRect(Color color, const Rect &rect, const RoundingRadii &radii, std::optional< StrokeParameters > stroke)
Creates UberSDFParameters for a rounded rectangle.
static UberSDFParameters MakeRoundedSuperellipse(Color color, const Rect &bounds, const RoundSuperellipseParam &round_superellipse_params, std::optional< StrokeParameters > stroke)
Creates UberSDFParameters for an asymmetric round superellipse.
static UberSDFParameters MakeRect(Color color, const Rect &rect, std::optional< StrokeParameters > stroke)
Creates UberSDFParameters for a rectangle.
std::vector< Point > points