Flutter Engine Uber Docs
Docs for the entire Flutter Engine repo.
 
Loading...
Searching...
No Matches
impeller::Canvas Class Reference

#include <canvas.h>

Classes

class  PathBlurShape
 
class  RRectBlurShape
 
class  RSuperellipseBlurShape
 
struct  SaveLayerState
 

Public Member Functions

 Canvas (ContentContext &renderer, const RenderTarget &render_target, bool is_onscreen, bool requires_readback)
 
 Canvas (ContentContext &renderer, const RenderTarget &render_target, bool is_onscreen, bool requires_readback, Rect cull_rect)
 
 Canvas (ContentContext &renderer, const RenderTarget &render_target, bool is_onscreen, bool requires_readback, IRect32 cull_rect)
 
 ~Canvas ()=default
 
void SetBackdropData (std::unordered_map< int64_t, BackdropData > backdrop_data, size_t backdrop_count)
 Update the backdrop data used to group together backdrop filters within the same layer.
 
std::optional< RectGetLocalCoverageLimit () const
 Return the culling bounds of the current render target, or nullopt if there is no coverage.
 
void Save (uint32_t total_content_depth=kMaxDepth)
 
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)
 
bool Restore ()
 
size_t GetSaveCount () const
 
void RestoreToCount (size_t count)
 
const MatrixGetCurrentTransform () const
 
void ResetTransform ()
 
void Transform (const Matrix &transform)
 
void Concat (const Matrix &transform)
 
void PreConcat (const Matrix &transform)
 
void Translate (const Vector3 &offset)
 
void Scale (const Vector2 &scale)
 
void Scale (const Vector3 &scale)
 
void Skew (Scalar sx, Scalar sy)
 
void Rotate (Radians radians)
 
void DrawPath (const flutter::DlPath &path, const Paint &paint)
 
void DrawPaint (const Paint &paint)
 
void DrawLine (const Point &p0, const Point &p1, const Paint &paint, bool reuse_depth=false)
 
void DrawDashedLine (const Point &p0, const Point &p1, Scalar on_length, Scalar off_length, const Paint &paint)
 
void DrawRect (const Rect &rect, const Paint &paint)
 
void DrawOval (const Rect &rect, const Paint &paint)
 
void DrawArc (const Arc &arc, const Paint &paint)
 
void DrawRoundRect (const RoundRect &rect, const Paint &paint)
 
void DrawDiffRoundRect (const RoundRect &outer, const RoundRect &inner, const Paint &paint)
 
void DrawRoundSuperellipse (const RoundSuperellipse &rse, const Paint &paint)
 
void DrawCircle (const Point &center, Scalar radius, const Paint &paint)
 
void DrawPoints (const Point points[], uint32_t count, Scalar radius, const Paint &paint, PointStyle point_style)
 
void DrawImage (const std::shared_ptr< Texture > &image, Point offset, const Paint &paint, const SamplerDescriptor &sampler={})
 
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 DrawTextFrame (const std::shared_ptr< TextFrame > &text_frame, Point position, const Paint &paint)
 
void DrawVertices (const std::shared_ptr< VerticesGeometry > &vertices, BlendMode blend_mode, const Paint &paint)
 
void DrawAtlas (const std::shared_ptr< AtlasContents > &atlas_contents, const Paint &paint)
 
void ClipGeometry (const Geometry &geometry, Entity::ClipOperation clip_op, bool is_aa=true)
 
void EndReplay ()
 
uint64_t GetOpDepth () const
 
uint64_t GetMaxOpDepth () const
 
bool RequiresReadback () const
 
bool SupportsBlitToOnscreen () const
 
bool EnsureFinalMipmapGeneration () const
 

Static Public Member Functions

static bool IsCompatibleWithSDFRendering (const Paint &paint)
 

Static Public Attributes

static constexpr uint32_t kMaxDepth = 1 << 24
 

Detailed Description

Definition at line 119 of file canvas.h.

Constructor & Destructor Documentation

◆ Canvas() [1/3]

impeller::Canvas::Canvas ( ContentContext renderer,
const RenderTarget render_target,
bool  is_onscreen,
bool  requires_readback 
)

Definition at line 297 of file canvas.cc.

301 : renderer_(renderer),
302 render_target_(render_target),
303 is_onscreen_(is_onscreen),
304 requires_readback_(requires_readback),
305 clip_coverage_stack_(EntityPassClipStack(
306 Rect::MakeSize(render_target.GetRenderTargetSize()))) {
307 Initialize(std::nullopt);
308 SetupRenderPass();
309}
static constexpr TRect MakeSize(const TSize< U > &size)
Definition rect.h:150

◆ Canvas() [2/3]

impeller::Canvas::Canvas ( ContentContext renderer,
const RenderTarget render_target,
bool  is_onscreen,
bool  requires_readback,
Rect  cull_rect 
)
explicit

Definition at line 311 of file canvas.cc.

316 : renderer_(renderer),
317 render_target_(render_target),
318 is_onscreen_(is_onscreen),
319 requires_readback_(requires_readback),
320 clip_coverage_stack_(EntityPassClipStack(
321 Rect::MakeSize(render_target.GetRenderTargetSize()))) {
322 Initialize(cull_rect);
323 SetupRenderPass();
324}

◆ Canvas() [3/3]

impeller::Canvas::Canvas ( ContentContext renderer,
const RenderTarget render_target,
bool  is_onscreen,
bool  requires_readback,
IRect32  cull_rect 
)
explicit

Definition at line 326 of file canvas.cc.

331 : renderer_(renderer),
332 render_target_(render_target),
333 is_onscreen_(is_onscreen),
334 requires_readback_(requires_readback),
335 clip_coverage_stack_(EntityPassClipStack(
336 Rect::MakeSize(render_target.GetRenderTargetSize()))) {
337 Initialize(Rect::MakeLTRB(cull_rect.GetLeft(), cull_rect.GetTop(),
338 cull_rect.GetRight(), cull_rect.GetBottom()));
339 SetupRenderPass();
340}
static constexpr TRect MakeLTRB(Type left, Type top, Type right, Type bottom)
Definition rect.h:129

References impeller::TRect< T >::GetBottom(), impeller::TRect< T >::GetLeft(), impeller::TRect< T >::GetRight(), impeller::TRect< T >::GetTop(), and impeller::TRect< Scalar >::MakeLTRB().

◆ ~Canvas()

flutter::Canvas::~Canvas ( )
default

Definition at line 48 of file canvas.cc.

48{}

Member Function Documentation

◆ ClipGeometry()

void impeller::Canvas::ClipGeometry ( const Geometry geometry,
Entity::ClipOperation  clip_op,
bool  is_aa = true 
)

Definition at line 1120 of file canvas.cc.

1122 {
1123 if (IsSkipping()) {
1124 return;
1125 }
1126
1127 // Ideally the clip depth would be greater than the current rendering
1128 // depth because any rendering calls that follow this clip operation will
1129 // pre-increment the depth and then be rendering above our clip depth,
1130 // but that case will be caught by the CHECK in AddRenderEntity above.
1131 // In practice we sometimes have a clip set with no rendering after it
1132 // and in such cases the current depth will equal the clip depth.
1133 // Eventually the DisplayList should optimize these out, but it is hard
1134 // to know if a clip will actually be used in advance of storing it in
1135 // the DisplayList buffer.
1136 // See https://github.com/flutter/flutter/issues/147021
1137 FML_DCHECK(current_depth_ <= transform_stack_.back().clip_depth)
1138 << current_depth_ << " <=? " << transform_stack_.back().clip_depth;
1139 uint32_t clip_depth = transform_stack_.back().clip_depth;
1140
1141 const Matrix clip_transform =
1142 Matrix::MakeTranslation(Vector3(-GetGlobalPassPosition())) *
1144
1145 std::optional<Rect> clip_coverage = geometry.GetCoverage(clip_transform);
1146 if (!clip_coverage.has_value()) {
1147 return;
1148 }
1149
1150 ClipContents clip_contents(
1151 clip_coverage.value(),
1152 /*is_axis_aligned_rect=*/geometry.IsAxisAlignedRect() &&
1153 GetCurrentTransform().IsTranslationScaleOnly());
1154 clip_contents.SetClipOperation(clip_op);
1155
1156 EntityPassClipStack::ClipStateResult clip_state_result =
1157 clip_coverage_stack_.RecordClip(
1158 clip_contents, //
1159 /*transform=*/clip_transform, //
1160 /*global_pass_position=*/GetGlobalPassPosition(), //
1161 /*clip_depth=*/clip_depth, //
1162 /*clip_height_floor=*/GetClipHeightFloor(), //
1163 /*is_aa=*/is_aa);
1164
1165 if (clip_state_result.clip_did_change) {
1166 // We only need to update the pass scissor if the clip state has changed.
1167 SetClipScissor(
1168 clip_coverage_stack_.CurrentClipCoverage(),
1169 *render_passes_.back().GetInlinePassContext()->GetRenderPass(),
1170 GetGlobalPassPosition());
1171 }
1172
1173 ++transform_stack_.back().clip_height;
1174 ++transform_stack_.back().num_clips;
1175
1176 if (!clip_state_result.should_render) {
1177 return;
1178 }
1179
1180 // Note: this is a bit of a hack. Its not possible to construct a geometry
1181 // result without begninning the render pass. We should refactor the geometry
1182 // objects so that they only need a reference to the render pass size and/or
1183 // orthographic transform.
1184 Entity entity;
1185 entity.SetTransform(clip_transform);
1186 entity.SetClipDepth(clip_depth);
1187
1188 GeometryResult geometry_result = geometry.GetPositionBuffer(
1189 renderer_, //
1190 entity, //
1191 *render_passes_.back().GetInlinePassContext()->GetRenderPass() //
1192 );
1193 clip_contents.SetGeometry(geometry_result);
1194 clip_coverage_stack_.GetLastReplayResult().clip_contents.SetGeometry(
1195 geometry_result);
1196
1197 clip_contents.Render(
1198 renderer_, *render_passes_.back().GetInlinePassContext()->GetRenderPass(),
1199 clip_depth);
1200}
const Matrix & GetCurrentTransform() const
Definition canvas.cc:371
void SetGeometry(GeometryResult geometry)
Set the pre-tessellated clip geometry.
std::optional< Rect > CurrentClipCoverage() const
ClipStateResult RecordClip(const ClipContents &clip_contents, Matrix transform, Point global_pass_position, uint32_t clip_depth, size_t clip_height_floor, bool is_aa)
#define FML_DCHECK(condition)
Definition logging.h:122
static constexpr Matrix MakeTranslation(const Vector3 &t)
Definition matrix.h:95

References impeller::EntityPassClipStack::ReplayResult::clip_contents, impeller::EntityPassClipStack::ClipStateResult::clip_did_change, impeller::EntityPassClipStack::CurrentClipCoverage(), FML_DCHECK, impeller::Geometry::GetCoverage(), GetCurrentTransform(), impeller::EntityPassClipStack::GetLastReplayResult(), impeller::Geometry::GetPositionBuffer(), impeller::Geometry::IsAxisAlignedRect(), impeller::Matrix::MakeTranslation(), impeller::EntityPassClipStack::RecordClip(), impeller::ClipContents::Render(), impeller::Entity::SetClipDepth(), impeller::ClipContents::SetClipOperation(), impeller::ClipContents::SetGeometry(), impeller::Entity::SetTransform(), and impeller::EntityPassClipStack::ClipStateResult::should_render.

Referenced by impeller::DlDispatcherBase::clipOval(), impeller::DlDispatcherBase::clipPath(), impeller::DlDispatcherBase::clipRect(), impeller::DlDispatcherBase::clipRoundRect(), and impeller::DlDispatcherBase::clipRoundSuperellipse().

◆ Concat()

void impeller::Canvas::Concat ( const Matrix transform)

Definition at line 355 of file canvas.cc.

355 {
356 transform_stack_.back().transform = GetCurrentTransform() * transform;
357}

References GetCurrentTransform(), and transform.

Referenced by DrawTextFrame(), Rotate(), Scale(), Scale(), Skew(), Transform(), and Translate().

◆ DrawArc()

void impeller::Canvas::DrawArc ( const Arc arc,
const Paint paint 
)

Definition at line 911 of file canvas.cc.

911 {
912 Entity entity;
913 entity.SetTransform(GetCurrentTransform());
914 entity.SetBlendMode(paint.blend_mode);
915
916 if (paint.style == Paint::Style::kFill) {
917 ArcGeometry geom(arc);
918 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
919 return;
920 }
921
922 const Rect& oval_bounds = arc.GetOvalBounds();
923 if (paint.stroke.width > oval_bounds.GetSize().MaxDimension()) {
924 // This is a special case for rendering arcs whose stroke width is so large
925 // you are effectively drawing a sector of a circle.
926 // https://github.com/flutter/flutter/issues/158567
927 Arc expanded_arc(oval_bounds.Expand(Size(paint.stroke.width * 0.5f)),
928 arc.GetStart(), arc.GetSweep(), true);
929
930 ArcGeometry geom(expanded_arc);
931 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
932 return;
933 }
934
935 // IncludeCenter incurs lots of extra work for stroking an arc, including:
936 // - It introduces segments to/from the center point (not too hard).
937 // - It introduces joins on those segments (a bit more complicated).
938 // - Even if the sweep is >=360 degrees, we still draw the segment to
939 // the center and it basically looks like a pie cut into the complete
940 // boundary circle, as if the slice were cut, but not extracted
941 // (hard to express as a continuous kTriangleStrip).
942 if (!arc.IncludeCenter()) {
943 if (arc.IsFullCircle()) {
944 return DrawOval(oval_bounds, paint);
945 }
946
947 // Our fast stroking code only works for circular bounds as it assumes
948 // that the inner and outer radii can be scaled along each angular step
949 // of the arc - which is not true for elliptical arcs where the inner
950 // and outer samples are perpendicular to the traveling direction of the
951 // elliptical curve which may not line up with the center of the bounds.
952 if (oval_bounds.IsSquare()) {
953 ArcGeometry geom(arc, paint.stroke);
954 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
955 return;
956 }
957 }
958
959 ArcStrokeGeometry geom(arc, paint.stroke);
960 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
961}
void DrawOval(const Rect &rect, const Paint &paint)
Definition canvas.cc:856
TRect< Scalar > Rect
Definition rect.h:822
TSize< Scalar > Size
Definition size.h:159

References impeller::Paint::blend_mode, DrawOval(), impeller::TRect< T >::Expand(), GetCurrentTransform(), impeller::Arc::GetOvalBounds(), impeller::TRect< T >::GetSize(), impeller::Arc::GetStart(), impeller::Arc::GetSweep(), impeller::Arc::IncludeCenter(), impeller::Arc::IsFullCircle(), impeller::TRect< T >::IsSquare(), impeller::Paint::kFill, impeller::Entity::SetBlendMode(), impeller::Entity::SetTransform(), impeller::Paint::stroke, impeller::Paint::style, and impeller::StrokeParameters::width.

Referenced by impeller::DlDispatcherBase::drawArc().

◆ DrawAtlas()

void impeller::Canvas::DrawAtlas ( const std::shared_ptr< AtlasContents > &  atlas_contents,
const Paint paint 
)

Definition at line 1416 of file canvas.cc.

1417 {
1418 atlas_contents->SetAlpha(paint.color.alpha);
1419
1420 Entity entity;
1421 entity.SetTransform(GetCurrentTransform());
1422 entity.SetBlendMode(paint.blend_mode);
1423 entity.SetContents(paint.WithFilters(renderer_, atlas_contents));
1424
1425 AddRenderEntityToCurrentPass(entity);
1426}

References impeller::Color::alpha, impeller::Paint::blend_mode, impeller::Paint::color, GetCurrentTransform(), impeller::Entity::SetBlendMode(), impeller::Entity::SetContents(), impeller::Entity::SetTransform(), and impeller::Paint::WithFilters().

Referenced by impeller::DlDispatcherBase::drawAtlas().

◆ DrawCircle()

void impeller::Canvas::DrawCircle ( const Point center,
Scalar  radius,
const Paint paint 
)

Definition at line 1083 of file canvas.cc.

1085 {
1086 if (IsShadowBlurDrawOperation(paint)) {
1087 Rect bounds = Rect::MakeCircleBounds(center, radius);
1088 RRectBlurShape shape(bounds, radius);
1089 if (AttemptDrawBlur(shape, paint)) {
1090 return;
1091 }
1092 }
1093
1094 if (renderer_.GetContext()->GetFlags().use_sdfs &&
1097 /*color=*/paint.color, /*center=*/center, /*radius=*/radius,
1098 /*stroke=*/paint.GetStroke());
1099 AddRenderSDFEntityToCurrentPass(paint, params);
1100 return;
1101 }
1102
1103 if (AttemptDrawAntialiasedCircle(center, radius, paint)) {
1104 return;
1105 }
1106
1107 Entity entity;
1108 entity.SetTransform(GetCurrentTransform());
1109 entity.SetBlendMode(paint.blend_mode);
1110
1111 if (paint.style == Paint::Style::kStroke) {
1112 CircleGeometry geom(center, radius, paint.stroke.width);
1113 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
1114 } else {
1115 CircleGeometry geom(center, radius);
1116 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
1117 }
1118}
static bool IsCompatibleWithSDFRendering(const Paint &paint)
Definition canvas.cc:2456
std::shared_ptr< Context > GetContext() const
const EmbeddedViewParams * params
static constexpr TRect MakeCircleBounds(const TPoint< Type > &center, Type radius)
Definition rect.h:156
static UberSDFParameters MakeCircle(Color color, const Point &center, Scalar radius, std::optional< StrokeParameters > stroke)
Creates UberSDFParameters for a circle.

References impeller::Paint::blend_mode, impeller::Paint::color, impeller::ContentContext::GetContext(), GetCurrentTransform(), impeller::Paint::GetStroke(), IsCompatibleWithSDFRendering(), impeller::Paint::kStroke, impeller::UberSDFParameters::MakeCircle(), impeller::TRect< Scalar >::MakeCircleBounds(), params, impeller::Entity::SetBlendMode(), impeller::Entity::SetTransform(), impeller::Paint::stroke, impeller::Paint::style, and impeller::StrokeParameters::width.

Referenced by impeller::DlDispatcherBase::drawCircle(), and DrawOval().

◆ DrawDashedLine()

void impeller::Canvas::DrawDashedLine ( const Point p0,
const Point p1,
Scalar  on_length,
Scalar  off_length,
const Paint paint 
)

Definition at line 799 of file canvas.cc.

803 {
804 // Reasons to defer to regular DrawLine:
805 // - performance for degenerate and "regular line" cases
806 // - length is non-positive - DrawLine will draw appropriate "dot"
807 // - off_length is non-positive - no gaps, DrawLine will draw it solid
808 // - on_length is negative - invalid dashing
809 //
810 // Note that a 0 length "on" dash will draw "dot"s every "off" distance
811 // apart so we proceed with the dashing process in that case.
812 Scalar length = p0.GetDistance(p1);
813 if (length > 0.0f && on_length >= 0.0f && off_length > 0.0f) {
814 Entity entity;
815 entity.SetTransform(GetCurrentTransform());
816 entity.SetBlendMode(paint.blend_mode);
817
818 StrokeDashedLineGeometry geom(p0, p1, on_length, off_length, paint.stroke);
819 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
820 } else {
821 DrawLine(p0, p1, paint);
822 }
823}
void DrawLine(const Point &p0, const Point &p1, const Paint &paint, bool reuse_depth=false)
Definition canvas.cc:776
size_t length
float Scalar
Definition scalar.h:19

References impeller::Paint::blend_mode, DrawLine(), GetCurrentTransform(), impeller::TPoint< T >::GetDistance(), length, p1, impeller::Entity::SetBlendMode(), impeller::Entity::SetTransform(), and impeller::Paint::stroke.

Referenced by impeller::DlDispatcherBase::drawDashedLine().

◆ DrawDiffRoundRect()

void impeller::Canvas::DrawDiffRoundRect ( const RoundRect outer,
const RoundRect inner,
const Paint paint 
)

Definition at line 1010 of file canvas.cc.

1012 {
1013 Entity entity;
1014 entity.SetTransform(GetCurrentTransform());
1015 entity.SetBlendMode(paint.blend_mode);
1016
1017 if (paint.style == Paint::Style::kFill) {
1018 FillDiffRoundRectGeometry geom(outer, inner);
1019 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
1020 } else {
1021 StrokeDiffRoundRectGeometry geom(outer, inner, paint.stroke);
1022 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
1023 }
1024}

References impeller::Paint::blend_mode, GetCurrentTransform(), impeller::Paint::kFill, impeller::Entity::SetBlendMode(), impeller::Entity::SetTransform(), impeller::Paint::stroke, and impeller::Paint::style.

Referenced by impeller::DlDispatcherBase::drawDiffRoundRect().

◆ DrawImage()

void impeller::Canvas::DrawImage ( const std::shared_ptr< Texture > &  image,
Point  offset,
const Paint paint,
const SamplerDescriptor sampler = {} 
)

Definition at line 1220 of file canvas.cc.

1223 {
1224 if (!image) {
1225 return;
1226 }
1227
1228 const Rect source = Rect::MakeSize(image->GetSize());
1229 const Rect dest = source.Shift(offset);
1230
1231 DrawImageRect(image, source, dest, paint, sampler);
1232}
void DrawImageRect(const std::shared_ptr< Texture > &image, Rect source, Rect dest, const Paint &paint, const SamplerDescriptor &sampler={}, SourceRectConstraint src_rect_constraint=SourceRectConstraint::kFast)
Definition canvas.cc:1234
FlutterVulkanImage * image
constexpr TRect< T > Shift(T dx, T dy) const
Returns a new rectangle translated by the given offset.
Definition rect.h:636

References DrawImageRect(), image, impeller::TRect< Scalar >::MakeSize(), and impeller::TRect< T >::Shift().

◆ DrawImageRect()

void impeller::Canvas::DrawImageRect ( const std::shared_ptr< Texture > &  image,
Rect  source,
Rect  dest,
const Paint paint,
const SamplerDescriptor sampler = {},
SourceRectConstraint  src_rect_constraint = SourceRectConstraint::kFast 
)

Definition at line 1234 of file canvas.cc.

1239 {
1240 if (!image || source.IsEmpty() || dest.IsEmpty()) {
1241 return;
1242 }
1243
1244 ISize size = image->GetSize();
1245 if (size.IsEmpty()) {
1246 return;
1247 }
1248
1249 std::optional<Rect> clipped_source =
1250 source.Intersection(Rect::MakeSize(size));
1251 if (!clipped_source) {
1252 return;
1253 }
1254
1255 if (AttemptColorFilterOptimization(image, source, dest, paint, sampler,
1256 src_rect_constraint)) {
1257 return;
1258 }
1259
1260 if (*clipped_source != source) {
1261 Scalar sx = dest.GetWidth() / source.GetWidth();
1262 Scalar sy = dest.GetHeight() / source.GetHeight();
1263 Scalar tx = dest.GetLeft() - source.GetLeft() * sx;
1264 Scalar ty = dest.GetTop() - source.GetTop() * sy;
1265 Matrix src_to_dest = Matrix::MakeTranslateScale({sx, sy, 1}, {tx, ty, 0});
1266 dest = clipped_source->TransformBounds(src_to_dest);
1267 }
1268
1269 auto texture_contents = TextureContents::MakeRect(dest);
1270 texture_contents->SetTexture(image);
1271 texture_contents->SetSourceRect(*clipped_source);
1272 texture_contents->SetStrictSourceRect(src_rect_constraint ==
1274 texture_contents->SetSamplerDescriptor(sampler);
1275 texture_contents->SetOpacity(paint.color.alpha);
1276 texture_contents->SetDeferApplyingOpacity(paint.HasColorFilter());
1277
1278 Entity entity;
1279 entity.SetBlendMode(paint.blend_mode);
1280 entity.SetTransform(GetCurrentTransform());
1281
1282 if (!paint.mask_blur_descriptor.has_value()) {
1283 entity.SetContents(
1284 paint.WithFilters(renderer_, std::move(texture_contents)));
1285 AddRenderEntityToCurrentPass(entity);
1286 return;
1287 }
1288
1289 FillRectGeometry out_rect(Rect{});
1290
1291 entity.SetContents(paint.WithFilters(
1292 renderer_,
1293 paint.mask_blur_descriptor->CreateMaskBlur(texture_contents, &out_rect)));
1294 AddRenderEntityToCurrentPass(entity);
1295}
static std::shared_ptr< TextureContents > MakeRect(Rect destination)
it will be possible to load the file into Perfetto s trace viewer use test Running tests that layout and measure text will not yield consistent results across various platforms Enabling this option will make font resolution default to the Ahem test font on all disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
@ kStrict
Sample only within the source rectangle. May be slower.
ISize64 ISize
Definition size.h:162
static constexpr Matrix MakeTranslateScale(const Vector3 &s, const Vector3 &t)
Definition matrix.h:113

References impeller::Color::alpha, impeller::Paint::blend_mode, impeller::Paint::color, GetCurrentTransform(), impeller::TRect< T >::GetHeight(), impeller::TRect< T >::GetLeft(), impeller::TRect< T >::GetTop(), impeller::TRect< T >::GetWidth(), impeller::Paint::HasColorFilter(), image, impeller::TRect< T >::Intersection(), impeller::TRect< T >::IsEmpty(), impeller::kStrict, impeller::TextureContents::MakeRect(), impeller::TRect< Scalar >::MakeSize(), impeller::Matrix::MakeTranslateScale(), impeller::Paint::mask_blur_descriptor, impeller::Entity::SetBlendMode(), impeller::Entity::SetContents(), impeller::Entity::SetTransform(), impeller::TRect< T >::TransformBounds(), and impeller::Paint::WithFilters().

Referenced by DrawImage(), impeller::DlDispatcherBase::drawImageRect(), and impeller::NinePatchConverter::DrawNinePatch().

◆ DrawLine()

void impeller::Canvas::DrawLine ( const Point p0,
const Point p1,
const Paint paint,
bool  reuse_depth = false 
)

Definition at line 776 of file canvas.cc.

779 {
780 Entity entity;
781 entity.SetTransform(GetCurrentTransform());
782 entity.SetBlendMode(paint.blend_mode);
783
784 auto geometry = std::make_unique<LineGeometry>(p0, p1, paint.stroke);
785
786 if ((renderer_.GetContext()->GetFlags().antialiased_lines ||
787 renderer_.GetContext()->GetFlags().use_sdfs) &&
788 !paint.color_filter && !paint.invert_colors && !paint.image_filter &&
789 !paint.mask_blur_descriptor.has_value() && !paint.color_source) {
790 auto contents = LineContents::Make(std::move(geometry), paint.color);
791 entity.SetContents(std::move(contents));
792 AddRenderEntityToCurrentPass(entity, reuse_depth);
793 } else {
794 AddRenderEntityWithFiltersToCurrentPass(entity, geometry.get(), paint,
795 /*reuse_depth=*/reuse_depth);
796 }
797}
static std::unique_ptr< LineContents > Make(std::unique_ptr< LineGeometry > geometry, Color color)

References impeller::Paint::blend_mode, impeller::Paint::color, impeller::Paint::color_filter, impeller::Paint::color_source, impeller::ContentContext::GetContext(), GetCurrentTransform(), impeller::Paint::image_filter, impeller::Paint::invert_colors, impeller::LineContents::Make(), impeller::Paint::mask_blur_descriptor, p1, impeller::Entity::SetBlendMode(), impeller::Entity::SetContents(), impeller::Entity::SetTransform(), and impeller::Paint::stroke.

Referenced by DrawDashedLine(), impeller::DlDispatcherBase::drawLine(), impeller::DlDispatcherBase::drawPoints(), and impeller::DlDispatcherBase::SimplifyOrDrawPath().

◆ DrawOval()

void impeller::Canvas::DrawOval ( const Rect rect,
const Paint paint 
)

Definition at line 856 of file canvas.cc.

856 {
857 // TODO(jonahwilliams): This additional condition avoids an assert in the
858 // stroke circle geometry generator. I need to verify the condition that this
859 // assert prevents.
860 if (rect.IsSquare() && (paint.style == Paint::Style::kFill ||
861 (paint.style == Paint::Style::kStroke &&
862 paint.stroke.width < rect.GetWidth()))) {
863 // Circles have slightly less overhead and can do stroking
864 DrawCircle(rect.GetCenter(), rect.GetWidth() * 0.5f, paint);
865 return;
866 }
867
868 if (IsShadowBlurDrawOperation(paint)) {
869 if (rect.IsSquare()) {
870 // RRectBlurShape takes the corner radii which are half of the
871 // overall width and height of the DrawOval bounds rect.
872 RRectBlurShape shape(rect, rect.GetWidth() * 0.5f);
873 if (AttemptDrawBlur(shape, paint)) {
874 return;
875 }
876 } else {
877 EllipsePathSource source(rect);
878 if (AttemptDrawBlurredPathSource(source, paint)) {
879 return;
880 }
881 }
882 }
883
884 Entity entity;
885 entity.SetTransform(GetCurrentTransform());
886 entity.SetBlendMode(paint.blend_mode);
887
888 if (renderer_.GetContext()->GetFlags().use_sdfs &&
890 UberSDFParameters params;
891
892 if (paint.style == Paint::Style::kStroke) {
893 params = UberSDFParameters::MakeOval(paint.color, rect, paint.stroke);
894 } else {
895 params = UberSDFParameters::MakeOval(paint.color, rect, std::nullopt);
896 }
897
898 AddRenderSDFEntityToCurrentPass(paint, params);
899 return;
900 }
901
902 if (paint.style == Paint::Style::kStroke) {
903 StrokeEllipseGeometry geom(rect, paint.stroke);
904 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
905 } else {
906 EllipseGeometry geom(rect);
907 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
908 }
909}
void DrawCircle(const Point &center, Scalar radius, const Paint &paint)
Definition canvas.cc:1083
static UberSDFParameters MakeOval(Color color, const Rect &bounds, std::optional< StrokeParameters > stroke)
Creates UberSDFParameters for an Oval.

References impeller::Paint::blend_mode, impeller::Paint::color, DrawCircle(), impeller::TRect< T >::GetCenter(), impeller::ContentContext::GetContext(), GetCurrentTransform(), impeller::TRect< T >::GetWidth(), IsCompatibleWithSDFRendering(), impeller::TRect< T >::IsSquare(), impeller::Paint::kFill, impeller::Paint::kStroke, impeller::UberSDFParameters::MakeOval(), params, impeller::Entity::SetBlendMode(), impeller::Entity::SetTransform(), impeller::Paint::stroke, impeller::Paint::style, and impeller::StrokeParameters::width.

Referenced by DrawArc(), impeller::DlDispatcherBase::drawOval(), and impeller::DlDispatcherBase::SimplifyOrDrawPath().

◆ DrawPaint()

void impeller::Canvas::DrawPaint ( const Paint paint)

Definition at line 446 of file canvas.cc.

446 {
447 Entity entity;
448 entity.SetTransform(GetCurrentTransform());
449 entity.SetBlendMode(paint.blend_mode);
450
451 CoverGeometry geom;
452 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
453}

References impeller::Paint::blend_mode, GetCurrentTransform(), impeller::Entity::SetBlendMode(), and impeller::Entity::SetTransform().

Referenced by impeller::DlDispatcherBase::drawColor(), and impeller::DlDispatcherBase::drawPaint().

◆ DrawPath()

void impeller::Canvas::DrawPath ( const flutter::DlPath path,
const Paint paint 
)

Definition at line 426 of file canvas.cc.

426 {
427 if (IsShadowBlurDrawOperation(paint)) {
428 if (AttemptDrawBlurredPathSource(path, paint)) {
429 return;
430 }
431 }
432
433 Entity entity;
434 entity.SetTransform(GetCurrentTransform());
435 entity.SetBlendMode(paint.blend_mode);
436
437 if (paint.style == Paint::Style::kFill) {
438 FillPathGeometry geom(path);
439 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
440 } else {
441 StrokePathGeometry geom(path, paint.stroke);
442 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
443 }
444}

References impeller::Paint::blend_mode, GetCurrentTransform(), impeller::Paint::kFill, impeller::Entity::SetBlendMode(), impeller::Entity::SetTransform(), impeller::Paint::stroke, and impeller::Paint::style.

Referenced by impeller::DlDispatcherBase::drawPath(), DrawTextFrame(), and impeller::DlDispatcherBase::SimplifyOrDrawPath().

◆ DrawPoints()

void impeller::Canvas::DrawPoints ( const Point  points[],
uint32_t  count,
Scalar  radius,
const Paint paint,
PointStyle  point_style 
)

Definition at line 1202 of file canvas.cc.

1206 {
1207 if (radius <= 0) {
1208 return;
1209 }
1210
1211 Entity entity;
1212 entity.SetTransform(GetCurrentTransform());
1213 entity.SetBlendMode(paint.blend_mode);
1214
1215 PointFieldGeometry geom(points, count, radius,
1216 /*round=*/point_style == PointStyle::kRound);
1217 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
1218}
@ kRound
Points are drawn as squares.
std::vector< Point > points

References impeller::Paint::blend_mode, GetCurrentTransform(), impeller::kRound, points, impeller::Entity::SetBlendMode(), and impeller::Entity::SetTransform().

Referenced by impeller::DlDispatcherBase::drawPoints().

◆ DrawRect()

void impeller::Canvas::DrawRect ( const Rect rect,
const Paint paint 
)

Definition at line 825 of file canvas.cc.

825 {
826 if (IsShadowBlurDrawOperation(paint)) {
827 RRectBlurShape shape(rect, 0.0f);
828 if (AttemptDrawBlur(shape, paint)) {
829 return;
830 }
831 }
832
833 if (renderer_.GetContext()->GetFlags().use_sdfs &&
836 /*color=*/paint.color,
837 /*rect=*/rect,
838 /*stroke=*/paint.GetStroke());
839 AddRenderSDFEntityToCurrentPass(paint, params);
840 return;
841 }
842
843 Entity entity;
844 entity.SetTransform(GetCurrentTransform());
845 entity.SetBlendMode(paint.blend_mode);
846
847 if (paint.style == Paint::Style::kStroke) {
848 StrokeRectGeometry geom(rect, paint.stroke);
849 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
850 } else {
851 FillRectGeometry geom(rect);
852 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
853 }
854}
static UberSDFParameters MakeRect(Color color, const Rect &rect, std::optional< StrokeParameters > stroke)
Creates UberSDFParameters for a rectangle.

References impeller::Paint::blend_mode, impeller::Paint::color, impeller::ContentContext::GetContext(), GetCurrentTransform(), impeller::Paint::GetStroke(), IsCompatibleWithSDFRendering(), impeller::Paint::kStroke, impeller::UberSDFParameters::MakeRect(), params, impeller::Entity::SetBlendMode(), impeller::Entity::SetTransform(), impeller::Paint::stroke, and impeller::Paint::style.

Referenced by impeller::DlDispatcherBase::drawRect(), and impeller::DlDispatcherBase::SimplifyOrDrawPath().

◆ DrawRoundRect()

void impeller::Canvas::DrawRoundRect ( const RoundRect rect,
const Paint paint 
)

Definition at line 963 of file canvas.cc.

963 {
964 if (IsShadowBlurDrawOperation(paint)) {
965 if (AttemptDrawBlurredRRect(round_rect, paint)) {
966 return;
967 }
968 }
969
970 const RoundingRadii& radii = round_rect.GetRadii();
971
972 if (renderer_.GetContext()->GetFlags().use_sdfs &&
973 IsCompatibleWithSDFRendering(paint) && radii.AreAllCornersCircular()) {
975 /*color=*/paint.color,
976 /*rect=*/round_rect.GetBounds(),
977 /*radii=*/radii,
978 /*stroke=*/paint.style == Paint::Style::kStroke
979 ? std::make_optional(paint.stroke)
980 : std::nullopt);
981 AddRenderSDFEntityToCurrentPass(paint, params);
982 return;
983 }
984
985 if (round_rect.GetRadii().AreAllCornersSame() &&
986 paint.style == Paint::Style::kFill) {
987 Entity entity;
988 entity.SetTransform(GetCurrentTransform());
989 entity.SetBlendMode(paint.blend_mode);
990
991 RoundRectGeometry geom(round_rect.GetBounds(),
992 round_rect.GetRadii().top_left);
993 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
994 return;
995 }
996
997 Entity entity;
998 entity.SetTransform(GetCurrentTransform());
999 entity.SetBlendMode(paint.blend_mode);
1000
1001 if (paint.style == Paint::Style::kFill) {
1002 FillRoundRectGeometry geom(round_rect);
1003 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
1004 } else {
1005 StrokeRoundRectGeometry geom(round_rect, paint.stroke);
1006 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
1007 }
1008}
Definition ref_ptr.h:261
static UberSDFParameters MakeRoundedRect(Color color, const Rect &rect, const RoundingRadii &radii, std::optional< StrokeParameters > stroke)
Creates UberSDFParameters for a rounded rectangle.

References impeller::RoundingRadii::AreAllCornersCircular(), impeller::RoundingRadii::AreAllCornersSame(), impeller::Paint::blend_mode, impeller::Paint::color, impeller::RoundRect::GetBounds(), impeller::ContentContext::GetContext(), GetCurrentTransform(), impeller::RoundRect::GetRadii(), IsCompatibleWithSDFRendering(), impeller::Paint::kFill, impeller::Paint::kStroke, impeller::UberSDFParameters::MakeRoundedRect(), params, impeller::Entity::SetBlendMode(), impeller::Entity::SetTransform(), impeller::Paint::stroke, impeller::Paint::style, and impeller::RoundingRadii::top_left.

Referenced by impeller::DlDispatcherBase::drawRoundRect(), and impeller::DlDispatcherBase::SimplifyOrDrawPath().

◆ DrawRoundSuperellipse()

void impeller::Canvas::DrawRoundSuperellipse ( const RoundSuperellipse rse,
const Paint paint 
)

Definition at line 1026 of file canvas.cc.

1027 {
1028 if (IsShadowBlurDrawOperation(paint)) {
1029 if (AttemptDrawBlurredRSuperellipse(round_superellipse, paint)) {
1030 return;
1031 }
1032 }
1033
1034 Entity entity;
1035 entity.SetTransform(GetCurrentTransform());
1036 entity.SetBlendMode(paint.blend_mode);
1037
1038 if (renderer_.GetContext()->GetFlags().use_sdfs &&
1040 round_superellipse.GetRadii().AreAllCornersSame()) {
1041 auto round_superellipse_params = RoundSuperellipseParam::MakeBoundsRadii(
1042 round_superellipse.GetBounds(), round_superellipse.GetRadii());
1043
1044 RoundSuperellipseParam::Octant octant_top =
1045 round_superellipse_params.top_right.top;
1046 RoundSuperellipseParam::Octant octant_right =
1047 round_superellipse_params.top_right.right;
1048
1049 auto adjusted_radii = RoundingRadii::MakeRadii(
1050 Size(octant_top.circle_radius, octant_right.circle_radius));
1051
1053 /*color=*/paint.color,
1054 /*bounds=*/round_superellipse.GetBounds(),
1055 /*superellipse_degree=*/Point(octant_top.se_n, octant_right.se_n),
1056 /*superellipse_a=*/Point(octant_top.se_a, octant_right.se_a),
1057 /*radii=*/adjusted_radii,
1058 /*corner_angle_span=*/
1059 Point(octant_top.circle_max_angle.radians,
1060 octant_right.circle_max_angle.radians),
1061 /*corner_circle_center_top=*/octant_top.circle_center,
1062 /*corner_circle_center_right=*/octant_right.circle_center,
1063 /*superellipse_c=*/octant_top.se_a - octant_right.se_a,
1064 /*superellipse_scale=*/
1065 Point(round_superellipse_params.top_right.signed_scale.Abs()),
1066 /*stroke=*/paint.GetStroke());
1067
1068 AddRenderSDFEntityToCurrentPass(paint, params);
1069
1070 return;
1071 }
1072
1073 if (paint.style == Paint::Style::kFill) {
1074 RoundSuperellipseGeometry geom(round_superellipse.GetBounds(),
1075 round_superellipse.GetRadii());
1076 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
1077 } else {
1078 StrokeRoundSuperellipseGeometry geom(round_superellipse, paint.stroke);
1079 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
1080 }
1081}
TPoint< Scalar > Point
Definition point.h:426
static RoundSuperellipseParam MakeBoundsRadii(const Rect &bounds, const RoundingRadii &radii)
static constexpr RoundingRadii MakeRadii(Size radii)
static UberSDFParameters MakeRoundedSuperellipse(Color color, Rect bounds, Point superellipse_degree, Point superellipse_a, RoundingRadii radii, Point corner_angle_span, Point corner_circle_center_top, Point corner_circle_center_right, Scalar superellipse_c, Point superellipse_scale, std::optional< StrokeParameters > stroke)
Creates UberSDFParameters for a symmetric round superellipse.

References impeller::RoundingRadii::AreAllCornersSame(), impeller::Paint::blend_mode, impeller::RoundSuperellipseParam::Octant::circle_center, impeller::RoundSuperellipseParam::Octant::circle_max_angle, impeller::RoundSuperellipseParam::Octant::circle_radius, impeller::Paint::color, impeller::RoundSuperellipse::GetBounds(), impeller::ContentContext::GetContext(), GetCurrentTransform(), impeller::RoundSuperellipse::GetRadii(), impeller::Paint::GetStroke(), IsCompatibleWithSDFRendering(), impeller::Paint::kFill, impeller::RoundSuperellipseParam::MakeBoundsRadii(), impeller::RoundingRadii::MakeRadii(), impeller::UberSDFParameters::MakeRoundedSuperellipse(), params, impeller::Radians::radians, impeller::RoundSuperellipseParam::Octant::se_a, impeller::RoundSuperellipseParam::Octant::se_n, impeller::Entity::SetBlendMode(), impeller::Entity::SetTransform(), impeller::Paint::stroke, and impeller::Paint::style.

Referenced by impeller::DlDispatcherBase::drawRoundSuperellipse(), and impeller::testing::TEST_P().

◆ DrawTextFrame()

void impeller::Canvas::DrawTextFrame ( const std::shared_ptr< TextFrame > &  text_frame,
Point  position,
const Paint paint 
)

Definition at line 1960 of file canvas.cc.

1962 {
1964 if (max_scale * text_frame->GetFont().GetMetrics().point_size >
1965 kMaxTextScale) {
1966 fml::StatusOr<flutter::DlPath> path = text_frame->GetPath();
1967 if (path.ok()) {
1968 Save(1);
1970 DrawPath(path.value(), paint);
1971 Restore();
1972 return;
1973 }
1974 }
1975
1976 Entity entity;
1977 entity.SetClipDepth(GetClipHeight());
1978 entity.SetBlendMode(paint.blend_mode);
1979
1980 auto text_contents = std::make_shared<TextContents>();
1981 text_contents->SetTextFrame(text_frame);
1982 text_contents->SetPosition(position);
1983 text_contents->SetScreenTransform(GetCurrentTransform());
1984 text_contents->SetForceTextColor(paint.mask_blur_descriptor.has_value());
1985 text_contents->SetColor(paint.color);
1986 text_contents->SetTextProperties(paint.color, paint.GetStroke());
1987
1988 entity.SetTransform(GetCurrentTransform());
1989
1990 if (AttemptBlurredTextOptimization(text_frame, text_contents, entity,
1991 paint)) {
1992 return;
1993 }
1994
1995 entity.SetContents(paint.WithFilters(renderer_, std::move(text_contents)));
1996 AddRenderEntityToCurrentPass(entity, false);
1997}
void Concat(const Matrix &transform)
Definition canvas.cc:355
void DrawPath(const flutter::DlPath &path, const Paint &paint)
Definition canvas.cc:426
void Save(uint32_t total_content_depth=kMaxDepth)
Definition canvas.cc:1484
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir path
Definition switch_defs.h:52
static constexpr Scalar kMaxTextScale
Definition canvas.cc:1958
Scalar GetMaxBasisLengthXY() const
Return the maximum scale applied specifically to either the X axis or Y axis unit vectors (the bases)...
Definition matrix.h:328

References impeller::Paint::blend_mode, impeller::Paint::color, Concat(), DrawPath(), GetCurrentTransform(), impeller::Matrix::GetMaxBasisLengthXY(), impeller::Paint::GetStroke(), impeller::kMaxTextScale, impeller::Matrix::MakeTranslation(), impeller::Paint::mask_blur_descriptor, Restore(), Save(), impeller::Entity::SetBlendMode(), impeller::Entity::SetClipDepth(), impeller::Entity::SetContents(), impeller::Entity::SetTransform(), and impeller::Paint::WithFilters().

Referenced by impeller::DlDispatcherBase::drawText().

◆ DrawVertices()

void impeller::Canvas::DrawVertices ( const std::shared_ptr< VerticesGeometry > &  vertices,
BlendMode  blend_mode,
const Paint paint 
)

Definition at line 1301 of file canvas.cc.

1303 {
1304 // Override the blend mode with kDestination in order to match the behavior
1305 // of Skia's SK_LEGACY_IGNORE_DRAW_VERTICES_BLEND_WITH_NO_SHADER flag, which
1306 // is enabled when the Flutter engine builds Skia.
1307 if (!paint.color_source) {
1308 blend_mode = BlendMode::kDst;
1309 }
1310
1311 Entity entity;
1312 entity.SetTransform(GetCurrentTransform());
1313 entity.SetBlendMode(paint.blend_mode);
1314
1315 // If there are no vertex colors.
1316 if (UseColorSourceContents(vertices, paint)) {
1317 AddRenderEntityWithFiltersToCurrentPass(entity, vertices.get(), paint);
1318 return;
1319 }
1320
1321 // If the blend mode is destination don't bother to bind or create a texture.
1322 if (blend_mode == BlendMode::kDst) {
1323 auto contents = std::make_shared<VerticesSimpleBlendContents>();
1324 contents->SetBlendMode(blend_mode);
1325 contents->SetAlpha(paint.color.alpha);
1326 contents->SetGeometry(vertices);
1327 entity.SetContents(paint.WithFilters(renderer_, std::move(contents)));
1328 AddRenderEntityToCurrentPass(entity);
1329 return;
1330 }
1331
1332 // If there is a texture, use this directly. Otherwise render the color
1333 // source to a texture.
1334 if (paint.color_source &&
1335 paint.color_source->type() == flutter::DlColorSourceType::kImage) {
1336 const flutter::DlImageColorSource* image_color_source =
1337 paint.color_source->asImage();
1338 FML_DCHECK(image_color_source);
1339 auto texture =
1340 image_color_source->image()->asImpellerImage()->GetCachedTexture(
1341 renderer_);
1343 auto x_tile_mode = static_cast<Entity::TileMode>(
1344 image_color_source->horizontal_tile_mode());
1345 auto y_tile_mode =
1346 static_cast<Entity::TileMode>(image_color_source->vertical_tile_mode());
1347 auto sampler_descriptor =
1348 skia_conversions::ToSamplerDescriptor(image_color_source->sampling());
1349 auto effect_transform = image_color_source->matrix();
1350
1351 auto contents = std::make_shared<VerticesSimpleBlendContents>();
1352 contents->SetBlendMode(blend_mode);
1353 contents->SetAlpha(paint.color.alpha);
1354 contents->SetGeometry(vertices);
1355 contents->SetEffectTransform(effect_transform);
1356 contents->SetTexture(texture);
1357 contents->SetTileMode(x_tile_mode, y_tile_mode);
1358 contents->SetSamplerDescriptor(sampler_descriptor);
1359
1360 entity.SetContents(paint.WithFilters(renderer_, std::move(contents)));
1361 AddRenderEntityToCurrentPass(entity);
1362 return;
1363 }
1364
1365 auto src_paint = paint;
1366 src_paint.color = paint.color.WithAlpha(1.0);
1367
1368 std::shared_ptr<ColorSourceContents> src_contents =
1369 src_paint.CreateContents(renderer_, vertices.get());
1370
1371 // If the color source has an intrinsic size, then we use that to
1372 // create the src contents as a simplification. Otherwise we use
1373 // the extent of the texture coordinates to determine how large
1374 // the src contents should be. If neither has a value we fall back
1375 // to using the geometry coverage data.
1376 Rect src_coverage;
1377 auto size = src_contents->GetColorSourceSize();
1378 if (size.has_value()) {
1379 src_coverage = Rect::MakeXYWH(0, 0, size->width, size->height);
1380 } else {
1381 auto cvg = vertices->GetCoverage(Matrix{});
1382 FML_CHECK(cvg.has_value());
1383 auto texture_coverage = vertices->GetTextureCoordinateCoverage();
1384 if (texture_coverage.has_value()) {
1385 src_coverage =
1386 Rect::MakeOriginSize(texture_coverage->GetOrigin(),
1387 texture_coverage->GetSize().Max({1, 1}));
1388 } else {
1389 // NOLINTNEXTLINE(bugprone-unchecked-optional-access)
1390 src_coverage = cvg.value();
1391 }
1392 }
1393 clip_geometry_.push_back(Geometry::MakeRect(Rect::Round(src_coverage)));
1394 src_contents =
1395 src_paint.CreateContents(renderer_, clip_geometry_.back().get());
1396
1397 auto contents = std::make_shared<VerticesSimpleBlendContents>();
1398 contents->SetBlendMode(blend_mode);
1399 contents->SetAlpha(paint.color.alpha);
1400 contents->SetGeometry(vertices);
1401 contents->SetLazyTextureCoverage(src_coverage);
1402 contents->SetLazyTexture(
1403 [src_contents, src_coverage](
1404 const ContentContext& renderer) -> std::shared_ptr<Texture> {
1405 // Applying the src coverage as the coverage limit prevents the 1px
1406 // coverage pad from adding a border that is picked up by developer
1407 // specified UVs.
1408 auto snapshot = src_contents->RenderToSnapshot(
1409 renderer, {}, {.coverage_limit = Rect::Round(src_coverage)});
1410 return snapshot.has_value() ? snapshot->texture : nullptr;
1411 });
1412 entity.SetContents(paint.WithFilters(renderer_, std::move(contents)));
1413 AddRenderEntityToCurrentPass(entity);
1414}
DlImageSampling sampling() const
const DlImageColorSource * asImage() const override
DlTileMode horizontal_tile_mode() const
sk_sp< const DlImage > image() const
static std::unique_ptr< Geometry > MakeRect(const Rect &rect)
Definition geometry.cc:83
#define FML_CHECK(condition)
Definition logging.h:104
FlTexture * texture
impeller::SamplerDescriptor ToSamplerDescriptor(const flutter::DlImageSampling options)
Round(const TRect< U > &r)
Definition rect.h:729
static constexpr TRect MakeOriginSize(const TPoint< Type > &origin, const TSize< Type > &size)
Definition rect.h:144
static constexpr TRect MakeXYWH(Type x, Type y, Type width, Type height)
Definition rect.h:136

References impeller::Color::alpha, flutter::DlColorSource::asImage(), impeller::Paint::blend_mode, impeller::Paint::color, impeller::Paint::color_source, FML_CHECK, FML_DCHECK, GetCurrentTransform(), flutter::DlImageColorSource::horizontal_tile_mode(), flutter::DlImageColorSource::image(), impeller::kDst, flutter::kImage, impeller::TRect< Scalar >::MakeOriginSize(), impeller::Geometry::MakeRect(), impeller::TRect< Scalar >::MakeXYWH(), flutter::DlMatrixColorSourceBase::matrix(), impeller::TRect< Scalar >::Round(), flutter::DlImageColorSource::sampling(), impeller::Entity::SetBlendMode(), impeller::Entity::SetContents(), impeller::Entity::SetTransform(), texture, impeller::skia_conversions::ToSamplerDescriptor(), flutter::DlAttribute< D, T >::type(), flutter::DlImageColorSource::vertical_tile_mode(), impeller::Color::WithAlpha(), and impeller::Paint::WithFilters().

Referenced by impeller::CanvasDlDispatcher::drawVertices(), impeller::testing::TEST_P(), and impeller::testing::TEST_P().

◆ EndReplay()

void impeller::Canvas::EndReplay ( )

Definition at line 2428 of file canvas.cc.

2428 {
2429 FML_DCHECK(render_passes_.size() == 1u);
2430 render_passes_.back().GetInlinePassContext()->GetRenderPass();
2431 render_passes_.back().GetInlinePassContext()->EndPass(
2432 /*is_onscreen=*/!requires_readback_ && is_onscreen_);
2433 backdrop_data_.clear();
2434
2435 // If requires_readback_ was true, then we rendered to an offscreen texture
2436 // instead of to the onscreen provided in the render target. Now we need to
2437 // draw or blit the offscreen back to the onscreen.
2438 if (requires_readback_) {
2439 BlitToOnscreen(/*is_onscreen_=*/is_onscreen_);
2440 }
2442 VALIDATION_LOG << "Failed to generate onscreen mipmaps.";
2443 }
2444 if (!renderer_.GetContext()->FlushCommandBuffers()) {
2445 // Not much we can do.
2446 VALIDATION_LOG << "Failed to submit command buffers";
2447 }
2448 render_passes_.clear();
2449 renderer_.GetRenderTargetCache()->End();
2450 clip_geometry_.clear();
2451
2452 Reset();
2453 Initialize(initial_cull_rect_);
2454}
bool EnsureFinalMipmapGeneration() const
Definition canvas.cc:2410
const std::shared_ptr< RenderTargetAllocator > & GetRenderTargetCache() const
#define VALIDATION_LOG
Definition validation.h:91

References FML_DCHECK, and VALIDATION_LOG.

Referenced by impeller::CanvasDlDispatcher::FinishRecording(), impeller::testing::TEST_P(), impeller::testing::TEST_P(), and impeller::testing::TEST_P().

◆ EnsureFinalMipmapGeneration()

bool impeller::Canvas::EnsureFinalMipmapGeneration ( ) const

For picture snapshots we need addition steps to verify that final mipmaps are generated.

Definition at line 2410 of file canvas.cc.

2410 {
2411 if (!render_target_.GetRenderTargetTexture()->NeedsMipmapGeneration()) {
2412 return true;
2413 }
2414 std::shared_ptr<CommandBuffer> cmd_buffer =
2415 renderer_.GetContext()->CreateCommandBuffer();
2416 if (!cmd_buffer) {
2417 return false;
2418 }
2419 std::shared_ptr<BlitPass> blit_pass = cmd_buffer->CreateBlitPass();
2420 if (!blit_pass) {
2421 return false;
2422 }
2423 blit_pass->GenerateMipmap(render_target_.GetRenderTargetTexture());
2424 blit_pass->EncodeCommands();
2425 return renderer_.GetContext()->EnqueueCommandBuffer(std::move(cmd_buffer));
2426}
std::shared_ptr< Texture > GetRenderTargetTexture() const

◆ GetCurrentTransform()

◆ GetLocalCoverageLimit()

std::optional< Rect > impeller::Canvas::GetLocalCoverageLimit ( ) const

Return the culling bounds of the current render target, or nullopt if there is no coverage.

Definition at line 1501 of file canvas.cc.

1501 {
1502 if (!clip_coverage_stack_.HasCoverage()) {
1503 // The current clip is empty. This means the pass texture won't be
1504 // visible, so skip it.
1505 return std::nullopt;
1506 }
1507
1508 std::optional<Rect> maybe_current_clip_coverage =
1509 clip_coverage_stack_.CurrentClipCoverage();
1510 if (!maybe_current_clip_coverage.has_value()) {
1511 return std::nullopt;
1512 }
1513
1514 Rect current_clip_coverage = maybe_current_clip_coverage.value();
1515
1516 FML_CHECK(!render_passes_.empty());
1517 const LazyRenderingConfig& back_render_pass = render_passes_.back();
1518 std::shared_ptr<Texture> back_texture =
1519 back_render_pass.GetInlinePassContext()->GetTexture();
1520 FML_CHECK(back_texture) << "Context is valid:"
1521 << back_render_pass.GetInlinePassContext()->IsValid();
1522
1523 // The maximum coverage of the subpass. Subpasses textures should never
1524 // extend outside the parent pass texture or the current clip coverage.
1525 std::optional<Rect> maybe_coverage_limit =
1526 Rect::MakeOriginSize(GetGlobalPassPosition(),
1527 Size(back_texture->GetSize()))
1528 .Intersection(current_clip_coverage);
1529
1530 if (!maybe_coverage_limit.has_value() || maybe_coverage_limit->IsEmpty()) {
1531 return std::nullopt;
1532 }
1533
1534 return maybe_coverage_limit->Intersection(
1535 Rect::MakeSize(render_target_.GetRenderTargetSize()));
1536}
ISize GetRenderTargetSize() const
constexpr std::optional< TRect > Intersection(const TRect &o) const
Definition rect.h:562

References impeller::EntityPassClipStack::CurrentClipCoverage(), FML_CHECK, impeller::LazyRenderingConfig::GetInlinePassContext(), impeller::RenderTarget::GetRenderTargetSize(), impeller::InlinePassContext::GetTexture(), impeller::EntityPassClipStack::HasCoverage(), impeller::TRect< T >::Intersection(), impeller::InlinePassContext::IsValid(), impeller::TRect< Scalar >::MakeOriginSize(), and impeller::TRect< Scalar >::MakeSize().

Referenced by impeller::DlDispatcherBase::drawDisplayList(), and SaveLayer().

◆ GetMaxOpDepth()

uint64_t impeller::Canvas::GetMaxOpDepth ( ) const
inline

Definition at line 257 of file canvas.h.

257{ return transform_stack_.back().clip_depth; }

◆ GetOpDepth()

uint64_t impeller::Canvas::GetOpDepth ( ) const
inline

Definition at line 255 of file canvas.h.

255{ return current_depth_; }

◆ GetSaveCount()

size_t impeller::Canvas::GetSaveCount ( ) const

Definition at line 410 of file canvas.cc.

410 {
411 return transform_stack_.size();
412}

Referenced by impeller::DlDispatcherBase::drawDisplayList(), and RestoreToCount().

◆ IsCompatibleWithSDFRendering()

bool impeller::Canvas::IsCompatibleWithSDFRendering ( const Paint paint)
static

Returns true if the paint is compatible with SDF rendering.

Visible for testing.

Definition at line 2456 of file canvas.cc.

2456 {
2457 if (!paint.anti_alias) {
2458 return false;
2459 }
2460 if (paint.mask_blur_descriptor.has_value()) {
2461 return false;
2462 }
2463 switch (paint.blend_mode) {
2464 // Incompatible blend modes:
2465 case BlendMode::kClear:
2466 case BlendMode::kSrc:
2467 case BlendMode::kSrcIn:
2468 case BlendMode::kDstIn:
2469 case BlendMode::kSrcOut:
2471 case BlendMode::kPlus:
2473 return false;
2474 // Compatible blend modes:
2475 case BlendMode::kDst:
2478 case BlendMode::kDstOut:
2480 case BlendMode::kXor:
2481 case BlendMode::kScreen:
2483 case BlendMode::kDarken:
2492 case BlendMode::kHue:
2494 case BlendMode::kColor:
2496 return true;
2497 }
2498}

References impeller::Paint::anti_alias, impeller::Paint::blend_mode, and impeller::Paint::mask_blur_descriptor.

Referenced by DrawCircle(), DrawOval(), DrawRect(), DrawRoundRect(), DrawRoundSuperellipse(), impeller::testing::TEST(), impeller::testing::TEST(), and impeller::testing::TEST_P().

◆ PreConcat()

void impeller::Canvas::PreConcat ( const Matrix transform)

Definition at line 359 of file canvas.cc.

359 {
360 transform_stack_.back().transform = transform * GetCurrentTransform();
361}

References GetCurrentTransform(), and transform.

Referenced by impeller::DlDispatcherBase::drawShadow().

◆ RequiresReadback()

bool impeller::Canvas::RequiresReadback ( ) const
inline

Definition at line 265 of file canvas.h.

265{ return requires_readback_; }

◆ ResetTransform()

void impeller::Canvas::ResetTransform ( )

Definition at line 363 of file canvas.cc.

363 {
364 transform_stack_.back().transform = {};
365}

Referenced by impeller::DlDispatcherBase::transformReset().

◆ Restore()

bool impeller::Canvas::Restore ( )

Definition at line 1768 of file canvas.cc.

1768 {
1769 FML_DCHECK(transform_stack_.size() > 0);
1770 if (transform_stack_.size() == 1) {
1771 return false;
1772 }
1773
1774 // This check is important to make sure we didn't exceed the depth
1775 // that the clips were rendered at while rendering any of the
1776 // rendering ops. It is OK for the current depth to equal the
1777 // outgoing clip depth because that means the clipping would have
1778 // been successful up through the last rendering op, but it cannot
1779 // be greater.
1780 // Also, we bump the current rendering depth to the outgoing clip
1781 // depth so that future rendering operations are not clipped by
1782 // any of the pixels set by the expiring clips. It is OK for the
1783 // estimates used to determine the clip depth in save/saveLayer
1784 // to be overly conservative, but we need to jump the depth to
1785 // the clip depth so that the next rendering op will get a
1786 // larger depth (it will pre-increment the current_depth_ value).
1787 FML_DCHECK(current_depth_ <= transform_stack_.back().clip_depth)
1788 << current_depth_ << " <=? " << transform_stack_.back().clip_depth;
1789 current_depth_ = transform_stack_.back().clip_depth;
1790
1791 if (IsSkipping()) {
1792 transform_stack_.pop_back();
1793 return true;
1794 }
1795
1796 if (transform_stack_.back().rendering_mode ==
1798 transform_stack_.back().rendering_mode ==
1800 auto lazy_render_pass = std::move(render_passes_.back());
1801 render_passes_.pop_back();
1802 // Force the render pass to be constructed if it never was.
1803 lazy_render_pass.GetInlinePassContext()->GetRenderPass();
1804
1805 SaveLayerState save_layer_state = save_layer_state_.back();
1806 save_layer_state_.pop_back();
1807 auto global_pass_position = GetGlobalPassPosition();
1808
1809 std::shared_ptr<Contents> contents = CreateContentsForSubpassTarget(
1810 renderer_, save_layer_state.paint, //
1811 lazy_render_pass.GetInlinePassContext()->GetTexture(), //
1812 Matrix::MakeTranslation(Vector3{-global_pass_position}) * //
1813 transform_stack_.back().transform //
1814 );
1815
1816 lazy_render_pass.GetInlinePassContext()->EndPass();
1817
1818 // Round the subpass texture position for pixel alignment with the parent
1819 // pass render target. By default, we draw subpass textures with nearest
1820 // sampling, so aligning here is important for avoiding visual nearest
1821 // sampling errors caused by limited floating point precision when
1822 // straddling a half pixel boundary.
1823 Point subpass_texture_position;
1824 if (transform_stack_.back().did_round_out) {
1825 // Subpass coverage was rounded out, origin potentially moved "down" by
1826 // as much as a pixel.
1827 subpass_texture_position =
1828 (save_layer_state.coverage.GetOrigin() - global_pass_position)
1829 .Floor();
1830 } else {
1831 // Subpass coverage was truncated. Pick the closest phyiscal pixel.
1832 subpass_texture_position =
1833 (save_layer_state.coverage.GetOrigin() - global_pass_position)
1834 .Round();
1835 }
1836
1837 Entity element_entity;
1838 element_entity.SetClipDepth(++current_depth_);
1839 element_entity.SetContents(std::move(contents));
1840 element_entity.SetBlendMode(save_layer_state.paint.blend_mode);
1841 element_entity.SetTransform(
1842 Matrix::MakeTranslation(Vector3(subpass_texture_position)));
1843
1844 if (element_entity.GetBlendMode() > Entity::kLastPipelineBlendMode) {
1846 ApplyFramebufferBlend(element_entity);
1847 } else {
1848 // End the active pass and flush the buffer before rendering "advanced"
1849 // blends. Advanced blends work by binding the current render target
1850 // texture as an input ("destination"), blending with a second texture
1851 // input ("source"), writing the result to an intermediate texture, and
1852 // finally copying the data from the intermediate texture back to the
1853 // render target texture. And so all of the commands that have written
1854 // to the render target texture so far need to execute before it's bound
1855 // for blending (otherwise the blend pass will end up executing before
1856 // all the previous commands in the active pass).
1857 auto input_texture = FlipBackdrop(GetGlobalPassPosition());
1858 if (!input_texture) {
1859 return false;
1860 }
1861
1862 FilterInput::Vector inputs = {
1863 FilterInput::Make(input_texture,
1864 element_entity.GetTransform().Invert()),
1865 FilterInput::Make(element_entity.GetContents())};
1866 auto contents = ColorFilterContents::MakeBlend(
1867 element_entity.GetBlendMode(), inputs);
1868 contents->SetCoverageHint(element_entity.GetCoverage());
1869 element_entity.SetContents(std::move(contents));
1870 element_entity.SetBlendMode(BlendMode::kSrc);
1871 }
1872 }
1873
1874 element_entity.Render(
1875 renderer_, //
1876 *render_passes_.back().GetInlinePassContext()->GetRenderPass() //
1877 );
1878 clip_coverage_stack_.PopSubpass();
1879 transform_stack_.pop_back();
1880
1881 // We don't need to restore clips if a saveLayer was performed, as the clip
1882 // state is per render target, and no more rendering operations will be
1883 // performed as the render target workloaded is completed in the restore.
1884 return true;
1885 }
1886
1887 size_t num_clips = transform_stack_.back().num_clips;
1888 transform_stack_.pop_back();
1889
1890 if (num_clips > 0) {
1891 EntityPassClipStack::ClipStateResult clip_state_result =
1892 clip_coverage_stack_.RecordRestore(GetGlobalPassPosition(),
1893 GetClipHeight());
1894
1895 // Clip restores are never required with depth based clipping.
1896 FML_DCHECK(!clip_state_result.should_render);
1897 if (clip_state_result.clip_did_change) {
1898 // We only need to update the pass scissor if the clip state has changed.
1899 SetClipScissor(
1900 clip_coverage_stack_.CurrentClipCoverage(), //
1901 *render_passes_.back().GetInlinePassContext()->GetRenderPass(), //
1902 GetGlobalPassPosition() //
1903 );
1904 }
1905 }
1906
1907 return true;
1908}
virtual bool SupportsFramebufferFetch() const =0
Whether the context backend is able to support pipelines with shaders that read from the framebuffer ...
static std::shared_ptr< ColorFilterContents > MakeBlend(BlendMode blend_mode, FilterInput::Vector inputs, std::optional< Color > foreground_color=std::nullopt)
the [inputs] are expected to be in the order of dst, src.
const Capabilities & GetDeviceCapabilities() const
static constexpr BlendMode kLastPipelineBlendMode
Definition entity.h:28
ClipStateResult RecordRestore(Point global_pass_position, size_t restore_height)
static FilterInput::Ref Make(Variant input, bool msaa_enabled=true)
std::vector< FilterInput::Ref > Vector

References impeller::Paint::blend_mode, impeller::EntityPassClipStack::ClipStateResult::clip_did_change, impeller::Canvas::SaveLayerState::coverage, impeller::EntityPassClipStack::CurrentClipCoverage(), FML_DCHECK, impeller::Entity::GetBlendMode(), impeller::Entity::GetContents(), impeller::Entity::GetCoverage(), impeller::ContentContext::GetDeviceCapabilities(), impeller::TRect< T >::GetOrigin(), impeller::Entity::GetTransform(), impeller::Matrix::Invert(), impeller::Entity::kLastPipelineBlendMode, impeller::kSrc, impeller::Entity::kSubpassAppendSnapshotTransform, impeller::Entity::kSubpassPrependSnapshotTransform, impeller::FilterInput::Make(), impeller::ColorFilterContents::MakeBlend(), impeller::Matrix::MakeTranslation(), impeller::Canvas::SaveLayerState::paint, impeller::EntityPassClipStack::PopSubpass(), impeller::EntityPassClipStack::RecordRestore(), impeller::Entity::Render(), impeller::Entity::SetBlendMode(), impeller::Entity::SetClipDepth(), impeller::Entity::SetContents(), impeller::Entity::SetTransform(), impeller::EntityPassClipStack::ClipStateResult::should_render, and impeller::Capabilities::SupportsFramebufferFetch().

Referenced by impeller::DlDispatcherBase::drawShadow(), DrawTextFrame(), impeller::DlDispatcherBase::restore(), and RestoreToCount().

◆ RestoreToCount()

void impeller::Canvas::RestoreToCount ( size_t  count)

Definition at line 418 of file canvas.cc.

418 {
419 while (GetSaveCount() > count) {
420 if (!Restore()) {
421 return;
422 }
423 }
424}
size_t GetSaveCount() const
Definition canvas.cc:410

References GetSaveCount(), and Restore().

Referenced by impeller::DlDispatcherBase::drawDisplayList().

◆ Rotate()

void impeller::Canvas::Rotate ( Radians  radians)

Definition at line 391 of file canvas.cc.

391 {
393}
static Matrix MakeRotationZ(Radians r)
Definition matrix.h:223

References Concat(), and impeller::Matrix::MakeRotationZ().

Referenced by impeller::DlDispatcherBase::rotate().

◆ Save()

void impeller::Canvas::Save ( uint32_t  total_content_depth = kMaxDepth)

Definition at line 1484 of file canvas.cc.

1484 {
1485 if (IsSkipping()) {
1486 return SkipUntilMatchingRestore(total_content_depth);
1487 }
1488
1489 auto entry = CanvasStackEntry{};
1490 entry.transform = transform_stack_.back().transform;
1491 entry.clip_depth = current_depth_ + total_content_depth;
1492 entry.distributed_opacity = transform_stack_.back().distributed_opacity;
1493 FML_DCHECK(entry.clip_depth <= transform_stack_.back().clip_depth)
1494 << entry.clip_depth << " <=? " << transform_stack_.back().clip_depth
1495 << " after allocating " << total_content_depth;
1496 entry.clip_height = transform_stack_.back().clip_height;
1497 entry.rendering_mode = Entity::RenderingMode::kDirect;
1498 transform_stack_.push_back(entry);
1499}

References FML_DCHECK, impeller::Entity::kDirect, and impeller::CanvasStackEntry::transform.

Referenced by impeller::DlDispatcherBase::drawDisplayList(), impeller::DlDispatcherBase::drawShadow(), DrawTextFrame(), impeller::DlDispatcherBase::save(), and SaveLayer().

◆ SaveLayer()

void impeller::Canvas::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 
)

Definition at line 1538 of file canvas.cc.

1544 {
1545 TRACE_EVENT0("flutter", "Canvas::saveLayer");
1546 if (IsSkipping()) {
1547 return SkipUntilMatchingRestore(total_content_depth);
1548 }
1549
1550 auto maybe_coverage_limit = GetLocalCoverageLimit();
1551 if (!maybe_coverage_limit.has_value()) {
1552 return SkipUntilMatchingRestore(total_content_depth);
1553 }
1554 auto coverage_limit = maybe_coverage_limit.value();
1555
1556 if (can_distribute_opacity && !backdrop_filter &&
1558 bounds_promise != ContentBoundsPromise::kMayClipContents) {
1559 Save(total_content_depth);
1560 transform_stack_.back().distributed_opacity *= paint.color.alpha;
1561 return;
1562 }
1563
1564 std::shared_ptr<FilterContents> filter_contents = paint.WithImageFilter(
1565 renderer_, Rect(), transform_stack_.back().transform,
1567
1568 std::optional<Rect> maybe_subpass_coverage = ComputeSaveLayerCoverage(
1569 bounds.value_or(Rect::MakeMaximum()),
1570 transform_stack_.back().transform, //
1571 coverage_limit, //
1572 filter_contents, //
1573 /*flood_output_coverage=*/
1574 Entity::IsBlendModeDestructive(paint.blend_mode), //
1575 /*flood_input_coverage=*/!!backdrop_filter ||
1576 (paint.color_filter &&
1577 paint.color_filter->modifies_transparent_black()) //
1578 );
1579
1580 if (!maybe_subpass_coverage.has_value()) {
1581 return SkipUntilMatchingRestore(total_content_depth);
1582 }
1583
1584 auto subpass_coverage = maybe_subpass_coverage.value();
1585
1586 // When an image filter is present, clamp to avoid flicking due to nearest
1587 // sampled image. For other cases, round out to ensure than any geometry is
1588 // not cut off.
1589 //
1590 // See also this bug: https://github.com/flutter/flutter/issues/144213
1591 //
1592 // TODO(jonahwilliams): this could still round out for filters that use decal
1593 // sampling mode.
1595 bool did_round_out = false;
1596 Point coverage_origin_adjustment = Point{0, 0};
1597 if (paint.image_filter) {
1598 subpass_size = ISize(subpass_coverage.GetSize());
1599 } else {
1600 did_round_out = true;
1601 subpass_size =
1602 static_cast<ISize>(IRect::RoundOut(subpass_coverage).GetSize());
1603 // If rounding out, adjust the coverage to account for the subpixel shift.
1604 coverage_origin_adjustment =
1605 Point(subpass_coverage.GetLeftTop().x -
1606 std::floor(subpass_coverage.GetLeftTop().x),
1607 subpass_coverage.GetLeftTop().y -
1608 std::floor(subpass_coverage.GetLeftTop().y));
1609 }
1610 if (subpass_size.IsEmpty()) {
1611 return SkipUntilMatchingRestore(total_content_depth);
1612 }
1613
1614 // When there are scaling filters present, these contents may exceed the
1615 // maximum texture size. Perform a clamp here, which may cause rendering
1616 // artifacts.
1617 subpass_size = subpass_size.Min(renderer_.GetContext()
1618 ->GetCapabilities()
1619 ->GetMaximumRenderPassAttachmentSize());
1620
1621 // Backdrop filter state, ignored if there is no BDF.
1622 std::shared_ptr<FilterContents> backdrop_filter_contents;
1623 Point local_position = Point(0, 0);
1624 if (backdrop_filter) {
1625 local_position = subpass_coverage.GetOrigin() - GetGlobalPassPosition();
1626
1627 std::shared_ptr<Texture> input_texture;
1628
1629 // If the backdrop ID is not nullopt and there is more than one usage
1630 // of it in the current scene, cache the backdrop texture and remove it from
1631 // the current entity pass flip.
1632 bool will_cache_backdrop_texture = false;
1633 BackdropData* backdrop_data = nullptr;
1634 // If we've reached this point, there is at least one backdrop filter. But
1635 // potentially more if there is a backdrop id. We may conditionally set this
1636 // to a higher value in the if block below.
1637 size_t backdrop_count = 1;
1638 if (backdrop_id.has_value()) {
1639 std::unordered_map<int64_t, BackdropData>::iterator backdrop_data_it =
1640 backdrop_data_.find(backdrop_id.value());
1641 if (backdrop_data_it != backdrop_data_.end()) {
1642 backdrop_data = &backdrop_data_it->second;
1643 will_cache_backdrop_texture =
1644 backdrop_data_it->second.backdrop_count > 1;
1645 backdrop_count = backdrop_data_it->second.backdrop_count;
1646 }
1647 }
1648
1649 if (!will_cache_backdrop_texture || !backdrop_data->texture_slot) {
1650 backdrop_count_ -= backdrop_count;
1651
1652 // The onscreen texture can be flipped to if:
1653 // 1. The device supports framebuffer fetch
1654 // 2. There are no more backdrop filters
1655 // 3. The current render pass is for the onscreen pass.
1656 const bool should_use_onscreen =
1658 backdrop_count_ == 0 && render_passes_.size() == 1u;
1659 input_texture = FlipBackdrop(
1660 GetGlobalPassPosition(), //
1661 /*should_remove_texture=*/will_cache_backdrop_texture, //
1662 /*should_use_onscreen=*/should_use_onscreen //
1663 );
1664 if (!input_texture) {
1665 // Validation failures are logged in FlipBackdrop.
1666 return;
1667 }
1668
1669 if (will_cache_backdrop_texture) {
1670 backdrop_data->texture_slot = input_texture;
1671 }
1672 } else {
1673 input_texture = backdrop_data->texture_slot;
1674 }
1675
1676 backdrop_filter_contents =
1677 WrapInput(renderer_, backdrop_filter,
1678 FilterInput::Make(std::move(input_texture)));
1679 backdrop_filter_contents->SetEffectTransform(
1680 transform_stack_.back().transform.Basis());
1681 backdrop_filter_contents->SetRenderingMode(
1682 transform_stack_.back().transform.HasTranslation()
1684 : Entity::RenderingMode::kSubpassAppendSnapshotTransform);
1685
1686 if (will_cache_backdrop_texture) {
1687 FML_DCHECK(backdrop_data);
1688 // If all filters on the shared backdrop layer are equal, process the
1689 // layer once.
1690 if (backdrop_data->all_filters_equal &&
1691 !backdrop_data->shared_filter_snapshot.has_value()) {
1692 // TODO(157110): compute minimum input hint.
1693 backdrop_data->shared_filter_snapshot =
1694 backdrop_filter_contents->RenderToSnapshot(renderer_, {}, {});
1695 }
1696
1697 std::optional<Snapshot> maybe_snapshot =
1698 backdrop_data->shared_filter_snapshot;
1699 if (maybe_snapshot.has_value()) {
1700 const Snapshot& snapshot = maybe_snapshot.value();
1701 std::shared_ptr<TextureContents> contents = TextureContents::MakeRect(
1702 subpass_coverage.Shift(-GetGlobalPassPosition()));
1703 auto scaled =
1704 subpass_coverage.TransformBounds(snapshot.transform.Invert());
1705 contents->SetTexture(snapshot.texture);
1706 contents->SetSourceRect(scaled);
1707 contents->SetSamplerDescriptor(snapshot.sampler_descriptor);
1708
1709 // This backdrop entity sets a depth value as it is written to the newly
1710 // flipped backdrop and not into a new saveLayer.
1711 Entity backdrop_entity;
1712 backdrop_entity.SetContents(std::move(contents));
1713 backdrop_entity.SetClipDepth(++current_depth_);
1714 backdrop_entity.SetBlendMode(paint.blend_mode);
1715
1716 backdrop_entity.Render(renderer_, GetCurrentRenderPass());
1717 Save(0);
1718 return;
1719 }
1720 }
1721 }
1722
1723 // When applying a save layer, absorb any pending distributed opacity.
1724 Paint paint_copy = paint;
1725 paint_copy.color.alpha *= transform_stack_.back().distributed_opacity;
1726 transform_stack_.back().distributed_opacity = 1.0;
1727
1728 render_passes_.push_back(
1729 LazyRenderingConfig(renderer_, //
1730 CreateRenderTarget(renderer_, //
1731 subpass_size, //
1733 )));
1734 save_layer_state_.push_back(SaveLayerState{
1735 paint_copy, subpass_coverage.Shift(-coverage_origin_adjustment)});
1736
1737 CanvasStackEntry entry;
1738 entry.transform = transform_stack_.back().transform;
1739 entry.clip_depth = current_depth_ + total_content_depth;
1740 FML_DCHECK(entry.clip_depth <= transform_stack_.back().clip_depth)
1741 << entry.clip_depth << " <=? " << transform_stack_.back().clip_depth
1742 << " after allocating " << total_content_depth;
1743 entry.clip_height = transform_stack_.back().clip_height;
1745 entry.did_round_out = did_round_out;
1746 transform_stack_.emplace_back(entry);
1747
1748 // Start non-collapsed subpasses with a fresh clip coverage stack limited by
1749 // the subpass coverage. This is important because image filters applied to
1750 // save layers may transform the subpass texture after it's rendered,
1751 // causing parent clip coverage to get misaligned with the actual area that
1752 // the subpass will affect in the parent pass.
1753 clip_coverage_stack_.PushSubpass(subpass_coverage, GetClipHeight());
1754
1755 if (!backdrop_filter_contents) {
1756 return;
1757 }
1758
1759 // Render the backdrop entity.
1760 Entity backdrop_entity;
1761 backdrop_entity.SetContents(std::move(backdrop_filter_contents));
1762 backdrop_entity.SetTransform(
1763 Matrix::MakeTranslation(Vector3(-local_position)));
1764 backdrop_entity.SetClipDepth(std::numeric_limits<uint32_t>::max());
1765 backdrop_entity.Render(renderer_, GetCurrentRenderPass());
1766}
std::optional< Rect > GetLocalCoverageLimit() const
Return the culling bounds of the current render target, or nullopt if there is no coverage.
Definition canvas.cc:1501
static bool IsBlendModeDestructive(BlendMode blend_mode)
Returns true if the blend mode is "destructive", meaning that even fully transparent source colors wo...
Definition entity.cc:128
void PushSubpass(std::optional< Rect > subpass_coverage, size_t clip_height)
ISize subpass_size
The output size of the down-sampling pass.
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...
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.
static constexpr Color BlackTransparent()
Definition color.h:275
static bool CanApplyOpacityPeephole(const Paint &paint)
Whether or not a save layer with the provided paint can perform the opacity peephole optimization.
Definition paint.h:42
RoundOut(const TRect< U > &r)
Definition rect.h:713
static constexpr TRect MakeMaximum()
Definition rect.h:212
#define TRACE_EVENT0(category_group, name)

References impeller::BackdropData::all_filters_equal, impeller::Color::alpha, impeller::BackdropData::backdrop_count, impeller::Color::BlackTransparent(), impeller::Paint::blend_mode, impeller::Paint::CanApplyOpacityPeephole(), impeller::CanvasStackEntry::clip_depth, impeller::CanvasStackEntry::clip_height, impeller::Paint::color, impeller::Paint::color_filter, impeller::ComputeSaveLayerCoverage(), impeller::CanvasStackEntry::did_round_out, FML_DCHECK, impeller::ContentContext::GetContext(), impeller::ContentContext::GetDeviceCapabilities(), GetLocalCoverageLimit(), impeller::Paint::image_filter, impeller::Matrix::Invert(), impeller::Entity::IsBlendModeDestructive(), impeller::kMayClipContents, impeller::Entity::kSubpassAppendSnapshotTransform, impeller::Entity::kSubpassPrependSnapshotTransform, impeller::FilterInput::Make(), impeller::TRect< Scalar >::MakeMaximum(), impeller::TextureContents::MakeRect(), impeller::Matrix::MakeTranslation(), flutter::DlColorFilter::modifies_transparent_black(), impeller::EntityPassClipStack::PushSubpass(), impeller::Entity::Render(), impeller::CanvasStackEntry::rendering_mode, impeller::TRect< T >::RoundOut(), impeller::Snapshot::sampler_descriptor, Save(), impeller::Entity::SetBlendMode(), impeller::Entity::SetClipDepth(), impeller::Entity::SetContents(), impeller::Entity::SetTransform(), impeller::BackdropData::shared_filter_snapshot, subpass_size, impeller::Capabilities::SupportsFramebufferFetch(), impeller::Snapshot::texture, impeller::BackdropData::texture_slot, TRACE_EVENT0, impeller::CanvasStackEntry::transform, impeller::Snapshot::transform, impeller::Paint::WithImageFilter(), and impeller::WrapInput().

Referenced by impeller::DlDispatcherBase::drawDisplayList(), and impeller::DlDispatcherBase::saveLayer().

◆ Scale() [1/2]

void impeller::Canvas::Scale ( const Vector2 scale)

Definition at line 379 of file canvas.cc.

379 {
381}
static constexpr Matrix MakeScale(const Vector3 &s)
Definition matrix.h:104

References Concat(), and impeller::Matrix::MakeScale().

Referenced by impeller::DlDispatcherBase::scale().

◆ Scale() [2/2]

void impeller::Canvas::Scale ( const Vector3 scale)

Definition at line 383 of file canvas.cc.

383 {
385}

References Concat(), and impeller::Matrix::MakeScale().

◆ SetBackdropData()

void impeller::Canvas::SetBackdropData ( std::unordered_map< int64_t, BackdropData backdrop_data,
size_t  backdrop_count 
)

Update the backdrop data used to group together backdrop filters within the same layer.

Definition at line 2229 of file canvas.cc.

2231 {
2232 backdrop_data_ = std::move(backdrop_data);
2233 backdrop_count_ = backdrop_count;
2234}

Referenced by impeller::CanvasDlDispatcher::SetBackdropData().

◆ Skew()

void impeller::Canvas::Skew ( Scalar  sx,
Scalar  sy 
)

Definition at line 387 of file canvas.cc.

387 {
388 Concat(Matrix::MakeSkew(sx, sy));
389}
static constexpr Matrix MakeSkew(Scalar sx, Scalar sy)
Definition matrix.h:127

References Concat(), and impeller::Matrix::MakeSkew().

Referenced by impeller::DlDispatcherBase::skew().

◆ SupportsBlitToOnscreen()

bool impeller::Canvas::SupportsBlitToOnscreen ( ) const

Definition at line 2352 of file canvas.cc.

2352 {
2353 return renderer_.GetContext()
2354 ->GetCapabilities()
2355 ->SupportsTextureToTextureBlits() &&
2356 renderer_.GetContext()->GetBackendType() ==
2358}

◆ Transform()

void impeller::Canvas::Transform ( const Matrix transform)

◆ Translate()

void impeller::Canvas::Translate ( const Vector3 offset)

Definition at line 375 of file canvas.cc.

375 {
377}

References Concat(), and impeller::Matrix::MakeTranslation().

Referenced by impeller::DlDispatcherBase::translate().

Member Data Documentation

◆ kMaxDepth

constexpr uint32_t impeller::Canvas::kMaxDepth = 1 << 24
staticconstexpr

Definition at line 121 of file canvas.h.


The documentation for this class was generated from the following files: