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

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

348 : renderer_(renderer),
349 render_target_(render_target),
350 is_onscreen_(is_onscreen),
351 requires_readback_(requires_readback),
352 clip_coverage_stack_(EntityPassClipStack(
353 Rect::MakeSize(render_target.GetRenderTargetSize()))) {
354 Initialize(cull_rect);
355 SetupRenderPass();
356}

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

363 : renderer_(renderer),
364 render_target_(render_target),
365 is_onscreen_(is_onscreen),
366 requires_readback_(requires_readback),
367 clip_coverage_stack_(EntityPassClipStack(
368 Rect::MakeSize(render_target.GetRenderTargetSize()))) {
369 Initialize(Rect::MakeLTRB(cull_rect.GetLeft(), cull_rect.GetTop(),
370 cull_rect.GetRight(), cull_rect.GetBottom()));
371 SetupRenderPass();
372}
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 1290 of file canvas.cc.

1292 {
1293 if (IsSkipping()) {
1294 return;
1295 }
1296
1297 // Ideally the clip depth would be greater than the current rendering
1298 // depth because any rendering calls that follow this clip operation will
1299 // pre-increment the depth and then be rendering above our clip depth,
1300 // but that case will be caught by the CHECK in AddRenderEntity above.
1301 // In practice we sometimes have a clip set with no rendering after it
1302 // and in such cases the current depth will equal the clip depth.
1303 // Eventually the DisplayList should optimize these out, but it is hard
1304 // to know if a clip will actually be used in advance of storing it in
1305 // the DisplayList buffer.
1306 // See https://github.com/flutter/flutter/issues/147021
1307 FML_DCHECK(current_depth_ <= transform_stack_.back().clip_depth)
1308 << current_depth_ << " <=? " << transform_stack_.back().clip_depth;
1309 uint32_t clip_depth = transform_stack_.back().clip_depth;
1310
1311 const Matrix clip_transform =
1312 Matrix::MakeTranslation(Vector3(-GetGlobalPassPosition())) *
1314
1315 std::optional<Rect> clip_coverage = geometry.GetCoverage(clip_transform);
1316 if (!clip_coverage.has_value()) {
1317 return;
1318 }
1319
1320 ClipContents clip_contents(
1321 clip_coverage.value(),
1322 /*is_axis_aligned_rect=*/geometry.IsAxisAlignedRect() &&
1323 GetCurrentTransform().IsTranslationScaleOnly());
1324 clip_contents.SetClipOperation(clip_op);
1325
1326 EntityPassClipStack::ClipStateResult clip_state_result =
1327 clip_coverage_stack_.RecordClip(
1328 clip_contents, //
1329 /*transform=*/clip_transform, //
1330 /*global_pass_position=*/GetGlobalPassPosition(), //
1331 /*clip_depth=*/clip_depth, //
1332 /*clip_height_floor=*/GetClipHeightFloor(), //
1333 /*is_aa=*/is_aa);
1334
1335 if (clip_state_result.clip_did_change) {
1336 // We only need to update the pass scissor if the clip state has changed.
1337 SetClipScissor(
1338 clip_coverage_stack_.CurrentClipCoverage(),
1339 *render_passes_.back().GetInlinePassContext()->GetRenderPass(),
1340 GetGlobalPassPosition());
1341 }
1342
1343 ++transform_stack_.back().clip_height;
1344 ++transform_stack_.back().num_clips;
1345
1346 if (!clip_state_result.should_render) {
1347 return;
1348 }
1349
1350 // Note: this is a bit of a hack. Its not possible to construct a geometry
1351 // result without begninning the render pass. We should refactor the geometry
1352 // objects so that they only need a reference to the render pass size and/or
1353 // orthographic transform.
1354 Entity entity;
1355 entity.SetTransform(clip_transform);
1356 entity.SetClipDepth(clip_depth);
1357
1358 GeometryResult geometry_result = geometry.GetPositionBuffer(
1359 renderer_, //
1360 entity, //
1361 *render_passes_.back().GetInlinePassContext()->GetRenderPass() //
1362 );
1363 clip_contents.SetGeometry(geometry_result);
1364 clip_coverage_stack_.GetLastReplayResult().clip_contents.SetGeometry(
1365 geometry_result);
1366
1367 clip_contents.Render(
1368 renderer_, *render_passes_.back().GetInlinePassContext()->GetRenderPass(),
1369 clip_depth);
1370}
const Matrix & GetCurrentTransform() const
Definition canvas.cc:403
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 387 of file canvas.cc.

387 {
388 transform_stack_.back().transform = GetCurrentTransform() * transform;
389}

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

1047 {
1048 Entity entity;
1049 entity.SetTransform(GetCurrentTransform());
1050 entity.SetBlendMode(paint.blend_mode);
1051
1052 if (paint.style == Paint::Style::kFill) {
1053 ArcGeometry geom(arc);
1054 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
1055 return;
1056 }
1057
1058 const Rect& oval_bounds = arc.GetOvalBounds();
1059 if (paint.stroke.width > oval_bounds.GetSize().MaxDimension()) {
1060 // This is a special case for rendering arcs whose stroke width is so large
1061 // you are effectively drawing a sector of a circle.
1062 // https://github.com/flutter/flutter/issues/158567
1063 Arc expanded_arc(oval_bounds.Expand(Size(paint.stroke.width * 0.5f)),
1064 arc.GetStart(), arc.GetSweep(), true);
1065
1066 ArcGeometry geom(expanded_arc);
1067 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
1068 return;
1069 }
1070
1071 // IncludeCenter incurs lots of extra work for stroking an arc, including:
1072 // - It introduces segments to/from the center point (not too hard).
1073 // - It introduces joins on those segments (a bit more complicated).
1074 // - Even if the sweep is >=360 degrees, we still draw the segment to
1075 // the center and it basically looks like a pie cut into the complete
1076 // boundary circle, as if the slice were cut, but not extracted
1077 // (hard to express as a continuous kTriangleStrip).
1078 if (!arc.IncludeCenter()) {
1079 if (arc.IsFullCircle()) {
1080 return DrawOval(oval_bounds, paint);
1081 }
1082
1083 // Our fast stroking code only works for circular bounds as it assumes
1084 // that the inner and outer radii can be scaled along each angular step
1085 // of the arc - which is not true for elliptical arcs where the inner
1086 // and outer samples are perpendicular to the traveling direction of the
1087 // elliptical curve which may not line up with the center of the bounds.
1088 if (oval_bounds.IsSquare()) {
1089 ArcGeometry geom(arc, paint.stroke);
1090 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
1091 return;
1092 }
1093 }
1094
1095 ArcStrokeGeometry geom(arc, paint.stroke);
1096 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
1097}
void DrawOval(const Rect &rect, const Paint &paint)
Definition canvas.cc:992
TRect< Scalar > Rect
Definition rect.h:857
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 1586 of file canvas.cc.

1587 {
1588 atlas_contents->SetAlpha(paint.color.alpha);
1589
1590 Entity entity;
1591 entity.SetTransform(GetCurrentTransform());
1592 entity.SetBlendMode(paint.blend_mode);
1593 entity.SetContents(paint.WithFilters(renderer_, atlas_contents));
1594
1595 AddRenderEntityToCurrentPass(entity);
1596}

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

1255 {
1256 if (IsShadowBlurDrawOperation(paint)) {
1257 Rect bounds = Rect::MakeCircleBounds(center, radius);
1258 RRectBlurShape shape(bounds, radius);
1259 if (AttemptDrawBlur(shape, paint)) {
1260 return;
1261 }
1262 }
1263
1264 if (renderer_.GetContext()->GetFlags().use_sdfs &&
1267 /*color=*/paint.color, /*center=*/center, /*radius=*/radius,
1268 /*stroke=*/paint.GetStroke());
1269 AddRenderSDFEntityToCurrentPass(paint, params);
1270 return;
1271 }
1272
1273 if (AttemptDrawAntialiasedCircle(center, radius, paint)) {
1274 return;
1275 }
1276
1277 Entity entity;
1278 entity.SetTransform(GetCurrentTransform());
1279 entity.SetBlendMode(paint.blend_mode);
1280
1281 if (paint.style == Paint::Style::kStroke) {
1282 CircleGeometry geom(center, radius, paint.stroke.width);
1283 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
1284 } else {
1285 CircleGeometry geom(center, radius);
1286 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
1287 }
1288}
static bool IsCompatibleWithSDFRendering(const Paint &paint)
Definition canvas.cc:2633
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 913 of file canvas.cc.

917 {
918 // Reasons to defer to regular DrawLine:
919 // - performance for degenerate and "regular line" cases
920 // - length is non-positive - DrawLine will draw appropriate "dot"
921 // - off_length is non-positive - no gaps, DrawLine will draw it solid
922 // - on_length is negative - invalid dashing
923 //
924 // Note that a 0 length "on" dash will draw "dot"s every "off" distance
925 // apart so we proceed with the dashing process in that case.
926 Scalar length = p0.GetDistance(p1);
927 if (length > 0.0f && on_length >= 0.0f && off_length > 0.0f) {
928 Entity entity;
929 entity.SetTransform(GetCurrentTransform());
930 entity.SetBlendMode(paint.blend_mode);
931
932 StrokeDashedLineGeometry geom(p0, p1, on_length, off_length, paint.stroke);
933 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
934 } else {
935 DrawLine(p0, p1, paint);
936 }
937}
void DrawLine(const Point &p0, const Point &p1, const Paint &paint, bool reuse_depth=false)
Definition canvas.cc:895
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 1168 of file canvas.cc.

1170 {
1171 Entity entity;
1172 entity.SetTransform(GetCurrentTransform());
1173 entity.SetBlendMode(paint.blend_mode);
1174
1175 if (paint.style == Paint::Style::kFill) {
1176 FillDiffRoundRectGeometry geom(outer, inner);
1177 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
1178 } else {
1179 StrokeDiffRoundRectGeometry geom(outer, inner, paint.stroke);
1180 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
1181 }
1182}

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

1393 {
1394 if (!image) {
1395 return;
1396 }
1397
1398 const Rect source = Rect::MakeSize(image->GetSize());
1399 const Rect dest = source.Shift(offset);
1400
1401 DrawImageRect(image, source, dest, paint, sampler);
1402}
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:1404
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 1404 of file canvas.cc.

1409 {
1410 if (!image || source.IsEmpty() || dest.IsEmpty()) {
1411 return;
1412 }
1413
1414 ISize size = image->GetSize();
1415 if (size.IsEmpty()) {
1416 return;
1417 }
1418
1419 std::optional<Rect> clipped_source =
1420 source.Intersection(Rect::MakeSize(size));
1421 if (!clipped_source) {
1422 return;
1423 }
1424
1425 if (AttemptColorFilterOptimization(image, source, dest, paint, sampler,
1426 src_rect_constraint)) {
1427 return;
1428 }
1429
1430 if (*clipped_source != source) {
1431 Scalar sx = dest.GetWidth() / source.GetWidth();
1432 Scalar sy = dest.GetHeight() / source.GetHeight();
1433 Scalar tx = dest.GetLeft() - source.GetLeft() * sx;
1434 Scalar ty = dest.GetTop() - source.GetTop() * sy;
1435 Matrix src_to_dest = Matrix::MakeTranslateScale({sx, sy, 1}, {tx, ty, 0});
1436 dest = clipped_source->TransformBounds(src_to_dest);
1437 }
1438
1439 auto texture_contents = TextureContents::MakeRect(dest);
1440 texture_contents->SetTexture(image);
1441 texture_contents->SetSourceRect(*clipped_source);
1442 texture_contents->SetStrictSourceRect(src_rect_constraint ==
1444 texture_contents->SetSamplerDescriptor(sampler);
1445 texture_contents->SetOpacity(paint.color.alpha);
1446 texture_contents->SetDeferApplyingOpacity(paint.HasColorFilter());
1447
1448 Entity entity;
1449 entity.SetBlendMode(paint.blend_mode);
1450 entity.SetTransform(GetCurrentTransform());
1451
1452 if (!paint.mask_blur_descriptor.has_value()) {
1453 entity.SetContents(
1454 paint.WithFilters(renderer_, std::move(texture_contents)));
1455 AddRenderEntityToCurrentPass(entity);
1456 return;
1457 }
1458
1459 FillRectGeometry out_rect(Rect{});
1460
1461 entity.SetContents(paint.WithFilters(
1462 renderer_,
1463 paint.mask_blur_descriptor->CreateMaskBlur(texture_contents, &out_rect)));
1464 AddRenderEntityToCurrentPass(entity);
1465}
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 895 of file canvas.cc.

898 {
899 if (AttemptDrawLineSDF(p0, p1, paint, reuse_depth)) {
900 return;
901 }
902
903 Entity entity;
904 entity.SetTransform(GetCurrentTransform());
905 entity.SetBlendMode(paint.blend_mode);
906
907 auto geometry = std::make_unique<LineGeometry>(p0, p1, paint.stroke);
908
909 AddRenderEntityWithFiltersToCurrentPass(entity, geometry.get(), paint,
910 reuse_depth);
911}

References impeller::Paint::blend_mode, GetCurrentTransform(), p1, impeller::Entity::SetBlendMode(), 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 992 of file canvas.cc.

992 {
993 // TODO(jonahwilliams): This additional condition avoids an assert in the
994 // stroke circle geometry generator. I need to verify the condition that this
995 // assert prevents.
996 if (rect.IsSquare() && (paint.style == Paint::Style::kFill ||
997 (paint.style == Paint::Style::kStroke &&
998 paint.stroke.width < rect.GetWidth()))) {
999 // Circles have slightly less overhead and can do stroking
1000 DrawCircle(rect.GetCenter(), rect.GetWidth() * 0.5f, paint);
1001 return;
1002 }
1003
1004 if (IsShadowBlurDrawOperation(paint)) {
1005 if (rect.IsSquare()) {
1006 // RRectBlurShape takes the corner radii which are half of the
1007 // overall width and height of the DrawOval bounds rect.
1008 RRectBlurShape shape(rect, rect.GetWidth() * 0.5f);
1009 if (AttemptDrawBlur(shape, paint)) {
1010 return;
1011 }
1012 } else {
1013 EllipsePathSource source(rect);
1014 if (AttemptDrawBlurredPathSource(source, paint)) {
1015 return;
1016 }
1017 }
1018 }
1019
1020 Entity entity;
1021 entity.SetTransform(GetCurrentTransform());
1022 entity.SetBlendMode(paint.blend_mode);
1023
1024 if (renderer_.GetContext()->GetFlags().use_sdfs &&
1026 UberSDFParameters params;
1027
1028 if (paint.style == Paint::Style::kStroke) {
1029 params = UberSDFParameters::MakeOval(paint.color, rect, paint.stroke);
1030 } else {
1031 params = UberSDFParameters::MakeOval(paint.color, rect, std::nullopt);
1032 }
1033
1034 AddRenderSDFEntityToCurrentPass(paint, params);
1035 return;
1036 }
1037
1038 if (paint.style == Paint::Style::kStroke) {
1039 StrokeEllipseGeometry geom(rect, paint.stroke);
1040 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
1041 } else {
1042 EllipseGeometry geom(rect);
1043 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
1044 }
1045}
void DrawCircle(const Point &center, Scalar radius, const Paint &paint)
Definition canvas.cc:1253
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 478 of file canvas.cc.

478 {
479 Entity entity;
480 entity.SetTransform(GetCurrentTransform());
481 entity.SetBlendMode(paint.blend_mode);
482
483 CoverGeometry geom;
484 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
485}

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

458 {
459 if (IsShadowBlurDrawOperation(paint)) {
460 if (AttemptDrawBlurredPathSource(path, paint)) {
461 return;
462 }
463 }
464
465 Entity entity;
466 entity.SetTransform(GetCurrentTransform());
467 entity.SetBlendMode(paint.blend_mode);
468
469 if (paint.style == Paint::Style::kFill) {
470 FillPathGeometry geom(path);
471 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
472 } else {
473 StrokePathGeometry geom(path, paint.stroke);
474 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
475 }
476}

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

1376 {
1377 if (radius <= 0) {
1378 return;
1379 }
1380
1381 Entity entity;
1382 entity.SetTransform(GetCurrentTransform());
1383 entity.SetBlendMode(paint.blend_mode);
1384
1385 PointFieldGeometry geom(points, count, radius,
1386 /*round=*/point_style == PointStyle::kRound);
1387 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
1388}
@ 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 939 of file canvas.cc.

939 {
940 if (paint.style == Paint::Style::kFill && rect.IsEmpty()) {
941 return;
942 }
943
944 if (IsShadowBlurDrawOperation(paint)) {
945 RRectBlurShape shape(rect, 0.0f);
946 if (AttemptDrawBlur(shape, paint)) {
947 return;
948 }
949 }
950
951 if (renderer_.GetContext()->GetFlags().use_sdfs &&
953 Rect effective_rect = rect;
954 Color effective_color = paint.color;
955
956 // Expand rect to 1 pixel minimum dimensions if applicable.
957 if (paint.style == Paint::Style::kFill &&
958 !GetCurrentTransform().HasPerspective2D()) {
959 auto [expanded, alpha_scaled_color] = ExpandRectToPixelMinimum(
960 rect, paint.color, GetCurrentTransform(), /*scale_alpha=*/true);
961
962 if (expanded.IsEmpty()) {
963 // Rect is invisible due to transform scaling or alpha scaling.
964 return;
965 }
966
967 effective_rect = expanded;
968 effective_color = alpha_scaled_color;
969 }
970
972 /*color=*/effective_color,
973 /*rect=*/effective_rect,
974 /*stroke=*/paint.GetStroke());
975 AddRenderSDFEntityToCurrentPass(paint, params);
976 return;
977 }
978
979 Entity entity;
980 entity.SetTransform(GetCurrentTransform());
981 entity.SetBlendMode(paint.blend_mode);
982
983 if (paint.style == Paint::Style::kStroke) {
984 StrokeRectGeometry geom(rect, paint.stroke);
985 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
986 } else {
987 FillRectGeometry geom(rect);
988 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
989 }
990}
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::TRect< T >::IsEmpty(), impeller::Paint::kFill, 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 1099 of file canvas.cc.

1099 {
1100 if (paint.style == Paint::Style::kFill && round_rect.IsEmpty()) {
1101 return;
1102 }
1103
1104 if (IsShadowBlurDrawOperation(paint)) {
1105 if (AttemptDrawBlurredRRect(round_rect, paint)) {
1106 return;
1107 }
1108 }
1109
1110 const RoundingRadii& radii = round_rect.GetRadii();
1111
1112 if (renderer_.GetContext()->GetFlags().use_sdfs &&
1113 IsCompatibleWithSDFRendering(paint) && radii.AreAllCornersCircular()) {
1114 Color effective_color = paint.color;
1115 Rect bounds = round_rect.GetBounds();
1116
1117 // Expand rrect bounds to 1 pixel minimum dimensions if applicable.
1118 if (paint.style == Paint::Style::kFill &&
1119 !GetCurrentTransform().HasPerspective2D()) {
1120 auto [expanded, alpha_scaled_color] = ExpandRectToPixelMinimum(
1121 bounds, paint.color, GetCurrentTransform(), /*scale_alpha=*/true);
1122
1123 if (expanded.IsEmpty()) {
1124 // RRect is invisible due to transform scaling or alpha scaling.
1125 return;
1126 }
1127
1128 bounds = expanded;
1129 effective_color = alpha_scaled_color;
1130 }
1131
1133 /*color=*/effective_color,
1134 /*rect=*/bounds,
1135 /*radii=*/radii,
1136 /*stroke=*/paint.style == Paint::Style::kStroke
1137 ? std::make_optional(paint.stroke)
1138 : std::nullopt);
1139 AddRenderSDFEntityToCurrentPass(paint, params);
1140 return;
1141 }
1142
1143 if (round_rect.GetRadii().AreAllCornersSame() &&
1144 paint.style == Paint::Style::kFill) {
1145 Entity entity;
1146 entity.SetTransform(GetCurrentTransform());
1147 entity.SetBlendMode(paint.blend_mode);
1148
1149 RoundRectGeometry geom(round_rect.GetBounds(),
1150 round_rect.GetRadii().top_left);
1151 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
1152 return;
1153 }
1154
1155 Entity entity;
1156 entity.SetTransform(GetCurrentTransform());
1157 entity.SetBlendMode(paint.blend_mode);
1158
1159 if (paint.style == Paint::Style::kFill) {
1160 FillRoundRectGeometry geom(round_rect);
1161 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
1162 } else {
1163 StrokeRoundRectGeometry geom(round_rect, paint.stroke);
1164 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
1165 }
1166}
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::RoundRect::IsEmpty(), 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 1184 of file canvas.cc.

1185 {
1186 if (IsShadowBlurDrawOperation(paint)) {
1187 if (AttemptDrawBlurredRSuperellipse(round_superellipse, paint)) {
1188 return;
1189 }
1190 }
1191
1192 Entity entity;
1193 entity.SetTransform(GetCurrentTransform());
1194 entity.SetBlendMode(paint.blend_mode);
1195
1196 if (renderer_.GetContext()->GetFlags().use_sdfs &&
1198 auto round_superellipse_params = RoundSuperellipseParam::MakeBoundsRadii(
1199 round_superellipse.GetBounds(), round_superellipse.GetRadii());
1200
1201 if (round_superellipse_params.all_corners_same) {
1203 /*color=*/paint.color,
1204 /*bounds=*/round_superellipse.GetBounds(),
1205 /*round_superellipse_params=*/round_superellipse_params,
1206 /*stroke=*/paint.GetStroke());
1207
1208 AddRenderSDFEntityToCurrentPass(paint, params);
1209 return;
1210 } else {
1212 /*color=*/paint.color_source ? Color::White() : paint.color,
1213 /*bounds=*/round_superellipse.GetBounds(),
1214 /*round_superellipse_params=*/round_superellipse_params,
1215 /*stroke=*/paint.GetStroke());
1216
1217 const Geometry* geom = contents->GetGeometry();
1218
1219 if (paint.color_source) {
1220 std::shared_ptr<Contents> color_source_contents =
1221 paint.CreateContents(renderer_, geom);
1222 std::shared_ptr<Contents> final_contents =
1224 BlendMode::kSrcIn, {FilterInput::Make(std::move(contents)),
1225 FilterInput::Make(color_source_contents)});
1226
1227 Paint new_paint = paint;
1228 new_paint.color_source = nullptr;
1229 AddRenderEntityWithFiltersToCurrentPass(entity, geom, new_paint,
1230 /*reuse_depth=*/false,
1231 /*override_contents=*/
1232 std::move(final_contents));
1233 } else {
1234 AddRenderEntityWithFiltersToCurrentPass(entity, geom, paint,
1235 /*reuse_depth=*/false,
1236 /*override_contents=*/
1237 std::move(contents));
1238 }
1239 return;
1240 }
1241 }
1242
1243 if (paint.style == Paint::Style::kFill) {
1244 RoundSuperellipseGeometry geom(round_superellipse.GetBounds(),
1245 round_superellipse.GetRadii());
1246 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
1247 } else {
1248 StrokeRoundSuperellipseGeometry geom(round_superellipse, paint.stroke);
1249 AddRenderEntityWithFiltersToCurrentPass(entity, &geom, paint);
1250 }
1251}
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 2130 of file canvas.cc.

2132 {
2134 if (max_scale * text_frame->GetFont().GetMetrics().point_size >
2135 kMaxTextScale) {
2136 fml::StatusOr<flutter::DlPath> path = text_frame->GetPath();
2137 if (path.ok()) {
2138 Save(1);
2140 DrawPath(path.value(), paint);
2141 Restore();
2142 return;
2143 }
2144 }
2145
2146 Entity entity;
2147 entity.SetClipDepth(GetClipHeight());
2148 entity.SetBlendMode(paint.blend_mode);
2149
2150 auto text_contents = std::make_shared<TextContents>();
2151 text_contents->SetTextFrame(text_frame);
2152 text_contents->SetPosition(position);
2153 text_contents->SetScreenTransform(GetCurrentTransform());
2154 text_contents->SetForceTextColor(paint.mask_blur_descriptor.has_value());
2155 text_contents->SetColor(paint.color);
2156 text_contents->SetTextProperties(paint.color, paint.GetStroke());
2157
2158 entity.SetTransform(GetCurrentTransform().Translate(position));
2159
2160 if (AttemptBlurredTextOptimization(text_frame, text_contents, entity,
2161 paint)) {
2162 return;
2163 }
2164
2165 entity.SetContents(paint.WithFilters(renderer_, std::move(text_contents)));
2166 AddRenderEntityToCurrentPass(entity, false);
2167}
void Concat(const Matrix &transform)
Definition canvas.cc:387
void DrawPath(const flutter::DlPath &path, const Paint &paint)
Definition canvas.cc:458
void Save(uint32_t total_content_depth=kMaxDepth)
Definition canvas.cc:1654
void Translate(const Vector3 &offset)
Definition canvas.cc:407
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:2128
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 1471 of file canvas.cc.

1473 {
1474 // Override the blend mode with kDestination in order to match the behavior
1475 // of Skia's SK_LEGACY_IGNORE_DRAW_VERTICES_BLEND_WITH_NO_SHADER flag, which
1476 // is enabled when the Flutter engine builds Skia.
1477 if (!paint.color_source) {
1478 blend_mode = BlendMode::kDst;
1479 }
1480
1481 Entity entity;
1482 entity.SetTransform(GetCurrentTransform());
1483 entity.SetBlendMode(paint.blend_mode);
1484
1485 // If there are no vertex colors.
1486 if (UseColorSourceContents(vertices, paint)) {
1487 AddRenderEntityWithFiltersToCurrentPass(entity, vertices.get(), paint);
1488 return;
1489 }
1490
1491 // If the blend mode is destination don't bother to bind or create a texture.
1492 if (blend_mode == BlendMode::kDst) {
1493 auto contents = std::make_shared<VerticesSimpleBlendContents>();
1494 contents->SetBlendMode(blend_mode);
1495 contents->SetAlpha(paint.color.alpha);
1496 contents->SetGeometry(vertices);
1497 entity.SetContents(paint.WithFilters(renderer_, std::move(contents)));
1498 AddRenderEntityToCurrentPass(entity);
1499 return;
1500 }
1501
1502 // If there is a texture, use this directly. Otherwise render the color
1503 // source to a texture.
1504 if (paint.color_source &&
1505 paint.color_source->type() == flutter::DlColorSourceType::kImage) {
1506 const flutter::DlImageColorSource* image_color_source =
1507 paint.color_source->asImage();
1508 FML_DCHECK(image_color_source);
1509 auto texture =
1510 image_color_source->image()->asImpellerImage()->GetCachedTexture(
1511 renderer_);
1513 auto x_tile_mode = static_cast<Entity::TileMode>(
1514 image_color_source->horizontal_tile_mode());
1515 auto y_tile_mode =
1516 static_cast<Entity::TileMode>(image_color_source->vertical_tile_mode());
1517 auto sampler_descriptor =
1518 skia_conversions::ToSamplerDescriptor(image_color_source->sampling());
1519 auto effect_transform = image_color_source->matrix();
1520
1521 auto contents = std::make_shared<VerticesSimpleBlendContents>();
1522 contents->SetBlendMode(blend_mode);
1523 contents->SetAlpha(paint.color.alpha);
1524 contents->SetGeometry(vertices);
1525 contents->SetEffectTransform(effect_transform);
1526 contents->SetTexture(texture);
1527 contents->SetTileMode(x_tile_mode, y_tile_mode);
1528 contents->SetSamplerDescriptor(sampler_descriptor);
1529
1530 entity.SetContents(paint.WithFilters(renderer_, std::move(contents)));
1531 AddRenderEntityToCurrentPass(entity);
1532 return;
1533 }
1534
1535 auto src_paint = paint;
1536 src_paint.color = paint.color.WithAlpha(1.0);
1537
1538 std::shared_ptr<ColorSourceContents> src_contents =
1539 src_paint.CreateContents(renderer_, vertices.get());
1540
1541 // If the color source has an intrinsic size, then we use that to
1542 // create the src contents as a simplification. Otherwise we use
1543 // the extent of the texture coordinates to determine how large
1544 // the src contents should be. If neither has a value we fall back
1545 // to using the geometry coverage data.
1546 Rect src_coverage;
1547 auto size = src_contents->GetColorSourceSize();
1548 if (size.has_value()) {
1549 src_coverage = Rect::MakeXYWH(0, 0, size->width, size->height);
1550 } else {
1551 auto cvg = vertices->GetCoverage(Matrix{});
1552 FML_CHECK(cvg.has_value());
1553 auto texture_coverage = vertices->GetTextureCoordinateCoverage();
1554 if (texture_coverage.has_value()) {
1555 src_coverage =
1556 Rect::MakeOriginSize(texture_coverage->GetOrigin(),
1557 texture_coverage->GetSize().Max({1, 1}));
1558 } else {
1559 // NOLINTNEXTLINE(bugprone-unchecked-optional-access)
1560 src_coverage = cvg.value();
1561 }
1562 }
1563 clip_geometry_.push_back(Geometry::MakeRect(Rect::Round(src_coverage)));
1564 src_contents =
1565 src_paint.CreateContents(renderer_, clip_geometry_.back().get());
1566
1567 auto contents = std::make_shared<VerticesSimpleBlendContents>();
1568 contents->SetBlendMode(blend_mode);
1569 contents->SetAlpha(paint.color.alpha);
1570 contents->SetGeometry(vertices);
1571 contents->SetLazyTextureCoverage(src_coverage);
1572 contents->SetLazyTexture(
1573 [src_contents, src_coverage](
1574 const ContentContext& renderer) -> std::shared_ptr<Texture> {
1575 // Applying the src coverage as the coverage limit prevents the 1px
1576 // coverage pad from adding a border that is picked up by developer
1577 // specified UVs.
1578 auto snapshot = src_contents->RenderToSnapshot(
1579 renderer, {}, {.coverage_limit = Rect::Round(src_coverage)});
1580 return snapshot.has_value() ? snapshot->texture : nullptr;
1581 });
1582 entity.SetContents(paint.WithFilters(renderer_, std::move(contents)));
1583 AddRenderEntityToCurrentPass(entity);
1584}
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:764
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 2605 of file canvas.cc.

2605 {
2606 FML_DCHECK(render_passes_.size() == 1u);
2607 render_passes_.back().GetInlinePassContext()->GetRenderPass();
2608 render_passes_.back().GetInlinePassContext()->EndPass(
2609 /*is_onscreen=*/!requires_readback_ && is_onscreen_);
2610 backdrop_data_.clear();
2611
2612 // If requires_readback_ was true, then we rendered to an offscreen texture
2613 // instead of to the onscreen provided in the render target. Now we need to
2614 // draw or blit the offscreen back to the onscreen.
2615 if (requires_readback_) {
2616 BlitToOnscreen(/*is_onscreen_=*/is_onscreen_);
2617 }
2619 VALIDATION_LOG << "Failed to generate onscreen mipmaps.";
2620 }
2621 if (!renderer_.GetContext()->FlushCommandBuffers()) {
2622 // Not much we can do.
2623 VALIDATION_LOG << "Failed to submit command buffers";
2624 }
2625 render_passes_.clear();
2626 renderer_.GetRenderTargetCache()->End();
2627 clip_geometry_.clear();
2628
2629 Reset();
2630 Initialize(initial_cull_rect_);
2631}
bool EnsureFinalMipmapGeneration() const
Definition canvas.cc:2587
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 2587 of file canvas.cc.

2587 {
2588 if (!render_target_.GetRenderTargetTexture()->NeedsMipmapGeneration()) {
2589 return true;
2590 }
2591 std::shared_ptr<CommandBuffer> cmd_buffer =
2592 renderer_.GetContext()->CreateCommandBuffer();
2593 if (!cmd_buffer) {
2594 return false;
2595 }
2596 std::shared_ptr<BlitPass> blit_pass = cmd_buffer->CreateBlitPass();
2597 if (!blit_pass) {
2598 return false;
2599 }
2600 blit_pass->GenerateMipmap(render_target_.GetRenderTargetTexture());
2601 blit_pass->EncodeCommands();
2602 return renderer_.GetContext()->EnqueueCommandBuffer(std::move(cmd_buffer));
2603}
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 1671 of file canvas.cc.

1671 {
1672 if (!clip_coverage_stack_.HasCoverage()) {
1673 // The current clip is empty. This means the pass texture won't be
1674 // visible, so skip it.
1675 return std::nullopt;
1676 }
1677
1678 std::optional<Rect> maybe_current_clip_coverage =
1679 clip_coverage_stack_.CurrentClipCoverage();
1680 if (!maybe_current_clip_coverage.has_value()) {
1681 return std::nullopt;
1682 }
1683
1684 Rect current_clip_coverage = maybe_current_clip_coverage.value();
1685
1686 FML_CHECK(!render_passes_.empty());
1687 const LazyRenderingConfig& back_render_pass = render_passes_.back();
1688 std::shared_ptr<Texture> back_texture =
1689 back_render_pass.GetInlinePassContext()->GetTexture();
1690 FML_CHECK(back_texture) << "Context is valid:"
1691 << back_render_pass.GetInlinePassContext()->IsValid();
1692
1693 // The maximum coverage of the subpass. Subpasses textures should never
1694 // extend outside the parent pass texture or the current clip coverage.
1695 std::optional<Rect> maybe_coverage_limit =
1696 Rect::MakeOriginSize(GetGlobalPassPosition(),
1697 Size(back_texture->GetSize()))
1698 .Intersection(current_clip_coverage);
1699
1700 if (!maybe_coverage_limit.has_value() || maybe_coverage_limit->IsEmpty()) {
1701 return std::nullopt;
1702 }
1703
1704 return maybe_coverage_limit->Intersection(
1705 Rect::MakeSize(render_target_.GetRenderTargetSize()));
1706}
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 442 of file canvas.cc.

442 {
443 return transform_stack_.size();
444}

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

2633 {
2634 if (!paint.anti_alias) {
2635 return false;
2636 }
2637 if (paint.mask_blur_descriptor.has_value()) {
2638 return false;
2639 }
2640 switch (paint.blend_mode) {
2641 // Incompatible blend modes:
2642 case BlendMode::kClear:
2643 case BlendMode::kSrc:
2644 case BlendMode::kSrcIn:
2645 case BlendMode::kDstIn:
2646 case BlendMode::kSrcOut:
2648 case BlendMode::kPlus:
2650 return false;
2651 // Compatible blend modes:
2652 case BlendMode::kDst:
2655 case BlendMode::kDstOut:
2657 case BlendMode::kXor:
2658 case BlendMode::kScreen:
2660 case BlendMode::kDarken:
2669 case BlendMode::kHue:
2671 case BlendMode::kColor:
2673 return true;
2674 }
2675}

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

391 {
392 transform_stack_.back().transform = transform * GetCurrentTransform();
393}

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

395 {
396 transform_stack_.back().transform = {};
397}

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

◆ Restore()

bool impeller::Canvas::Restore ( )

Definition at line 1938 of file canvas.cc.

1938 {
1939 FML_DCHECK(transform_stack_.size() > 0);
1940 if (transform_stack_.size() == 1) {
1941 return false;
1942 }
1943
1944 // This check is important to make sure we didn't exceed the depth
1945 // that the clips were rendered at while rendering any of the
1946 // rendering ops. It is OK for the current depth to equal the
1947 // outgoing clip depth because that means the clipping would have
1948 // been successful up through the last rendering op, but it cannot
1949 // be greater.
1950 // Also, we bump the current rendering depth to the outgoing clip
1951 // depth so that future rendering operations are not clipped by
1952 // any of the pixels set by the expiring clips. It is OK for the
1953 // estimates used to determine the clip depth in save/saveLayer
1954 // to be overly conservative, but we need to jump the depth to
1955 // the clip depth so that the next rendering op will get a
1956 // larger depth (it will pre-increment the current_depth_ value).
1957 FML_DCHECK(current_depth_ <= transform_stack_.back().clip_depth)
1958 << current_depth_ << " <=? " << transform_stack_.back().clip_depth;
1959 current_depth_ = transform_stack_.back().clip_depth;
1960
1961 if (IsSkipping()) {
1962 transform_stack_.pop_back();
1963 return true;
1964 }
1965
1966 if (transform_stack_.back().rendering_mode ==
1968 transform_stack_.back().rendering_mode ==
1970 auto lazy_render_pass = std::move(render_passes_.back());
1971 render_passes_.pop_back();
1972 // Force the render pass to be constructed if it never was.
1973 lazy_render_pass.GetInlinePassContext()->GetRenderPass();
1974
1975 SaveLayerState save_layer_state = save_layer_state_.back();
1976 save_layer_state_.pop_back();
1977 auto global_pass_position = GetGlobalPassPosition();
1978
1979 std::shared_ptr<Contents> contents = CreateContentsForSubpassTarget(
1980 renderer_, save_layer_state.paint, //
1981 lazy_render_pass.GetInlinePassContext()->GetTexture(), //
1982 Matrix::MakeTranslation(Vector3{-global_pass_position}) * //
1983 transform_stack_.back().transform //
1984 );
1985
1986 lazy_render_pass.GetInlinePassContext()->EndPass();
1987
1988 // Round the subpass texture position for pixel alignment with the parent
1989 // pass render target. By default, we draw subpass textures with nearest
1990 // sampling, so aligning here is important for avoiding visual nearest
1991 // sampling errors caused by limited floating point precision when
1992 // straddling a half pixel boundary.
1993 Point subpass_texture_position;
1994 if (transform_stack_.back().did_round_out) {
1995 // Subpass coverage was rounded out, origin potentially moved "down" by
1996 // as much as a pixel.
1997 subpass_texture_position =
1998 (save_layer_state.coverage.GetOrigin() - global_pass_position)
1999 .Floor();
2000 } else {
2001 // Subpass coverage was truncated. Pick the closest phyiscal pixel.
2002 subpass_texture_position =
2003 (save_layer_state.coverage.GetOrigin() - global_pass_position)
2004 .Round();
2005 }
2006
2007 Entity element_entity;
2008 element_entity.SetClipDepth(++current_depth_);
2009 element_entity.SetContents(std::move(contents));
2010 element_entity.SetBlendMode(save_layer_state.paint.blend_mode);
2011 element_entity.SetTransform(
2012 Matrix::MakeTranslation(Vector3(subpass_texture_position)));
2013
2014 if (element_entity.GetBlendMode() > Entity::kLastPipelineBlendMode) {
2016 ApplyFramebufferBlend(element_entity);
2017 } else {
2018 // End the active pass and flush the buffer before rendering "advanced"
2019 // blends. Advanced blends work by binding the current render target
2020 // texture as an input ("destination"), blending with a second texture
2021 // input ("source"), writing the result to an intermediate texture, and
2022 // finally copying the data from the intermediate texture back to the
2023 // render target texture. And so all of the commands that have written
2024 // to the render target texture so far need to execute before it's bound
2025 // for blending (otherwise the blend pass will end up executing before
2026 // all the previous commands in the active pass).
2027 auto input_texture = FlipBackdrop(GetGlobalPassPosition());
2028 if (!input_texture) {
2029 return false;
2030 }
2031
2032 FilterInput::Vector inputs = {
2033 FilterInput::Make(input_texture,
2034 element_entity.GetTransform().Invert()),
2035 FilterInput::Make(element_entity.GetContents())};
2036 auto contents = ColorFilterContents::MakeBlend(
2037 element_entity.GetBlendMode(), inputs);
2038 contents->SetCoverageHint(element_entity.GetCoverage());
2039 element_entity.SetContents(std::move(contents));
2040 element_entity.SetBlendMode(BlendMode::kSrc);
2041 }
2042 }
2043
2044 element_entity.Render(
2045 renderer_, //
2046 *render_passes_.back().GetInlinePassContext()->GetRenderPass() //
2047 );
2048 clip_coverage_stack_.PopSubpass();
2049 transform_stack_.pop_back();
2050
2051 // We don't need to restore clips if a saveLayer was performed, as the clip
2052 // state is per render target, and no more rendering operations will be
2053 // performed as the render target workloaded is completed in the restore.
2054 return true;
2055 }
2056
2057 size_t num_clips = transform_stack_.back().num_clips;
2058 transform_stack_.pop_back();
2059
2060 if (num_clips > 0) {
2061 EntityPassClipStack::ClipStateResult clip_state_result =
2062 clip_coverage_stack_.RecordRestore(GetGlobalPassPosition(),
2063 GetClipHeight());
2064
2065 // Clip restores are never required with depth based clipping.
2066 FML_DCHECK(!clip_state_result.should_render);
2067 if (clip_state_result.clip_did_change) {
2068 // We only need to update the pass scissor if the clip state has changed.
2069 SetClipScissor(
2070 clip_coverage_stack_.CurrentClipCoverage(), //
2071 *render_passes_.back().GetInlinePassContext()->GetRenderPass(), //
2072 GetGlobalPassPosition() //
2073 );
2074 }
2075 }
2076
2077 return true;
2078}
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 450 of file canvas.cc.

450 {
451 while (GetSaveCount() > count) {
452 if (!Restore()) {
453 return;
454 }
455 }
456}
size_t GetSaveCount() const
Definition canvas.cc:442

References GetSaveCount(), and Restore().

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

◆ Rotate()

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

Definition at line 423 of file canvas.cc.

423 {
425}
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 1654 of file canvas.cc.

1654 {
1655 if (IsSkipping()) {
1656 return SkipUntilMatchingRestore(total_content_depth);
1657 }
1658
1659 auto entry = CanvasStackEntry{};
1660 entry.transform = transform_stack_.back().transform;
1661 entry.clip_depth = current_depth_ + total_content_depth;
1662 entry.distributed_opacity = transform_stack_.back().distributed_opacity;
1663 FML_DCHECK(entry.clip_depth <= transform_stack_.back().clip_depth)
1664 << entry.clip_depth << " <=? " << transform_stack_.back().clip_depth
1665 << " after allocating " << total_content_depth;
1666 entry.clip_height = transform_stack_.back().clip_height;
1667 entry.rendering_mode = Entity::RenderingMode::kDirect;
1668 transform_stack_.push_back(entry);
1669}

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

1714 {
1715 TRACE_EVENT0("flutter", "Canvas::saveLayer");
1716 if (IsSkipping()) {
1717 return SkipUntilMatchingRestore(total_content_depth);
1718 }
1719
1720 auto maybe_coverage_limit = GetLocalCoverageLimit();
1721 if (!maybe_coverage_limit.has_value()) {
1722 return SkipUntilMatchingRestore(total_content_depth);
1723 }
1724 auto coverage_limit = maybe_coverage_limit.value();
1725
1726 if (can_distribute_opacity && !backdrop_filter &&
1728 bounds_promise != ContentBoundsPromise::kMayClipContents) {
1729 Save(total_content_depth);
1730 transform_stack_.back().distributed_opacity *= paint.color.alpha;
1731 return;
1732 }
1733
1734 std::shared_ptr<FilterContents> filter_contents = paint.WithImageFilter(
1735 renderer_, Rect(), transform_stack_.back().transform,
1737
1738 std::optional<Rect> maybe_subpass_coverage = ComputeSaveLayerCoverage(
1739 bounds.value_or(Rect::MakeMaximum()),
1740 transform_stack_.back().transform, //
1741 coverage_limit, //
1742 filter_contents, //
1743 /*flood_output_coverage=*/
1744 Entity::IsBlendModeDestructive(paint.blend_mode), //
1745 /*flood_input_coverage=*/!!backdrop_filter ||
1746 (paint.color_filter &&
1747 paint.color_filter->modifies_transparent_black()) //
1748 );
1749
1750 if (!maybe_subpass_coverage.has_value()) {
1751 return SkipUntilMatchingRestore(total_content_depth);
1752 }
1753
1754 auto subpass_coverage = maybe_subpass_coverage.value();
1755
1756 // When an image filter is present, clamp to avoid flicking due to nearest
1757 // sampled image. For other cases, round out to ensure than any geometry is
1758 // not cut off.
1759 //
1760 // See also this bug: https://github.com/flutter/flutter/issues/144213
1761 //
1762 // TODO(jonahwilliams): this could still round out for filters that use decal
1763 // sampling mode.
1765 bool did_round_out = false;
1766 Point coverage_origin_adjustment = Point{0, 0};
1767 if (paint.image_filter) {
1768 subpass_size = ISize(subpass_coverage.GetSize());
1769 } else {
1770 did_round_out = true;
1771 subpass_size =
1772 static_cast<ISize>(IRect::RoundOut(subpass_coverage).GetSize());
1773 // If rounding out, adjust the coverage to account for the subpixel shift.
1774 coverage_origin_adjustment =
1775 Point(subpass_coverage.GetLeftTop().x -
1776 std::floor(subpass_coverage.GetLeftTop().x),
1777 subpass_coverage.GetLeftTop().y -
1778 std::floor(subpass_coverage.GetLeftTop().y));
1779 }
1780 if (subpass_size.IsEmpty()) {
1781 return SkipUntilMatchingRestore(total_content_depth);
1782 }
1783
1784 // When there are scaling filters present, these contents may exceed the
1785 // maximum texture size. Perform a clamp here, which may cause rendering
1786 // artifacts.
1787 subpass_size = subpass_size.Min(renderer_.GetContext()
1788 ->GetCapabilities()
1789 ->GetMaximumRenderPassAttachmentSize());
1790
1791 // Backdrop filter state, ignored if there is no BDF.
1792 std::shared_ptr<FilterContents> backdrop_filter_contents;
1793 Point local_position = Point(0, 0);
1794 if (backdrop_filter) {
1795 local_position = subpass_coverage.GetOrigin() - GetGlobalPassPosition();
1796
1797 std::shared_ptr<Texture> input_texture;
1798
1799 // If the backdrop ID is not nullopt and there is more than one usage
1800 // of it in the current scene, cache the backdrop texture and remove it from
1801 // the current entity pass flip.
1802 bool will_cache_backdrop_texture = false;
1803 BackdropData* backdrop_data = nullptr;
1804 // If we've reached this point, there is at least one backdrop filter. But
1805 // potentially more if there is a backdrop id. We may conditionally set this
1806 // to a higher value in the if block below.
1807 size_t backdrop_count = 1;
1808 if (backdrop_id.has_value()) {
1809 std::unordered_map<int64_t, BackdropData>::iterator backdrop_data_it =
1810 backdrop_data_.find(backdrop_id.value());
1811 if (backdrop_data_it != backdrop_data_.end()) {
1812 backdrop_data = &backdrop_data_it->second;
1813 will_cache_backdrop_texture =
1814 backdrop_data_it->second.backdrop_count > 1;
1815 backdrop_count = backdrop_data_it->second.backdrop_count;
1816 }
1817 }
1818
1819 if (!will_cache_backdrop_texture || !backdrop_data->texture_slot) {
1820 backdrop_count_ -= backdrop_count;
1821
1822 // The onscreen texture can be flipped to if:
1823 // 1. The device supports framebuffer fetch
1824 // 2. There are no more backdrop filters
1825 // 3. The current render pass is for the onscreen pass.
1826 const bool should_use_onscreen =
1828 backdrop_count_ == 0 && render_passes_.size() == 1u;
1829 input_texture = FlipBackdrop(
1830 GetGlobalPassPosition(), //
1831 /*should_remove_texture=*/will_cache_backdrop_texture, //
1832 /*should_use_onscreen=*/should_use_onscreen //
1833 );
1834 if (!input_texture) {
1835 // Validation failures are logged in FlipBackdrop.
1836 return;
1837 }
1838
1839 if (will_cache_backdrop_texture) {
1840 backdrop_data->texture_slot = input_texture;
1841 }
1842 } else {
1843 input_texture = backdrop_data->texture_slot;
1844 }
1845
1846 backdrop_filter_contents =
1847 WrapInput(renderer_, backdrop_filter,
1848 FilterInput::Make(std::move(input_texture)));
1849 backdrop_filter_contents->SetEffectTransform(
1850 transform_stack_.back().transform.Basis());
1851 backdrop_filter_contents->SetRenderingMode(
1852 transform_stack_.back().transform.HasTranslation()
1854 : Entity::RenderingMode::kSubpassAppendSnapshotTransform);
1855
1856 if (will_cache_backdrop_texture) {
1857 FML_DCHECK(backdrop_data);
1858 // If all filters on the shared backdrop layer are equal, process the
1859 // layer once.
1860 if (backdrop_data->all_filters_equal &&
1861 !backdrop_data->shared_filter_snapshot.has_value()) {
1862 // TODO(157110): compute minimum input hint.
1863 backdrop_data->shared_filter_snapshot =
1864 backdrop_filter_contents->RenderToSnapshot(renderer_, {}, {});
1865 }
1866
1867 std::optional<Snapshot> maybe_snapshot =
1868 backdrop_data->shared_filter_snapshot;
1869 if (maybe_snapshot.has_value()) {
1870 const Snapshot& snapshot = maybe_snapshot.value();
1871 std::shared_ptr<TextureContents> contents = TextureContents::MakeRect(
1872 subpass_coverage.Shift(-GetGlobalPassPosition()));
1873 auto scaled =
1874 subpass_coverage.TransformBounds(snapshot.transform.Invert());
1875 contents->SetTexture(snapshot.texture);
1876 contents->SetSourceRect(scaled);
1877 contents->SetSamplerDescriptor(snapshot.sampler_descriptor);
1878
1879 // This backdrop entity sets a depth value as it is written to the newly
1880 // flipped backdrop and not into a new saveLayer.
1881 Entity backdrop_entity;
1882 backdrop_entity.SetContents(std::move(contents));
1883 backdrop_entity.SetClipDepth(++current_depth_);
1884 backdrop_entity.SetBlendMode(paint.blend_mode);
1885
1886 backdrop_entity.Render(renderer_, GetCurrentRenderPass());
1887 Save(0);
1888 return;
1889 }
1890 }
1891 }
1892
1893 // When applying a save layer, absorb any pending distributed opacity.
1894 Paint paint_copy = paint;
1895 paint_copy.color.alpha *= transform_stack_.back().distributed_opacity;
1896 transform_stack_.back().distributed_opacity = 1.0;
1897
1898 render_passes_.push_back(
1899 LazyRenderingConfig(renderer_, //
1900 CreateRenderTarget(renderer_, //
1901 subpass_size, //
1903 )));
1904 save_layer_state_.push_back(SaveLayerState{
1905 paint_copy, subpass_coverage.Shift(-coverage_origin_adjustment)});
1906
1907 CanvasStackEntry entry;
1908 entry.transform = transform_stack_.back().transform;
1909 entry.clip_depth = current_depth_ + total_content_depth;
1910 FML_DCHECK(entry.clip_depth <= transform_stack_.back().clip_depth)
1911 << entry.clip_depth << " <=? " << transform_stack_.back().clip_depth
1912 << " after allocating " << total_content_depth;
1913 entry.clip_height = transform_stack_.back().clip_height;
1915 entry.did_round_out = did_round_out;
1916 transform_stack_.emplace_back(entry);
1917
1918 // Start non-collapsed subpasses with a fresh clip coverage stack limited by
1919 // the subpass coverage. This is important because image filters applied to
1920 // save layers may transform the subpass texture after it's rendered,
1921 // causing parent clip coverage to get misaligned with the actual area that
1922 // the subpass will affect in the parent pass.
1923 clip_coverage_stack_.PushSubpass(subpass_coverage, GetClipHeight());
1924
1925 if (!backdrop_filter_contents) {
1926 return;
1927 }
1928
1929 // Render the backdrop entity.
1930 Entity backdrop_entity;
1931 backdrop_entity.SetContents(std::move(backdrop_filter_contents));
1932 backdrop_entity.SetTransform(
1933 Matrix::MakeTranslation(Vector3(-local_position)));
1934 backdrop_entity.SetClipDepth(std::numeric_limits<uint32_t>::max());
1935 backdrop_entity.Render(renderer_, GetCurrentRenderPass());
1936}
std::optional< Rect > GetLocalCoverageLimit() const
Return the culling bounds of the current render target, or nullopt if there is no coverage.
Definition canvas.cc:1671
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:748
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 411 of file canvas.cc.

411 {
413}
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 415 of file canvas.cc.

415 {
417}

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

2408 {
2409 backdrop_data_ = std::move(backdrop_data);
2410 backdrop_count_ = backdrop_count;
2411}

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

◆ Skew()

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

Definition at line 419 of file canvas.cc.

419 {
420 Concat(Matrix::MakeSkew(sx, sy));
421}
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 2529 of file canvas.cc.

2529 {
2530 return renderer_.GetContext()
2531 ->GetCapabilities()
2532 ->SupportsTextureToTextureBlits() &&
2533 renderer_.GetContext()->GetBackendType() ==
2535}

◆ Transform()

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

◆ Translate()

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

Definition at line 407 of file canvas.cc.

407 {
409}

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: