9#include <unordered_map>
73constexpr Scalar kAntialiasPadding = 1.0f;
81static bool UseColorSourceContents(
82 const std::shared_ptr<VerticesGeometry>& vertices,
86 if (vertices->HasVertexColors()) {
89 if (vertices->HasTextureCoordinates() && !paint.color_source) {
92 return !vertices->HasTextureCoordinates();
95static void SetClipScissor(std::optional<Rect> clip_coverage,
97 Point global_pass_position) {
101 if (clip_coverage.has_value()) {
102 clip_coverage = clip_coverage->Shift(-global_pass_position);
109 pass.SetScissor(scissor);
112static void ApplyFramebufferBlend(Entity& entity) {
113 auto src_contents = entity.GetContents();
114 auto contents = std::make_shared<FramebufferBlendContents>();
115 contents->SetChildContents(src_contents);
116 contents->SetBlendMode(entity.GetBlendMode());
117 entity.SetContents(std::move(contents));
123static std::shared_ptr<Contents> CreateContentsForSubpassTarget(
124 const ContentContext& renderer,
126 const std::shared_ptr<Texture>&
target,
127 const Matrix& effect_transform) {
129 contents->SetTexture(
target);
130 contents->SetLabel(
"Subpass");
132 contents->SetOpacity(paint.color.alpha);
133 contents->SetDeferApplyingOpacity(
true);
135 return paint.WithFiltersForSubpassTarget(renderer, std::move(contents),
139static const constexpr RenderTarget::AttachmentConfig kDefaultStencilConfig =
140 RenderTarget::AttachmentConfig{
146static std::unique_ptr<EntityPassTarget> CreateRenderTarget(
147 ContentContext& renderer,
149 const Color& clear_color) {
150 const std::shared_ptr<Context>&
context = renderer.GetContext();
158 if (
context->GetCapabilities()->SupportsOffscreenMSAA()) {
159 target = renderer.GetRenderTargetCache()->CreateOffscreenMSAA(
165 RenderTarget::AttachmentConfigMSAA{
170 .clear_color = clear_color},
171 kDefaultStencilConfig);
173 target = renderer.GetRenderTargetCache()->CreateOffscreen(
178 RenderTarget::AttachmentConfig{
182 .clear_color = clear_color,
184 kDefaultStencilConfig
188 return std::make_unique<EntityPassTarget>(
190 renderer.GetDeviceCapabilities().SupportsReadFromResolve(),
191 renderer.GetDeviceCapabilities().SupportsImplicitResolvingMSAA()
202static std::pair<Rect, Color> ExpandRectToPixelMinimum(
const Rect& rect,
206 std::optional<Rect> expanded =
207 rect.ExpandToMinTransformedSize({1.0f, 1.0f},
transform);
210 return {
Rect(), color};
215 return {expanded.value(), color};
219 Scalar alpha_scaling = rect.
Area() / expanded->Area();
222 return {
Rect(), color};
224 return {expanded.value(), color.WithAlpha(color.alpha * alpha_scaling)};
232 : rect_(rect), corner_radius_(corner_radius) {}
237 auto contents = std::make_shared<SolidRRectBlurContents>();
238 contents->SetSigma(sigma);
239 contents->SetShape(rect_, corner_radius_);
244 return geom_.emplace(rect_,
Size(corner_radius_));
249 const Scalar corner_radius_;
251 std::optional<RoundRectGeometry> geom_;
257 : rect_(rect), corner_radius_(corner_radius) {}
262 auto contents = std::make_shared<SolidRSuperellipseBlurContents>();
263 contents->SetSigma(sigma);
264 contents->SetShape(rect_, corner_radius_);
269 return geom_.emplace(rect_, corner_radius_);
274 const Scalar corner_radius_;
276 std::optional<RoundSuperellipseGeometry> geom_;
296 std::shared_ptr<ShadowVertices> shadow_vertices,
300 shadow_vertices_(
std::move(shadow_vertices)) {}
303 return shadow_vertices_->GetBounds().value_or(
Rect());
317 return source_geometry_.emplace(source_);
323 const std::shared_ptr<ShadowVertices> shadow_vertices_;
326 std::optional<FillPathFromSourceGeometry> source_geometry_;
332 bool requires_readback)
333 : renderer_(renderer),
334 render_target_(render_target),
335 is_onscreen_(is_onscreen),
336 requires_readback_(requires_readback),
338 Rect::MakeSize(render_target.GetRenderTargetSize()))) {
339 Initialize(std::nullopt);
346 bool requires_readback,
348 : renderer_(renderer),
349 render_target_(render_target),
350 is_onscreen_(is_onscreen),
351 requires_readback_(requires_readback),
353 Rect::MakeSize(render_target.GetRenderTargetSize()))) {
354 Initialize(cull_rect);
361 bool requires_readback,
363 : renderer_(renderer),
364 render_target_(render_target),
365 is_onscreen_(is_onscreen),
366 requires_readback_(requires_readback),
368 Rect::MakeSize(render_target.GetRenderTargetSize()))) {
374void Canvas::Initialize(std::optional<Rect> cull_rect) {
375 initial_cull_rect_ = cull_rect;
382void Canvas::Reset() {
384 transform_stack_ = {};
396 transform_stack_.back().transform = {};
404 return transform_stack_.back().transform;
427Point Canvas::GetGlobalPassPosition()
const {
428 if (save_layer_state_.empty()) {
431 return save_layer_state_.back().coverage.GetOrigin();
435size_t Canvas::GetClipHeightFloor()
const {
436 if (transform_stack_.size() > 1) {
437 return transform_stack_[transform_stack_.size() - 2].clip_height;
443 return transform_stack_.size();
446bool Canvas::IsSkipping()
const {
447 return transform_stack_.back().skipping;
459 if (IsShadowBlurDrawOperation(paint)) {
460 if (AttemptDrawBlurredPathSource(path, paint)) {
471 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
474 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
484 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
491bool Canvas::AttemptColorFilterOptimization(
492 const std::shared_ptr<Texture>&
image,
509 DrawImageRectAtlasGeometry geometry = DrawImageRectAtlasGeometry(
514 blend_filter->
mode(),
516 src_rect_constraint ==
519 auto atlas_contents = std::make_shared<AtlasContents>();
520 atlas_contents->SetGeometry(&geometry);
526 entity.SetContents(atlas_contents);
528 AddRenderEntityToCurrentPass(entity);
539 DrawImageRectAtlasGeometry geometry = DrawImageRectAtlasGeometry(
546 src_rect_constraint ==
549 auto atlas_contents = std::make_shared<ColorFilterAtlasContents>();
550 atlas_contents->SetGeometry(&geometry);
554 atlas_contents->SetMatrix(color_matrix);
559 entity.SetContents(atlas_contents);
561 AddRenderEntityToCurrentPass(entity);
566bool Canvas::AttemptDrawAntialiasedCircle(
const Point& center,
568 const Paint& paint) {
569 if (paint.HasColorFilter() || paint.image_filter || paint.invert_colors ||
570 paint.color_source || paint.mask_blur_descriptor.has_value()) {
576 entity.SetBlendMode(paint.blend_mode);
579 std::unique_ptr<CircleGeometry> geom;
581 geom = std::make_unique<CircleGeometry>(center, radius, paint.stroke.width);
583 geom = std::make_unique<CircleGeometry>(center, radius);
585 geom->SetAntialiasPadding(kAntialiasPadding);
589 entity.SetContents(std::move(contents));
590 AddRenderEntityToCurrentPass(entity);
595bool Canvas::IsShadowBlurDrawOperation(
const Paint& paint) {
600 if (paint.color_source) {
604 if (!paint.mask_blur_descriptor.has_value()) {
615 Radius radius = paint.mask_blur_descriptor->sigma;
623bool Canvas::AttemptDrawBlurredPathSource(
const PathSource& source,
624 const Paint& paint) {
631 if (paint.mask_blur_descriptor.has_value()) {
635 static constexpr Scalar kSigmaScale = 2.8f;
637 Sigma sigma = paint.mask_blur_descriptor->sigma;
639 Scalar basis_scale = matrix.GetMaxBasisLengthXY();
640 Scalar device_radius = sigma.sigma * kSigmaScale * basis_scale;
641 std::shared_ptr<ShadowVertices> shadow_vertices =
644 if (shadow_vertices) {
645 PathBlurShape shape(source, std::move(shadow_vertices), sigma);
646 return AttemptDrawBlur(shape, paint);
652Scalar Canvas::GetCommonRRectLikeRadius(
const RoundingRadii& radii) {
653 if (!radii.AreAllCornersSame()) {
656 const Size& corner_radii = radii.top_left;
658 return corner_radii.
width;
663bool Canvas::AttemptDrawBlurredRRect(
const RoundRect& round_rect,
664 const Paint& paint) {
665 Scalar radius = GetCommonRRectLikeRadius(round_rect.GetRadii());
667 RoundRectPathSource source(round_rect);
668 return AttemptDrawBlurredPathSource(source, paint);
670 RRectBlurShape shape(round_rect.GetBounds(), radius);
671 return AttemptDrawBlur(shape, paint);
674bool Canvas::AttemptDrawBlurredRSuperellipse(
const RoundSuperellipse& rse,
675 const Paint& paint) {
676 Scalar radius = GetCommonRRectLikeRadius(rse.GetRadii());
678 RoundSuperellipsePathSource source(rse);
679 return AttemptDrawBlurredPathSource(source, paint);
681 RSuperellipseBlurShape shape(rse.GetBounds(), radius);
682 return AttemptDrawBlur(shape, paint);
685bool Canvas::AttemptDrawBlur(BlurShape& shape,
const Paint& paint) {
690 Color rrect_color = paint.color;
691 if (paint.invert_colors) {
694 if (paint.color_filter) {
698 Paint rrect_paint = {.mask_blur_descriptor = paint.mask_blur_descriptor};
700 if (!rrect_paint.mask_blur_descriptor.has_value()) {
727 if ((paint.mask_blur_descriptor->style !=
729 paint.image_filter) ||
732 Rect render_bounds = shape.GetBounds();
733 if (paint.mask_blur_descriptor->style !=
736 render_bounds.
Expand(paint.mask_blur_descriptor->sigma.sigma * 4.0);
742 .image_filter = paint.image_filter,
743 .blend_mode = paint.blend_mode,
746 rrect_paint.color = rrect_color.WithAlpha(1);
748 rrect_paint.color = rrect_color;
749 rrect_paint.blend_mode = paint.blend_mode;
750 rrect_paint.image_filter = paint.image_filter;
754 auto draw_blurred_rrect = [
this, &rrect_paint, &shape]() {
755 std::shared_ptr<SolidBlurContents> contents =
756 shape.BuildBlurContent(rrect_paint.mask_blur_descriptor->sigma);
759 contents->SetColor(rrect_paint.color);
761 Entity blurred_rrect_entity;
763 blurred_rrect_entity.SetBlendMode(rrect_paint.blend_mode);
765 rrect_paint.mask_blur_descriptor = std::nullopt;
766 blurred_rrect_entity.SetContents(
767 rrect_paint.WithFilters(renderer_, std::move(contents)));
768 AddRenderEntityToCurrentPass(blurred_rrect_entity);
771 switch (rrect_paint.mask_blur_descriptor->style) {
773 draw_blurred_rrect();
778 draw_blurred_rrect();
782 entity.SetBlendMode(rrect_paint.blend_mode);
784 const Geometry& geom = shape.BuildDrawGeometry();
785 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, rrect_paint,
790 const Geometry& geom = shape.BuildDrawGeometry();
792 draw_blurred_rrect();
796 const Geometry& geom = shape.BuildDrawGeometry();
798 draw_blurred_rrect();
808bool Canvas::AttemptDrawLineSDF(
const Point& p0,
812 if (!renderer_.
GetContext()->GetFlags().use_sdfs ||
819 Paint rect_paint = paint;
822 Scalar line_length = p0.GetDistance(
p1);
823 if (line_length == 0.0f && paint.stroke.cap ==
Cap::kButt) {
827 Scalar half_stroke_width = paint.stroke.width * 0.5f;
828 Scalar half_length = line_length * 0.5f;
834 half_length += half_stroke_width;
839 Point(half_length, half_stroke_width));
846 line_length > 0.0f ? ((
p1 - p0) / line_length) :
Point(1.0f, 0.0f);
851 u.x, u.y, 0.0f, 0.0f,
853 perp.x, perp.y, 0.0f, 0.0f,
855 0.0f, 0.0f, 1.0f, 0.0f,
861 auto [expanded, alpha_scaled_color] = ExpandRectToPixelMinimum(
865 paint.stroke.width != 0.0f);
867 if (expanded.IsEmpty()) {
872 rect_paint.color = alpha_scaled_color;
890 AddRenderSDFEntityToCurrentPass(paint,
params, reuse_depth,
891 rect_to_line_transform);
899 if (AttemptDrawLineSDF(p0,
p1, paint, reuse_depth)) {
907 auto geometry = std::make_unique<LineGeometry>(p0,
p1, paint.
stroke);
909 AddRenderEntityWithFiltersToCurrentPass(entity, geometry.get(), paint,
917 const Paint& paint) {
927 if (
length > 0.0f && on_length >= 0.0f && off_length > 0.0f) {
933 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
944 if (IsShadowBlurDrawOperation(paint)) {
946 if (AttemptDrawBlur(shape, paint)) {
951 if (renderer_.
GetContext()->GetFlags().use_sdfs &&
953 Rect effective_rect = rect;
959 auto [expanded, alpha_scaled_color] = ExpandRectToPixelMinimum(
962 if (expanded.IsEmpty()) {
967 effective_rect = expanded;
968 effective_color = alpha_scaled_color;
975 AddRenderSDFEntityToCurrentPass(paint,
params);
985 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
988 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
1004 if (IsShadowBlurDrawOperation(paint)) {
1009 if (AttemptDrawBlur(shape, paint)) {
1014 if (AttemptDrawBlurredPathSource(source, paint)) {
1024 if (renderer_.
GetContext()->GetFlags().use_sdfs &&
1034 AddRenderSDFEntityToCurrentPass(paint,
params);
1040 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
1043 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
1054 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
1067 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
1080 return DrawOval(oval_bounds, paint);
1090 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
1096 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
1104 if (IsShadowBlurDrawOperation(paint)) {
1105 if (AttemptDrawBlurredRRect(round_rect, paint)) {
1112 if (renderer_.
GetContext()->GetFlags().use_sdfs &&
1120 auto [expanded, alpha_scaled_color] = ExpandRectToPixelMinimum(
1123 if (expanded.IsEmpty()) {
1129 effective_color = alpha_scaled_color;
1137 ? std::make_optional(paint.
stroke)
1139 AddRenderSDFEntityToCurrentPass(paint,
params);
1151 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
1161 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
1164 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
1170 const Paint& paint) {
1177 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
1180 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
1185 const Paint& paint) {
1186 if (IsShadowBlurDrawOperation(paint)) {
1187 if (AttemptDrawBlurredRSuperellipse(round_superellipse, paint)) {
1196 if (renderer_.
GetContext()->GetFlags().use_sdfs &&
1201 if (round_superellipse_params.all_corners_same) {
1205 round_superellipse_params,
1208 AddRenderSDFEntityToCurrentPass(paint,
params);
1214 round_superellipse_params,
1217 const Geometry* geom = contents->GetGeometry();
1220 std::shared_ptr<Contents> color_source_contents =
1222 std::shared_ptr<Contents> final_contents =
1227 Paint new_paint = paint;
1229 AddRenderEntityWithFiltersToCurrentPass(entity, geom, new_paint,
1232 std::move(final_contents));
1234 AddRenderEntityWithFiltersToCurrentPass(entity, geom, paint,
1237 std::move(contents));
1246 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
1249 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
1255 const Paint& paint) {
1256 if (IsShadowBlurDrawOperation(paint)) {
1259 if (AttemptDrawBlur(shape, paint)) {
1264 if (renderer_.
GetContext()->GetFlags().use_sdfs &&
1267 paint.
color, center, radius,
1269 AddRenderSDFEntityToCurrentPass(paint,
params);
1273 if (AttemptDrawAntialiasedCircle(center, radius, paint)) {
1283 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
1286 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
1307 FML_DCHECK(current_depth_ <= transform_stack_.back().clip_depth)
1308 << current_depth_ <<
" <=? " << transform_stack_.back().clip_depth;
1309 uint32_t clip_depth = transform_stack_.back().clip_depth;
1311 const Matrix clip_transform =
1315 std::optional<Rect> clip_coverage = geometry.
GetCoverage(clip_transform);
1316 if (!clip_coverage.has_value()) {
1321 clip_coverage.value(),
1330 GetGlobalPassPosition(),
1332 GetClipHeightFloor(),
1339 *render_passes_.back().GetInlinePassContext()->GetRenderPass(),
1340 GetGlobalPassPosition());
1343 ++transform_stack_.back().clip_height;
1344 ++transform_stack_.back().num_clips;
1361 *render_passes_.back().GetInlinePassContext()->GetRenderPass()
1368 renderer_, *render_passes_.back().GetInlinePassContext()->GetRenderPass(),
1387 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
1415 if (size.IsEmpty()) {
1419 std::optional<Rect> clipped_source =
1421 if (!clipped_source) {
1425 if (AttemptColorFilterOptimization(
image, source, dest, paint, sampler,
1426 src_rect_constraint)) {
1430 if (*clipped_source != source) {
1440 texture_contents->SetTexture(
image);
1441 texture_contents->SetSourceRect(*clipped_source);
1442 texture_contents->SetStrictSourceRect(src_rect_constraint ==
1444 texture_contents->SetSamplerDescriptor(sampler);
1445 texture_contents->SetOpacity(paint.
color.
alpha);
1446 texture_contents->SetDeferApplyingOpacity(paint.
HasColorFilter());
1454 paint.
WithFilters(renderer_, std::move(texture_contents)));
1455 AddRenderEntityToCurrentPass(entity);
1464 AddRenderEntityToCurrentPass(entity);
1467size_t Canvas::GetClipHeight()
const {
1468 return transform_stack_.back().clip_height;
1473 const Paint& paint) {
1486 if (UseColorSourceContents(vertices, paint)) {
1487 AddRenderEntityWithFiltersToCurrentPass(entity, vertices.get(), paint);
1493 auto contents = std::make_shared<VerticesSimpleBlendContents>();
1494 contents->SetBlendMode(blend_mode);
1496 contents->SetGeometry(vertices);
1498 AddRenderEntityToCurrentPass(entity);
1510 image_color_source->
image()->asImpellerImage()->GetCachedTexture(
1517 auto sampler_descriptor =
1519 auto effect_transform = image_color_source->
matrix();
1521 auto contents = std::make_shared<VerticesSimpleBlendContents>();
1522 contents->SetBlendMode(blend_mode);
1524 contents->SetGeometry(vertices);
1525 contents->SetEffectTransform(effect_transform);
1526 contents->SetTexture(
texture);
1527 contents->SetTileMode(x_tile_mode, y_tile_mode);
1528 contents->SetSamplerDescriptor(sampler_descriptor);
1531 AddRenderEntityToCurrentPass(entity);
1535 auto src_paint = paint;
1538 std::shared_ptr<ColorSourceContents> src_contents =
1539 src_paint.CreateContents(renderer_, vertices.get());
1547 auto size = src_contents->GetColorSourceSize();
1548 if (size.has_value()) {
1551 auto cvg = vertices->GetCoverage(
Matrix{});
1553 auto texture_coverage = vertices->GetTextureCoordinateCoverage();
1554 if (texture_coverage.has_value()) {
1557 texture_coverage->GetSize().Max({1, 1}));
1560 src_coverage = cvg.value();
1565 src_paint.CreateContents(renderer_, clip_geometry_.back().get());
1567 auto contents = std::make_shared<VerticesSimpleBlendContents>();
1568 contents->SetBlendMode(blend_mode);
1570 contents->SetGeometry(vertices);
1571 contents->SetLazyTextureCoverage(src_coverage);
1572 contents->SetLazyTexture(
1573 [src_contents, src_coverage](
1578 auto snapshot = src_contents->RenderToSnapshot(
1579 renderer, {}, {.coverage_limit =
Rect::Round(src_coverage)});
1580 return snapshot.has_value() ? snapshot->texture :
nullptr;
1583 AddRenderEntityToCurrentPass(entity);
1587 const Paint& paint) {
1595 AddRenderEntityToCurrentPass(entity);
1601void Canvas::SetupRenderPass() {
1607 if (!stencil_attachment.has_value() || !depth_attachment.has_value()) {
1612 *renderer_.
GetContext()->GetResourceAllocator(),
1614 renderer_.
GetContext()->GetCapabilities()->SupportsOffscreenMSAA() &&
1615 color0.
texture->GetTextureDescriptor().sample_count >
1617 "ImpellerOnscreen", kDefaultStencilConfig);
1629 if (requires_readback_) {
1630 auto entity_pass_target =
1631 CreateRenderTarget(renderer_,
1634 render_passes_.push_back(
1635 LazyRenderingConfig(renderer_, std::move(entity_pass_target)));
1637 auto entity_pass_target = std::make_unique<EntityPassTarget>(
1642 render_passes_.push_back(
1643 LazyRenderingConfig(renderer_, std::move(entity_pass_target)));
1647void Canvas::SkipUntilMatchingRestore(
size_t total_content_depth) {
1648 auto entry = CanvasStackEntry{};
1649 entry.skipping =
true;
1650 entry.clip_depth = current_depth_ + total_content_depth;
1651 transform_stack_.push_back(entry);
1656 return SkipUntilMatchingRestore(total_content_depth);
1660 entry.
transform = transform_stack_.back().transform;
1661 entry.clip_depth = current_depth_ + total_content_depth;
1662 entry.distributed_opacity = transform_stack_.back().distributed_opacity;
1663 FML_DCHECK(entry.clip_depth <= transform_stack_.back().clip_depth)
1664 << entry.clip_depth <<
" <=? " << transform_stack_.back().clip_depth
1665 <<
" after allocating " << total_content_depth;
1666 entry.clip_height = transform_stack_.back().clip_height;
1668 transform_stack_.push_back(entry);
1675 return std::nullopt;
1678 std::optional<Rect> maybe_current_clip_coverage =
1680 if (!maybe_current_clip_coverage.has_value()) {
1681 return std::nullopt;
1684 Rect current_clip_coverage = maybe_current_clip_coverage.value();
1688 std::shared_ptr<Texture> back_texture =
1690 FML_CHECK(back_texture) <<
"Context is valid:"
1695 std::optional<Rect> maybe_coverage_limit =
1697 Size(back_texture->GetSize()))
1700 if (!maybe_coverage_limit.has_value() || maybe_coverage_limit->IsEmpty()) {
1701 return std::nullopt;
1704 return maybe_coverage_limit->Intersection(
1709 std::optional<Rect> bounds,
1712 uint32_t total_content_depth,
1713 bool can_distribute_opacity,
1714 std::optional<int64_t> backdrop_id) {
1717 return SkipUntilMatchingRestore(total_content_depth);
1721 if (!maybe_coverage_limit.has_value()) {
1722 return SkipUntilMatchingRestore(total_content_depth);
1724 auto coverage_limit = maybe_coverage_limit.value();
1726 if (can_distribute_opacity && !backdrop_filter &&
1729 Save(total_content_depth);
1730 transform_stack_.back().distributed_opacity *= paint.
color.
alpha;
1734 std::shared_ptr<FilterContents> filter_contents = paint.
WithImageFilter(
1735 renderer_,
Rect(), transform_stack_.back().transform,
1740 transform_stack_.back().transform,
1745 !!backdrop_filter ||
1750 if (!maybe_subpass_coverage.has_value()) {
1751 return SkipUntilMatchingRestore(total_content_depth);
1754 auto subpass_coverage = maybe_subpass_coverage.value();
1765 bool did_round_out =
false;
1766 Point coverage_origin_adjustment =
Point{0, 0};
1770 did_round_out =
true;
1774 coverage_origin_adjustment =
1775 Point(subpass_coverage.GetLeftTop().x -
1776 std::floor(subpass_coverage.GetLeftTop().x),
1777 subpass_coverage.GetLeftTop().y -
1778 std::floor(subpass_coverage.GetLeftTop().y));
1781 return SkipUntilMatchingRestore(total_content_depth);
1789 ->GetMaximumRenderPassAttachmentSize());
1792 std::shared_ptr<FilterContents> backdrop_filter_contents;
1794 if (backdrop_filter) {
1795 local_position = subpass_coverage.GetOrigin() - GetGlobalPassPosition();
1797 std::shared_ptr<Texture> input_texture;
1802 bool will_cache_backdrop_texture =
false;
1807 size_t backdrop_count = 1;
1808 if (backdrop_id.has_value()) {
1809 std::unordered_map<int64_t, BackdropData>::iterator backdrop_data_it =
1810 backdrop_data_.find(backdrop_id.value());
1811 if (backdrop_data_it != backdrop_data_.end()) {
1812 backdrop_data = &backdrop_data_it->second;
1813 will_cache_backdrop_texture =
1815 backdrop_count = backdrop_data_it->second.backdrop_count;
1819 if (!will_cache_backdrop_texture || !backdrop_data->
texture_slot) {
1820 backdrop_count_ -= backdrop_count;
1826 const bool should_use_onscreen =
1828 backdrop_count_ == 0 && render_passes_.size() == 1u;
1829 input_texture = FlipBackdrop(
1830 GetGlobalPassPosition(),
1831 will_cache_backdrop_texture,
1834 if (!input_texture) {
1839 if (will_cache_backdrop_texture) {
1846 backdrop_filter_contents =
1849 backdrop_filter_contents->SetEffectTransform(
1850 transform_stack_.back().transform.Basis());
1851 backdrop_filter_contents->SetRenderingMode(
1852 transform_stack_.back().transform.HasTranslation()
1856 if (will_cache_backdrop_texture) {
1864 backdrop_filter_contents->RenderToSnapshot(renderer_, {}, {});
1867 std::optional<Snapshot> maybe_snapshot =
1869 if (maybe_snapshot.has_value()) {
1870 const Snapshot& snapshot = maybe_snapshot.value();
1872 subpass_coverage.Shift(-GetGlobalPassPosition()));
1875 contents->SetTexture(snapshot.
texture);
1876 contents->SetSourceRect(scaled);
1886 backdrop_entity.
Render(renderer_, GetCurrentRenderPass());
1894 Paint paint_copy = paint;
1895 paint_copy.
color.
alpha *= transform_stack_.back().distributed_opacity;
1896 transform_stack_.back().distributed_opacity = 1.0;
1898 render_passes_.push_back(
1900 CreateRenderTarget(renderer_,
1905 paint_copy, subpass_coverage.Shift(-coverage_origin_adjustment)});
1908 entry.
transform = transform_stack_.back().transform;
1909 entry.
clip_depth = current_depth_ + total_content_depth;
1911 << entry.
clip_depth <<
" <=? " << transform_stack_.back().clip_depth
1912 <<
" after allocating " << total_content_depth;
1913 entry.
clip_height = transform_stack_.back().clip_height;
1916 transform_stack_.emplace_back(entry);
1923 clip_coverage_stack_.
PushSubpass(subpass_coverage, GetClipHeight());
1925 if (!backdrop_filter_contents) {
1931 backdrop_entity.
SetContents(std::move(backdrop_filter_contents));
1934 backdrop_entity.
SetClipDepth(std::numeric_limits<uint32_t>::max());
1935 backdrop_entity.
Render(renderer_, GetCurrentRenderPass());
1940 if (transform_stack_.size() == 1) {
1957 FML_DCHECK(current_depth_ <= transform_stack_.back().clip_depth)
1958 << current_depth_ <<
" <=? " << transform_stack_.back().clip_depth;
1959 current_depth_ = transform_stack_.back().clip_depth;
1962 transform_stack_.pop_back();
1966 if (transform_stack_.back().rendering_mode ==
1968 transform_stack_.back().rendering_mode ==
1970 auto lazy_render_pass = std::move(render_passes_.back());
1971 render_passes_.pop_back();
1973 lazy_render_pass.GetInlinePassContext()->GetRenderPass();
1976 save_layer_state_.pop_back();
1977 auto global_pass_position = GetGlobalPassPosition();
1979 std::shared_ptr<Contents> contents = CreateContentsForSubpassTarget(
1980 renderer_, save_layer_state.
paint,
1981 lazy_render_pass.GetInlinePassContext()->GetTexture(),
1983 transform_stack_.back().transform
1986 lazy_render_pass.GetInlinePassContext()->EndPass();
1993 Point subpass_texture_position;
1994 if (transform_stack_.back().did_round_out) {
1997 subpass_texture_position =
2002 subpass_texture_position =
2016 ApplyFramebufferBlend(element_entity);
2027 auto input_texture = FlipBackdrop(GetGlobalPassPosition());
2028 if (!input_texture) {
2038 contents->SetCoverageHint(element_entity.
GetCoverage());
2046 *render_passes_.back().GetInlinePassContext()->GetRenderPass()
2049 transform_stack_.pop_back();
2057 size_t num_clips = transform_stack_.back().num_clips;
2058 transform_stack_.pop_back();
2060 if (num_clips > 0) {
2071 *render_passes_.back().GetInlinePassContext()->GetRenderPass(),
2072 GetGlobalPassPosition()
2080bool Canvas::AttemptBlurredTextOptimization(
2081 const std::shared_ptr<TextFrame>& text_frame,
2082 const std::shared_ptr<TextContents>& text_contents,
2084 const Paint& paint) {
2098 std::shared_ptr<FilterContents> filter =
2103 std::optional<Glyph> maybe_glyph = text_frame->AsSingleGlyph();
2104 int64_t identifier = maybe_glyph.has_value()
2105 ? maybe_glyph.value().index
2106 :
reinterpret_cast<int64_t
>(text_frame.get());
2107 TextShadowCache::TextShadowCacheKey cache_key(
2110 maybe_glyph.has_value(),
2111 text_frame->GetFont(),
2116 renderer_, entity, filter, cache_key);
2117 if (result.has_value()) {
2118 AddRenderEntityToCurrentPass(result.value(),
false);
2132 const Paint& paint) {
2134 if (max_scale * text_frame->GetFont().GetMetrics().point_size >
2150 auto text_contents = std::make_shared<TextContents>();
2151 text_contents->SetTextFrame(text_frame);
2152 text_contents->SetPosition(position);
2155 text_contents->SetColor(paint.
color);
2156 text_contents->SetTextProperties(paint.
color, paint.
GetStroke());
2160 if (AttemptBlurredTextOptimization(text_frame, text_contents, entity,
2166 AddRenderEntityToCurrentPass(entity,
false);
2169void Canvas::AddRenderSDFEntityToCurrentPass(
2173 const std::optional<Matrix>& shape_transform) {
2175 if (shape_transform.has_value()) {
2189 auto geometry = std::make_unique<UberSDFGeometry>(
params);
2191 const Geometry* geom = contents->GetGeometry();
2196 std::shared_ptr<ColorSourceContents> color_source_contents =
2202 Paint new_paint = paint;
2204 AddRenderEntityWithFiltersToCurrentPass(entity, geom, new_paint,
2207 std::move(final_contents));
2209 AddRenderEntityWithFiltersToCurrentPass(entity, geom, paint, reuse_depth,
2211 std::move(contents));
2215void Canvas::AddRenderEntityWithFiltersToCurrentPass(
2217 const Geometry* geometry,
2220 std::shared_ptr<Contents> override_contents) {
2221 std::shared_ptr<ColorSourceContents> color_source_contents;
2222 std::shared_ptr<Contents> contents;
2223 if (override_contents) {
2224 contents = std::move(override_contents);
2226 color_source_contents = paint.CreateContents(renderer_, geometry);
2227 contents = color_source_contents;
2230 if (!paint.color_filter && !paint.invert_colors && !paint.image_filter &&
2231 !paint.mask_blur_descriptor.has_value()) {
2232 entity.SetContents(std::move(contents));
2233 AddRenderEntityToCurrentPass(entity, reuse_depth);
2240 bool needs_color_filter = paint.color_filter || paint.invert_colors;
2241 if (needs_color_filter &&
2242 contents->ApplyColorFilter([&](Color color) -> Color {
2243 if (paint.color_filter) {
2244 color = GetCPUColorFilterProc(paint.color_filter)(color);
2246 if (paint.invert_colors) {
2247 color = color.ApplyColorMatrix(kColorInversion);
2251 needs_color_filter =
false;
2254 bool can_apply_mask_filter = geometry->CanApplyMaskFilter();
2256 if (can_apply_mask_filter && paint.mask_blur_descriptor.has_value()) {
2260 FML_DCHECK(color_source_contents) <<
"Mask blur is only supported when no "
2261 "override contents are provided.";
2262 FillRectGeometry out_rect(
Rect{});
2263 auto filter = paint.mask_blur_descriptor->CreateMaskBlur(
2264 paint, renderer_, geometry, color_source_contents, needs_color_filter,
2266 entity.SetContents(std::move(filter));
2267 AddRenderEntityToCurrentPass(entity, reuse_depth);
2271 std::shared_ptr<Contents> contents_copy = std::move(contents);
2275 if (needs_color_filter &&
2276 (!paint.color_source ||
2278 if (paint.color_filter) {
2283 if (paint.invert_colors) {
2290 if (paint.image_filter) {
2291 std::shared_ptr<FilterContents> filter =
2292 WrapInput(renderer_, paint.image_filter,
2295 entity.SetContents(filter);
2296 AddRenderEntityToCurrentPass(entity, reuse_depth);
2300 entity.SetContents(std::move(contents_copy));
2301 AddRenderEntityToCurrentPass(entity, reuse_depth);
2304void Canvas::AddRenderEntityToCurrentPass(Entity& entity,
bool reuse_depth) {
2309 entity.SetTransform(
2310 Matrix::MakeTranslation(Vector3(-GetGlobalPassPosition())) *
2311 entity.GetTransform());
2312 entity.SetInheritedOpacity(transform_stack_.back().distributed_opacity);
2313 if (entity.GetBlendMode() == BlendMode::kSrcOver &&
2314 entity.GetContents()->IsOpaque(entity.GetTransform())) {
2315 entity.SetBlendMode(BlendMode::kSrc);
2321 if (render_passes_.back().IsApplyingClearColor()) {
2322 std::optional<Color> maybe_color = entity.AsBackgroundColor(
2323 render_passes_.back().GetInlinePassContext()->GetTexture()->GetSize());
2324 if (maybe_color.has_value()) {
2325 Color color = maybe_color.value();
2326 RenderTarget& render_target = render_passes_.back()
2327 .GetInlinePassContext()
2330 ColorAttachment attachment = render_target.GetColorAttachment(0);
2333 attachment.clear_color = attachment.clear_color.Unpremultiply()
2334 .Blend(color, entity.GetBlendMode())
2336 render_target.SetColorAttachment(attachment, 0u);
2347 FML_DCHECK(current_depth_ <= transform_stack_.back().clip_depth)
2348 << current_depth_ <<
" <=? " << transform_stack_.back().clip_depth;
2349 entity.SetClipDepth(current_depth_);
2351 if (entity.GetBlendMode() > Entity::kLastPipelineBlendMode) {
2352 if (renderer_.GetDeviceCapabilities().SupportsFramebufferFetch()) {
2353 ApplyFramebufferBlend(entity);
2364 auto input_texture = FlipBackdrop(GetGlobalPassPosition(),
2368 if (!input_texture) {
2376 auto element_coverage_hint = entity.GetContents()->GetCoverageHint();
2377 entity.GetContents()->SetCoverageHint(Rect::Intersection(
2378 element_coverage_hint, clip_coverage_stack_.CurrentClipCoverage()));
2380 FilterInput::Vector inputs = {
2381 FilterInput::Make(input_texture, entity.GetTransform().Invert()),
2382 FilterInput::Make(entity.GetContents())};
2384 ColorFilterContents::MakeBlend(entity.GetBlendMode(), inputs);
2385 entity.SetContents(std::move(contents));
2386 entity.SetBlendMode(BlendMode::kSrc);
2390 const std::shared_ptr<RenderPass>& result =
2391 render_passes_.back().GetInlinePassContext()->GetRenderPass();
2399 entity.Render(renderer_, *result);
2402RenderPass& Canvas::GetCurrentRenderPass()
const {
2403 return *render_passes_.back().GetInlinePassContext()->GetRenderPass();
2406void Canvas::SetBackdropData(
2407 std::unordered_map<int64_t, BackdropData> backdrop_data,
2408 size_t backdrop_count) {
2409 backdrop_data_ = std::move(backdrop_data);
2410 backdrop_count_ = backdrop_count;
2413std::shared_ptr<Texture> Canvas::FlipBackdrop(
Point global_pass_position,
2414 bool should_remove_texture,
2415 bool should_use_onscreen,
2416 bool post_depth_increment) {
2418 render_passes_.pop_back();
2434 <<
"Failed to end the current render pass in order to read from "
2435 "the backdrop texture and apply an advanced blend or backdrop "
2440 render_passes_.emplace_back(std::move(rendering_config));
2444 const std::shared_ptr<Texture>& input_texture =
2447 if (!input_texture) {
2448 VALIDATION_LOG <<
"Failed to fetch the color texture in order to "
2449 "apply an advanced blend or backdrop filter.";
2452 render_passes_.emplace_back(std::move(rendering_config));
2456 if (should_use_onscreen) {
2457 ColorAttachment color0 = render_target_.GetColorAttachment(0);
2461 color0.load_action = color0.resolve_texture !=
nullptr
2462 ? LoadAction::kDontCare
2463 : LoadAction::kLoad;
2464 render_target_.SetColorAttachment(color0, 0);
2466 auto entity_pass_target = std::make_unique<EntityPassTarget>(
2468 renderer_.GetDeviceCapabilities().SupportsReadFromResolve(),
2469 renderer_.GetDeviceCapabilities().SupportsImplicitResolvingMSAA()
2471 render_passes_.push_back(
2472 LazyRenderingConfig(renderer_, std::move(entity_pass_target)));
2473 requires_readback_ =
false;
2475 render_passes_.emplace_back(std::move(rendering_config));
2478 if (should_remove_texture) {
2479 render_passes_.back().GetEntityPassTarget()->RemoveSecondary();
2482 RenderPass& current_render_pass =
2483 *render_passes_.back().GetInlinePassContext()->GetRenderPass();
2492 Rect size_rect = Rect::MakeSize(input_texture->GetSize());
2493 auto msaa_backdrop_contents = TextureContents::MakeRect(size_rect);
2494 msaa_backdrop_contents->SetStencilEnabled(
false);
2495 msaa_backdrop_contents->SetLabel(
"MSAA backdrop");
2496 msaa_backdrop_contents->SetSourceRect(size_rect);
2497 msaa_backdrop_contents->SetTexture(input_texture);
2499 Entity msaa_backdrop_entity;
2500 msaa_backdrop_entity.SetContents(std::move(msaa_backdrop_contents));
2501 msaa_backdrop_entity.SetBlendMode(BlendMode::kSrc);
2502 msaa_backdrop_entity.SetClipDepth(std::numeric_limits<uint32_t>::max());
2503 if (!msaa_backdrop_entity.Render(renderer_, current_render_pass)) {
2510 auto& replay_entities = clip_coverage_stack_.GetReplayEntities();
2511 uint64_t current_depth =
2512 post_depth_increment ? current_depth_ - 1 : current_depth_;
2513 for (
const auto& replay : replay_entities) {
2514 if (replay.clip_depth <= current_depth) {
2518 SetClipScissor(replay.clip_coverage, current_render_pass,
2519 global_pass_position);
2520 if (!replay.clip_contents.Render(renderer_, current_render_pass,
2521 replay.clip_depth)) {
2526 return input_texture;
2529bool Canvas::SupportsBlitToOnscreen()
const {
2530 return renderer_.GetContext()
2532 ->SupportsTextureToTextureBlits() &&
2533 renderer_.GetContext()->GetBackendType() ==
2534 Context::BackendType::kMetal;
2537bool Canvas::BlitToOnscreen(
bool is_onscreen) {
2538 auto command_buffer = renderer_.GetContext()->CreateCommandBuffer();
2540 auto offscreen_target = render_passes_.back()
2541 .GetInlinePassContext()
2544 if (SupportsBlitToOnscreen()) {
2546 blit_pass->AddCopy(offscreen_target.GetRenderTargetTexture(),
2547 render_target_.GetRenderTargetTexture());
2548 if (!blit_pass->EncodeCommands()) {
2554 render_pass->SetLabel(
"EntityPass Root Render Pass");
2557 auto size_rect = Rect::MakeSize(offscreen_target.GetRenderTargetSize());
2558 auto contents = TextureContents::MakeRect(size_rect);
2559 contents->SetTexture(offscreen_target.GetRenderTargetTexture());
2560 contents->SetSourceRect(size_rect);
2561 contents->SetLabel(
"Root pass blit");
2564 entity.SetContents(contents);
2565 entity.SetBlendMode(BlendMode::kSrc);
2580 return renderer_.GetContext()->SubmitOnscreen(std::move(
command_buffer));
2582 return renderer_.GetContext()->EnqueueCommandBuffer(
2587bool Canvas::EnsureFinalMipmapGeneration()
const {
2588 if (!render_target_.GetRenderTargetTexture()->NeedsMipmapGeneration()) {
2591 std::shared_ptr<CommandBuffer> cmd_buffer =
2592 renderer_.GetContext()->CreateCommandBuffer();
2596 std::shared_ptr<BlitPass> blit_pass = cmd_buffer->CreateBlitPass();
2600 blit_pass->GenerateMipmap(render_target_.GetRenderTargetTexture());
2601 blit_pass->EncodeCommands();
2602 return renderer_.GetContext()->EnqueueCommandBuffer(std::move(cmd_buffer));
2605void Canvas::EndReplay() {
2607 render_passes_.back().GetInlinePassContext()->GetRenderPass();
2608 render_passes_.back().GetInlinePassContext()->EndPass(
2609 !requires_readback_ && is_onscreen_);
2610 backdrop_data_.clear();
2615 if (requires_readback_) {
2616 BlitToOnscreen(is_onscreen_);
2618 if (!EnsureFinalMipmapGeneration()) {
2621 if (!renderer_.GetContext()->FlushCommandBuffers()) {
2625 render_passes_.clear();
2626 renderer_.GetRenderTargetCache()->End();
2627 clip_geometry_.clear();
2630 Initialize(initial_cull_rect_);
2633bool Canvas::IsCompatibleWithSDFRendering(
const Paint& paint) {
2642 case BlendMode::kClear:
2643 case BlendMode::kSrc:
2644 case BlendMode::kSrcIn:
2645 case BlendMode::kDstIn:
2646 case BlendMode::kSrcOut:
2647 case BlendMode::kDstATop:
2648 case BlendMode::kPlus:
2649 case BlendMode::kModulate:
2652 case BlendMode::kDst:
2653 case BlendMode::kSrcOver:
2654 case BlendMode::kDstOver:
2655 case BlendMode::kDstOut:
2656 case BlendMode::kSrcATop:
2657 case BlendMode::kXor:
2658 case BlendMode::kScreen:
2659 case BlendMode::kOverlay:
2660 case BlendMode::kDarken:
2661 case BlendMode::kLighten:
2662 case BlendMode::kColorDodge:
2663 case BlendMode::kColorBurn:
2664 case BlendMode::kHardLight:
2665 case BlendMode::kSoftLight:
2666 case BlendMode::kDifference:
2667 case BlendMode::kExclusion:
2668 case BlendMode::kMultiply:
2669 case BlendMode::kHue:
2670 case BlendMode::kSaturation:
2671 case BlendMode::kColor:
2672 case BlendMode::kLuminosity:
2677LazyRenderingConfig::LazyRenderingConfig(
2679 std::unique_ptr<EntityPassTarget> p_entity_pass_target)
2680 : entity_pass_target_(
std::move(p_entity_pass_target)) {
2681 inline_pass_context_ =
2682 std::make_unique<InlinePassContext>(renderer, *entity_pass_target_);
2686 return !inline_pass_context_->IsActive();
2690 return entity_pass_target_.get();
2694 return inline_pass_context_.get();
virtual T type() const =0
virtual const DlBlendColorFilter * asBlend() const
virtual const DlMatrixColorFilter * asMatrix() const
virtual bool modifies_transparent_black() const =0
virtual const DlImageColorSource * asImage() const
DlImageSampling sampling() const
DlTileMode vertical_tile_mode() const
DlTileMode horizontal_tile_mode() const
sk_sp< const DlImage > image() const
void get_matrix(float matrix[20]) const
const DlMatrix & matrix() const
A Geometry that produces fillable vertices representing the stroked outline of an |Arc| object using ...
const Geometry & BuildDrawGeometry() override
PathBlurShape(const PathSource &source, std::shared_ptr< ShadowVertices > shadow_vertices, Sigma sigma)
Rect GetBounds() const override
std::shared_ptr< SolidBlurContents > BuildBlurContent(Sigma sigma) override
Rect GetBounds() const override
RRectBlurShape(const Rect &rect, Scalar corner_radius)
const Geometry & BuildDrawGeometry() override
std::shared_ptr< SolidBlurContents > BuildBlurContent(Sigma sigma) override
std::shared_ptr< SolidBlurContents > BuildBlurContent(Sigma sigma) override
const Geometry & BuildDrawGeometry() override
Rect GetBounds() const 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 std::shared_ptr< RenderTargetAllocator > & GetRenderTargetCache() const
const Capabilities & GetDeviceCapabilities() 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)
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)
ReplayResult & GetLastReplayResult()
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.
virtual std::optional< Rect > GetCoverage(const Matrix &transform) const =0
The coverage rectangle of this geometry, transformed by the transform argument.
static std::unique_ptr< Geometry > MakeRect(const Rect &rect)
virtual GeometryResult GetPositionBuffer(const ContentContext &renderer, const Entity &entity, RenderPass &pass) 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
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)
const EmbeddedViewParams * params
FlutterVulkanImage * image
#define FML_CHECK(condition)
#define FML_DCHECK(condition)
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...
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)
static const constexpr ColorMatrix kColorInversion
A color matrix which inverts colors.
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
constexpr Degrees GetSweep() const
constexpr Degrees GetStart() const
const Rect & GetOvalBounds() const
Return the bounds of the oval in which this arc is inscribed.
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
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< StrokeParameters > GetStroke() const
Return an optional StrokeParameters if this Paint is a stroked Paint, otherwise return a nullopt.
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 bool IsEmpty() const
constexpr const RoundingRadii & GetRadii() const
constexpr const Rect & GetBounds() const
constexpr const Rect & GetBounds() const
constexpr const RoundingRadii & GetRadii() const
static RoundSuperellipseParam MakeBoundsRadii(const Rect &bounds, const RoundingRadii &radii)
constexpr bool AreAllCornersCircular() const
static constexpr RoundingRadii MakeRadius(Scalar radius)
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 TPoint PerpendicularRight() const
constexpr auto GetBottom() const
constexpr TRect TransformBounds(const Matrix &transform) const
Creates a new bounding box that contains this transformed rectangle.
static constexpr TRect MakeEllipseBounds(const TPoint< Type > ¢er, const TSize< Type > &radii)
constexpr auto GetTop() const
constexpr std::optional< TRect > Intersection(const TRect &o) 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...
constexpr Type GetHeight() const
Returns the height of the rectangle, equivalent to |GetSize().height|.
constexpr bool IsEmpty() const
Returns true if either of the width or height are 0, negative, or NaN.
constexpr T Area() const
Get the area of the rectangle, equivalent to |GetSize().Area()|.
constexpr auto GetLeft() const
Round(const TRect< U > &r)
RoundOut(const TRect< U > &r)
static constexpr TRect MakeOriginSize(const TPoint< Type > &origin, const TSize< Type > &size)
constexpr auto GetRight() const
constexpr bool IsSquare() const
Returns true if width and height are equal and neither is NaN.
static constexpr TRect MakeXYWH(Type x, Type y, Type width, Type height)
static constexpr TRect MakeCircleBounds(const TPoint< Type > ¢er, Type radius)
static constexpr TRect MakeSize(const TSize< U > &size)
constexpr Type GetWidth() const
Returns the width of the rectangle, equivalent to |GetSize().width|.
constexpr TRect< T > Expand(T left, T top, T right, T bottom) const
Returns a rectangle with expanded edges. Negative expansion results in shrinking.
static constexpr TRect MakeMaximum()
constexpr Point GetCenter() const
Get the center point as a |Point|.
constexpr TRect< T > Shift(T dx, T dy) const
Returns a new rectangle translated by the given offset.
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...
static constexpr TRect MakeLTRB(Type left, Type top, Type right, Type bottom)
Parameters for rendering shapes using the UberSDF shader.
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
#define TRACE_EVENT0(category_group, name)