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 298 of file canvas.cc.

302 : renderer_(renderer),
303 render_target_(render_target),
304 is_onscreen_(is_onscreen),
305 requires_readback_(requires_readback),
306 clip_coverage_stack_(EntityPassClipStack(
307 Rect::MakeSize(render_target.GetRenderTargetSize()))) {
308 Initialize(std::nullopt);
309 SetupRenderPass();
310}
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 312 of file canvas.cc.

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

◆ 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 327 of file canvas.cc.

332 : renderer_(renderer),
333 render_target_(render_target),
334 is_onscreen_(is_onscreen),
335 requires_readback_(requires_readback),
336 clip_coverage_stack_(EntityPassClipStack(
337 Rect::MakeSize(render_target.GetRenderTargetSize()))) {
338 Initialize(Rect::MakeLTRB(cull_rect.GetLeft(), cull_rect.GetTop(),
339 cull_rect.GetRight(), cull_rect.GetBottom()));
340 SetupRenderPass();
341}
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 1133 of file canvas.cc.

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

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

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 912 of file canvas.cc.

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

1430 {
1431 atlas_contents->SetAlpha(paint.color.alpha);
1432
1433 Entity entity;
1434 entity.SetTransform(GetCurrentTransform());
1435 entity.SetBlendMode(paint.blend_mode);
1436 entity.SetContents(paint.WithFilters(renderer_, atlas_contents));
1437
1438 AddRenderEntityToCurrentPass(entity);
1439}

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 1096 of file canvas.cc.

1098 {
1099 if (IsShadowBlurDrawOperation(paint)) {
1100 Rect bounds = Rect::MakeCircleBounds(center, radius);
1101 RRectBlurShape shape(bounds, radius);
1102 if (AttemptDrawBlur(shape, paint)) {
1103 return;
1104 }
1105 }
1106
1107 if (renderer_.GetContext()->GetFlags().use_sdfs &&
1110 /*color=*/paint.color, /*center=*/center, /*radius=*/radius,
1111 /*stroke=*/paint.GetStroke());
1112 AddRenderSDFEntityToCurrentPass(paint, params);
1113 return;
1114 }
1115
1116 if (AttemptDrawAntialiasedCircle(center, radius, paint)) {
1117 return;
1118 }
1119
1120 Entity entity;
1121 entity.SetTransform(GetCurrentTransform());
1122 entity.SetBlendMode(paint.blend_mode);
1123
1124 if (paint.style == Paint::Style::kStroke) {
1125 CircleGeometry geom(center, radius, paint.stroke.width);
1126 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
1127 } else {
1128 CircleGeometry geom(center, radius);
1129 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
1130 }
1131}
static bool IsCompatibleWithSDFRendering(const Paint &paint)
Definition canvas.cc:2469
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 800 of file canvas.cc.

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

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

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 1233 of file canvas.cc.

1236 {
1237 if (!image) {
1238 return;
1239 }
1240
1241 const Rect source = Rect::MakeSize(image->GetSize());
1242 const Rect dest = source.Shift(offset);
1243
1244 DrawImageRect(image, source, dest, paint, sampler);
1245}
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:1247
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 1247 of file canvas.cc.

1252 {
1253 if (!image || source.IsEmpty() || dest.IsEmpty()) {
1254 return;
1255 }
1256
1257 ISize size = image->GetSize();
1258 if (size.IsEmpty()) {
1259 return;
1260 }
1261
1262 std::optional<Rect> clipped_source =
1263 source.Intersection(Rect::MakeSize(size));
1264 if (!clipped_source) {
1265 return;
1266 }
1267
1268 if (AttemptColorFilterOptimization(image, source, dest, paint, sampler,
1269 src_rect_constraint)) {
1270 return;
1271 }
1272
1273 if (*clipped_source != source) {
1274 Scalar sx = dest.GetWidth() / source.GetWidth();
1275 Scalar sy = dest.GetHeight() / source.GetHeight();
1276 Scalar tx = dest.GetLeft() - source.GetLeft() * sx;
1277 Scalar ty = dest.GetTop() - source.GetTop() * sy;
1278 Matrix src_to_dest = Matrix::MakeTranslateScale({sx, sy, 1}, {tx, ty, 0});
1279 dest = clipped_source->TransformBounds(src_to_dest);
1280 }
1281
1282 auto texture_contents = TextureContents::MakeRect(dest);
1283 texture_contents->SetTexture(image);
1284 texture_contents->SetSourceRect(*clipped_source);
1285 texture_contents->SetStrictSourceRect(src_rect_constraint ==
1287 texture_contents->SetSamplerDescriptor(sampler);
1288 texture_contents->SetOpacity(paint.color.alpha);
1289 texture_contents->SetDeferApplyingOpacity(paint.HasColorFilter());
1290
1291 Entity entity;
1292 entity.SetBlendMode(paint.blend_mode);
1293 entity.SetTransform(GetCurrentTransform());
1294
1295 if (!paint.mask_blur_descriptor.has_value()) {
1296 entity.SetContents(
1297 paint.WithFilters(renderer_, std::move(texture_contents)));
1298 AddRenderEntityToCurrentPass(entity);
1299 return;
1300 }
1301
1302 FillRectGeometry out_rect(Rect{});
1303
1304 entity.SetContents(paint.WithFilters(
1305 renderer_,
1306 paint.mask_blur_descriptor->CreateMaskBlur(texture_contents, &out_rect)));
1307 AddRenderEntityToCurrentPass(entity);
1308}
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 777 of file canvas.cc.

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

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

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

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 427 of file canvas.cc.

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

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 1215 of file canvas.cc.

1219 {
1220 if (radius <= 0) {
1221 return;
1222 }
1223
1224 Entity entity;
1225 entity.SetTransform(GetCurrentTransform());
1226 entity.SetBlendMode(paint.blend_mode);
1227
1228 PointFieldGeometry geom(points, count, radius,
1229 /*round=*/point_style == PointStyle::kRound);
1230 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
1231}
@ 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 826 of file canvas.cc.

826 {
827 if (IsShadowBlurDrawOperation(paint)) {
828 RRectBlurShape shape(rect, 0.0f);
829 if (AttemptDrawBlur(shape, paint)) {
830 return;
831 }
832 }
833
834 if (renderer_.GetContext()->GetFlags().use_sdfs &&
837 /*color=*/paint.color,
838 /*rect=*/rect,
839 /*stroke=*/paint.GetStroke());
840 AddRenderSDFEntityToCurrentPass(paint, params);
841 return;
842 }
843
844 Entity entity;
845 entity.SetTransform(GetCurrentTransform());
846 entity.SetBlendMode(paint.blend_mode);
847
848 if (paint.style == Paint::Style::kStroke) {
849 StrokeRectGeometry geom(rect, paint.stroke);
850 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
851 } else {
852 FillRectGeometry geom(rect);
853 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
854 }
855}
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 964 of file canvas.cc.

964 {
965 if (IsShadowBlurDrawOperation(paint)) {
966 if (AttemptDrawBlurredRRect(round_rect, paint)) {
967 return;
968 }
969 }
970
971 const RoundingRadii& radii = round_rect.GetRadii();
972
973 if (renderer_.GetContext()->GetFlags().use_sdfs &&
974 IsCompatibleWithSDFRendering(paint) && radii.AreAllCornersCircular()) {
976 /*color=*/paint.color,
977 /*rect=*/round_rect.GetBounds(),
978 /*radii=*/radii,
979 /*stroke=*/paint.style == Paint::Style::kStroke
980 ? std::make_optional(paint.stroke)
981 : std::nullopt);
982 AddRenderSDFEntityToCurrentPass(paint, params);
983 return;
984 }
985
986 if (round_rect.GetRadii().AreAllCornersSame() &&
987 paint.style == Paint::Style::kFill) {
988 Entity entity;
989 entity.SetTransform(GetCurrentTransform());
990 entity.SetBlendMode(paint.blend_mode);
991
992 RoundRectGeometry geom(round_rect.GetBounds(),
993 round_rect.GetRadii().top_left);
994 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
995 return;
996 }
997
998 Entity entity;
999 entity.SetTransform(GetCurrentTransform());
1000 entity.SetBlendMode(paint.blend_mode);
1001
1002 if (paint.style == Paint::Style::kFill) {
1003 FillRoundRectGeometry geom(round_rect);
1004 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
1005 } else {
1006 StrokeRoundRectGeometry geom(round_rect, paint.stroke);
1007 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
1008 }
1009}
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 1027 of file canvas.cc.

1028 {
1029 if (IsShadowBlurDrawOperation(paint)) {
1030 if (AttemptDrawBlurredRSuperellipse(round_superellipse, paint)) {
1031 return;
1032 }
1033 }
1034
1035 Entity entity;
1036 entity.SetTransform(GetCurrentTransform());
1037 entity.SetBlendMode(paint.blend_mode);
1038
1039 if (renderer_.GetContext()->GetFlags().use_sdfs &&
1041 auto round_superellipse_params = RoundSuperellipseParam::MakeBoundsRadii(
1042 round_superellipse.GetBounds(), round_superellipse.GetRadii());
1043
1044 if (round_superellipse_params.all_corners_same) {
1046 /*color=*/paint.color,
1047 /*bounds=*/round_superellipse.GetBounds(),
1048 /*round_superellipse_params=*/round_superellipse_params,
1049 /*stroke=*/paint.GetStroke());
1050
1051 AddRenderSDFEntityToCurrentPass(paint, params);
1052 return;
1053 } else {
1055 /*color=*/paint.color_source ? Color::White() : paint.color,
1056 /*bounds=*/round_superellipse.GetBounds(),
1057 /*round_superellipse_params=*/round_superellipse_params,
1058 /*stroke=*/paint.GetStroke());
1059
1060 const Geometry* geom = contents->GetGeometry();
1061
1062 if (paint.color_source) {
1063 std::shared_ptr<Contents> color_source_contents =
1064 paint.CreateContents(renderer_, geom);
1065 std::shared_ptr<Contents> final_contents =
1067 BlendMode::kSrcIn, {FilterInput::Make(std::move(contents)),
1068 FilterInput::Make(color_source_contents)});
1069
1070 Paint new_paint = paint;
1071 new_paint.color_source = nullptr;
1072 AddRenderEntityWithFiltersToCurrentPass(entity, geom, new_paint,
1073 /*reuse_depth=*/false,
1074 /*override_contents=*/
1075 std::move(final_contents));
1076 } else {
1077 AddRenderEntityWithFiltersToCurrentPass(entity, geom, paint,
1078 /*reuse_depth=*/false,
1079 /*override_contents=*/
1080 std::move(contents));
1081 }
1082 return;
1083 }
1084 }
1085
1086 if (paint.style == Paint::Style::kFill) {
1087 RoundSuperellipseGeometry geom(round_superellipse.GetBounds(),
1088 round_superellipse.GetRadii());
1089 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
1090 } else {
1091 StrokeRoundSuperellipseGeometry geom(round_superellipse, paint.stroke);
1092 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
1093 }
1094}
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)
static FilterInput::Ref Make(Variant input, bool msaa_enabled=true)
static constexpr Color White()
Definition color.h:269
static RoundSuperellipseParam MakeBoundsRadii(const Rect &bounds, const RoundingRadii &radii)
static UberSDFParameters MakeRoundedSuperellipse(Color color, const Rect &bounds, const RoundSuperellipseParam &round_superellipse_params, std::optional< StrokeParameters > stroke)
Creates UberSDFParameters for an asymmetric round superellipse.

References impeller::Paint::blend_mode, impeller::Paint::color, impeller::Paint::color_source, impeller::Paint::CreateContents(), impeller::RoundSuperellipse::GetBounds(), impeller::ContentContext::GetContext(), GetCurrentTransform(), impeller::RoundSuperellipse::GetRadii(), impeller::Paint::GetStroke(), IsCompatibleWithSDFRendering(), impeller::Paint::kFill, impeller::kSrcIn, impeller::ComplexRoundedSuperellipseContents::Make(), impeller::FilterInput::Make(), impeller::ColorFilterContents::MakeBlend(), impeller::RoundSuperellipseParam::MakeBoundsRadii(), impeller::UberSDFParameters::MakeRoundedSuperellipse(), params, impeller::Entity::SetBlendMode(), impeller::Entity::SetTransform(), impeller::Paint::stroke, impeller::Paint::style, and impeller::Color::White().

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 1973 of file canvas.cc.

1975 {
1977 if (max_scale * text_frame->GetFont().GetMetrics().point_size >
1978 kMaxTextScale) {
1979 fml::StatusOr<flutter::DlPath> path = text_frame->GetPath();
1980 if (path.ok()) {
1981 Save(1);
1983 DrawPath(path.value(), paint);
1984 Restore();
1985 return;
1986 }
1987 }
1988
1989 Entity entity;
1990 entity.SetClipDepth(GetClipHeight());
1991 entity.SetBlendMode(paint.blend_mode);
1992
1993 auto text_contents = std::make_shared<TextContents>();
1994 text_contents->SetTextFrame(text_frame);
1995 text_contents->SetPosition(position);
1996 text_contents->SetScreenTransform(GetCurrentTransform());
1997 text_contents->SetForceTextColor(paint.mask_blur_descriptor.has_value());
1998 text_contents->SetColor(paint.color);
1999 text_contents->SetTextProperties(paint.color, paint.GetStroke());
2000
2001 entity.SetTransform(GetCurrentTransform().Translate(position));
2002
2003 if (AttemptBlurredTextOptimization(text_frame, text_contents, entity,
2004 paint)) {
2005 return;
2006 }
2007
2008 entity.SetContents(paint.WithFilters(renderer_, std::move(text_contents)));
2009 AddRenderEntityToCurrentPass(entity, false);
2010}
void Concat(const Matrix &transform)
Definition canvas.cc:356
void DrawPath(const flutter::DlPath &path, const Paint &paint)
Definition canvas.cc:427
void Save(uint32_t total_content_depth=kMaxDepth)
Definition canvas.cc:1497
void Translate(const Vector3 &offset)
Definition canvas.cc:376
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:1971
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(), Translate(), 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 1314 of file canvas.cc.

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

2441 {
2442 FML_DCHECK(render_passes_.size() == 1u);
2443 render_passes_.back().GetInlinePassContext()->GetRenderPass();
2444 render_passes_.back().GetInlinePassContext()->EndPass(
2445 /*is_onscreen=*/!requires_readback_ && is_onscreen_);
2446 backdrop_data_.clear();
2447
2448 // If requires_readback_ was true, then we rendered to an offscreen texture
2449 // instead of to the onscreen provided in the render target. Now we need to
2450 // draw or blit the offscreen back to the onscreen.
2451 if (requires_readback_) {
2452 BlitToOnscreen(/*is_onscreen_=*/is_onscreen_);
2453 }
2455 VALIDATION_LOG << "Failed to generate onscreen mipmaps.";
2456 }
2457 if (!renderer_.GetContext()->FlushCommandBuffers()) {
2458 // Not much we can do.
2459 VALIDATION_LOG << "Failed to submit command buffers";
2460 }
2461 render_passes_.clear();
2462 renderer_.GetRenderTargetCache()->End();
2463 clip_geometry_.clear();
2464
2465 Reset();
2466 Initialize(initial_cull_rect_);
2467}
bool EnsureFinalMipmapGeneration() const
Definition canvas.cc:2423
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 2423 of file canvas.cc.

2423 {
2424 if (!render_target_.GetRenderTargetTexture()->NeedsMipmapGeneration()) {
2425 return true;
2426 }
2427 std::shared_ptr<CommandBuffer> cmd_buffer =
2428 renderer_.GetContext()->CreateCommandBuffer();
2429 if (!cmd_buffer) {
2430 return false;
2431 }
2432 std::shared_ptr<BlitPass> blit_pass = cmd_buffer->CreateBlitPass();
2433 if (!blit_pass) {
2434 return false;
2435 }
2436 blit_pass->GenerateMipmap(render_target_.GetRenderTargetTexture());
2437 blit_pass->EncodeCommands();
2438 return renderer_.GetContext()->EnqueueCommandBuffer(std::move(cmd_buffer));
2439}
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 1514 of file canvas.cc.

1514 {
1515 if (!clip_coverage_stack_.HasCoverage()) {
1516 // The current clip is empty. This means the pass texture won't be
1517 // visible, so skip it.
1518 return std::nullopt;
1519 }
1520
1521 std::optional<Rect> maybe_current_clip_coverage =
1522 clip_coverage_stack_.CurrentClipCoverage();
1523 if (!maybe_current_clip_coverage.has_value()) {
1524 return std::nullopt;
1525 }
1526
1527 Rect current_clip_coverage = maybe_current_clip_coverage.value();
1528
1529 FML_CHECK(!render_passes_.empty());
1530 const LazyRenderingConfig& back_render_pass = render_passes_.back();
1531 std::shared_ptr<Texture> back_texture =
1532 back_render_pass.GetInlinePassContext()->GetTexture();
1533 FML_CHECK(back_texture) << "Context is valid:"
1534 << back_render_pass.GetInlinePassContext()->IsValid();
1535
1536 // The maximum coverage of the subpass. Subpasses textures should never
1537 // extend outside the parent pass texture or the current clip coverage.
1538 std::optional<Rect> maybe_coverage_limit =
1539 Rect::MakeOriginSize(GetGlobalPassPosition(),
1540 Size(back_texture->GetSize()))
1541 .Intersection(current_clip_coverage);
1542
1543 if (!maybe_coverage_limit.has_value() || maybe_coverage_limit->IsEmpty()) {
1544 return std::nullopt;
1545 }
1546
1547 return maybe_coverage_limit->Intersection(
1548 Rect::MakeSize(render_target_.GetRenderTargetSize()));
1549}
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 411 of file canvas.cc.

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

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 2469 of file canvas.cc.

2469 {
2470 if (!paint.anti_alias) {
2471 return false;
2472 }
2473 if (paint.mask_blur_descriptor.has_value()) {
2474 return false;
2475 }
2476 switch (paint.blend_mode) {
2477 // Incompatible blend modes:
2478 case BlendMode::kClear:
2479 case BlendMode::kSrc:
2480 case BlendMode::kSrcIn:
2481 case BlendMode::kDstIn:
2482 case BlendMode::kSrcOut:
2484 case BlendMode::kPlus:
2486 return false;
2487 // Compatible blend modes:
2488 case BlendMode::kDst:
2491 case BlendMode::kDstOut:
2493 case BlendMode::kXor:
2494 case BlendMode::kScreen:
2496 case BlendMode::kDarken:
2505 case BlendMode::kHue:
2507 case BlendMode::kColor:
2509 return true;
2510 }
2511}

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 360 of file canvas.cc.

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

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 364 of file canvas.cc.

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

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

◆ Restore()

bool impeller::Canvas::Restore ( )

Definition at line 1781 of file canvas.cc.

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

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 419 of file canvas.cc.

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

References GetSaveCount(), and Restore().

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

◆ Rotate()

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

Definition at line 392 of file canvas.cc.

392 {
394}
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 1497 of file canvas.cc.

1497 {
1498 if (IsSkipping()) {
1499 return SkipUntilMatchingRestore(total_content_depth);
1500 }
1501
1502 auto entry = CanvasStackEntry{};
1503 entry.transform = transform_stack_.back().transform;
1504 entry.clip_depth = current_depth_ + total_content_depth;
1505 entry.distributed_opacity = transform_stack_.back().distributed_opacity;
1506 FML_DCHECK(entry.clip_depth <= transform_stack_.back().clip_depth)
1507 << entry.clip_depth << " <=? " << transform_stack_.back().clip_depth
1508 << " after allocating " << total_content_depth;
1509 entry.clip_height = transform_stack_.back().clip_height;
1510 entry.rendering_mode = Entity::RenderingMode::kDirect;
1511 transform_stack_.push_back(entry);
1512}

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 1551 of file canvas.cc.

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

380 {
382}
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 384 of file canvas.cc.

384 {
386}

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 2242 of file canvas.cc.

2244 {
2245 backdrop_data_ = std::move(backdrop_data);
2246 backdrop_count_ = backdrop_count;
2247}

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

◆ Skew()

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

Definition at line 388 of file canvas.cc.

388 {
389 Concat(Matrix::MakeSkew(sx, sy));
390}
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 2365 of file canvas.cc.

2365 {
2366 return renderer_.GetContext()
2367 ->GetCapabilities()
2368 ->SupportsTextureToTextureBlits() &&
2369 renderer_.GetContext()->GetBackendType() ==
2371}

◆ Transform()

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

◆ Translate()

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

Definition at line 376 of file canvas.cc.

376 {
378}

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

Referenced by DrawTextFrame(), and 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: