Flutter Impeller
impeller::ExperimentalCanvas Class Reference

#include <experimental_canvas.h>

Inheritance diagram for impeller::ExperimentalCanvas:
impeller::Canvas

Classes

struct  SaveLayerState
 

Public Member Functions

 ExperimentalCanvas (ContentContext &renderer, RenderTarget &render_target, bool requires_readback)
 
 ExperimentalCanvas (ContentContext &renderer, RenderTarget &render_target, bool requires_readback, Rect cull_rect)
 
 ExperimentalCanvas (ContentContext &renderer, RenderTarget &render_target, bool requires_readback, IRect cull_rect)
 
 ~ExperimentalCanvas () override=default
 
void Save (uint32_t total_content_depth) override
 
void SaveLayer (const Paint &paint, std::optional< Rect > bounds, const std::shared_ptr< ImageFilter > &backdrop_filter, ContentBoundsPromise bounds_promise, uint32_t total_content_depth, bool can_distribute_opacity) override
 
bool Restore () override
 
void EndReplay ()
 
void DrawTextFrame (const std::shared_ptr< TextFrame > &text_frame, Point position, const Paint &paint) override
 
- Public Member Functions inherited from impeller::Canvas
 Canvas ()
 
 Canvas (Rect cull_rect)
 
 Canvas (IRect cull_rect)
 
virtual ~Canvas ()
 
size_t GetSaveCount () const
 
void RestoreToCount (size_t count)
 
const MatrixGetCurrentTransform () const
 
const std::optional< RectGetCurrentLocalCullingBounds () 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 Path &path, const Paint &paint)
 
void DrawPaint (const Paint &paint)
 
void DrawLine (const Point &p0, const Point &p1, const Paint &paint)
 
void DrawRect (const Rect &rect, const Paint &paint)
 
void DrawOval (const Rect &rect, const Paint &paint)
 
void DrawRRect (const Rect &rect, const Size &corner_radii, const Paint &paint)
 
void DrawCircle (const Point &center, Scalar radius, const Paint &paint)
 
void DrawPoints (std::vector< Point > points, Scalar radius, const Paint &paint, PointStyle point_style)
 
void DrawImage (const std::shared_ptr< Image > &image, Point offset, const Paint &paint, SamplerDescriptor sampler={})
 
void DrawImageRect (const std::shared_ptr< Image > &image, Rect source, Rect dest, const Paint &paint, SamplerDescriptor sampler={}, SourceRectConstraint src_rect_constraint=SourceRectConstraint::kFast)
 
void ClipPath (const Path &path, Entity::ClipOperation clip_op=Entity::ClipOperation::kIntersect)
 
void ClipRect (const Rect &rect, Entity::ClipOperation clip_op=Entity::ClipOperation::kIntersect)
 
void ClipOval (const Rect &bounds, Entity::ClipOperation clip_op=Entity::ClipOperation::kIntersect)
 
void ClipRRect (const Rect &rect, const Size &corner_radii, Entity::ClipOperation clip_op=Entity::ClipOperation::kIntersect)
 
void DrawVertices (const std::shared_ptr< VerticesGeometry > &vertices, BlendMode blend_mode, const Paint &paint)
 
void DrawAtlas (const std::shared_ptr< Image > &atlas, std::vector< Matrix > transforms, std::vector< Rect > texture_coordinates, std::vector< Color > colors, BlendMode blend_mode, SamplerDescriptor sampler, std::optional< Rect > cull_rect, const Paint &paint)
 
Picture EndRecordingAsPicture ()
 

Additional Inherited Members

- Static Public Attributes inherited from impeller::Canvas
static constexpr uint32_t kMaxDepth = 1 << 24
 
- Protected Member Functions inherited from impeller::Canvas
size_t GetClipHeight () const
 
void Initialize (std::optional< Rect > cull_rect)
 
void Reset ()
 
- Protected Attributes inherited from impeller::Canvas
std::deque< CanvasStackEntrytransform_stack_
 
std::optional< Rectinitial_cull_rect_
 
uint64_t current_depth_ = 0u
 

Detailed Description

This Canvas attempts to translate from display lists to draw calls directly.

It's not fully implemented yet but if successful it will be replacing the aiks Canvas functionality.

See also:

  • go/impeller-canvas-efficiency

Definition at line 40 of file experimental_canvas.h.

Constructor & Destructor Documentation

◆ ExperimentalCanvas() [1/3]

impeller::ExperimentalCanvas::ExperimentalCanvas ( ContentContext renderer,
RenderTarget render_target,
bool  requires_readback 
)

Definition at line 109 of file experimental_canvas.cc.

112  : Canvas(),
113  renderer_(renderer),
114  render_target_(render_target),
115  requires_readback_(requires_readback),
116  clip_coverage_stack_(EntityPassClipStack(
117  Rect::MakeSize(render_target.GetRenderTargetSize()))) {
118  SetupRenderPass();
119 }

◆ ExperimentalCanvas() [2/3]

impeller::ExperimentalCanvas::ExperimentalCanvas ( ContentContext renderer,
RenderTarget render_target,
bool  requires_readback,
Rect  cull_rect 
)

Definition at line 121 of file experimental_canvas.cc.

125  : Canvas(cull_rect),
126  renderer_(renderer),
127  render_target_(render_target),
128  requires_readback_(requires_readback),
129  clip_coverage_stack_(EntityPassClipStack(
130  Rect::MakeSize(render_target.GetRenderTargetSize()))) {
131  SetupRenderPass();
132 }

◆ ExperimentalCanvas() [3/3]

impeller::ExperimentalCanvas::ExperimentalCanvas ( ContentContext renderer,
RenderTarget render_target,
bool  requires_readback,
IRect  cull_rect 
)

Definition at line 134 of file experimental_canvas.cc.

138  : Canvas(cull_rect),
139  renderer_(renderer),
140  render_target_(render_target),
141  requires_readback_(requires_readback),
142  clip_coverage_stack_(EntityPassClipStack(
143  Rect::MakeSize(render_target.GetRenderTargetSize()))) {
144  SetupRenderPass();
145 }

◆ ~ExperimentalCanvas()

impeller::ExperimentalCanvas::~ExperimentalCanvas ( )
overridedefault

Member Function Documentation

◆ DrawTextFrame()

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

Reimplemented from impeller::Canvas.

Definition at line 558 of file experimental_canvas.cc.

561  {
562  Entity entity;
563  entity.SetClipDepth(GetClipHeight());
564  entity.SetBlendMode(paint.blend_mode);
565 
566  auto text_contents = std::make_shared<TextContents>();
567  text_contents->SetTextFrame(text_frame);
568  text_contents->SetForceTextColor(paint.mask_blur_descriptor.has_value());
569  text_contents->SetScale(GetCurrentTransform().GetMaxBasisLengthXY());
570  text_contents->SetColor(paint.color);
571  text_contents->SetOffset(position);
572  text_contents->SetTextProperties(paint.color, //
573  paint.style == Paint::Style::kStroke, //
574  paint.stroke_width, //
575  paint.stroke_cap, //
576  paint.stroke_join, //
577  paint.stroke_miter //
578  );
579 
580  entity.SetTransform(GetCurrentTransform() *
581  Matrix::MakeTranslation(position));
582 
583  // TODO(bdero): This mask blur application is a hack. It will always wind up
584  // doing a gaussian blur that affects the color source itself
585  // instead of just the mask. The color filter text support
586  // needs to be reworked in order to interact correctly with
587  // mask filters.
588  // https://github.com/flutter/flutter/issues/133297
589  entity.SetContents(paint.WithFilters(paint.WithMaskBlur(
590  std::move(text_contents), true, GetCurrentTransform())));
591 
592  AddRenderEntityToCurrentPass(std::move(entity), false);
593 }

References impeller::Canvas::GetClipHeight(), impeller::Canvas::GetCurrentTransform(), impeller::Paint::kStroke, impeller::Matrix::MakeTranslation(), paint, impeller::Entity::SetBlendMode(), impeller::Entity::SetClipDepth(), impeller::Entity::SetContents(), and impeller::Entity::SetTransform().

◆ EndReplay()

void impeller::ExperimentalCanvas::EndReplay ( )

Definition at line 745 of file experimental_canvas.cc.

745  {
746  FML_DCHECK(render_passes_.size() == 1u);
747  render_passes_.back().inline_pass_context->EndPass();
748 
749  // If requires_readback_ was true, then we rendered to an offscreen texture
750  // instead of to the onscreen provided in the render target. Now we need to
751  // draw or blit the offscreen back to the onscreen.
752  if (requires_readback_) {
753  BlitToOnscreen();
754  }
755 
756  render_passes_.clear();
757  renderer_.GetRenderTargetCache()->End();
758 
759  Reset();
761 }

References impeller::ContentContext::GetRenderTargetCache(), impeller::Canvas::initial_cull_rect_, impeller::Canvas::Initialize(), and impeller::Canvas::Reset().

Referenced by impeller::ExperimentalDlDispatcher::FinishRecording().

◆ Restore()

bool impeller::ExperimentalCanvas::Restore ( )
overridevirtual

Reimplemented from impeller::Canvas.

Definition at line 416 of file experimental_canvas.cc.

416  {
417  FML_DCHECK(transform_stack_.size() > 0);
418  if (transform_stack_.size() == 1) {
419  return false;
420  }
421 
422  // This check is important to make sure we didn't exceed the depth
423  // that the clips were rendered at while rendering any of the
424  // rendering ops. It is OK for the current depth to equal the
425  // outgoing clip depth because that means the clipping would have
426  // been successful up through the last rendering op, but it cannot
427  // be greater.
428  // Also, we bump the current rendering depth to the outgoing clip
429  // depth so that future rendering operations are not clipped by
430  // any of the pixels set by the expiring clips. It is OK for the
431  // estimates used to determine the clip depth in save/saveLayer
432  // to be overly conservative, but we need to jump the depth to
433  // the clip depth so that the next rendering op will get a
434  // larger depth (it will pre-increment the current_depth_ value).
435  FML_CHECK(current_depth_ <= transform_stack_.back().clip_depth)
436  << current_depth_ << " <=? " << transform_stack_.back().clip_depth;
437  current_depth_ = transform_stack_.back().clip_depth;
438 
439  if (transform_stack_.back().rendering_mode ==
441  transform_stack_.back().rendering_mode ==
443  auto lazy_render_pass = std::move(render_passes_.back());
444  render_passes_.pop_back();
445  // Force the render pass to be constructed if it never was.
446  lazy_render_pass.inline_pass_context->GetRenderPass(0);
447 
448  SaveLayerState save_layer_state = save_layer_state_.back();
449  save_layer_state_.pop_back();
450 
451  std::shared_ptr<Contents> contents =
452  PaintPassDelegate(save_layer_state.paint)
453  .CreateContentsForSubpassTarget(
454  lazy_render_pass.inline_pass_context->GetTexture(),
455  transform_stack_.back().transform);
456 
457  lazy_render_pass.inline_pass_context->EndPass();
458 
459  // Round the subpass texture position for pixel alignment with the parent
460  // pass render target. By default, we draw subpass textures with nearest
461  // sampling, so aligning here is important for avoiding visual nearest
462  // sampling errors caused by limited floating point precision when
463  // straddling a half pixel boundary.
464  //
465  // We do this in lieu of expanding/rounding out the subpass coverage in
466  // order to keep the bounds wrapping consistently tight around subpass
467  // elements. Which is necessary to avoid intense flickering in cases
468  // where a subpass texture has a large blur filter with clamp sampling.
469  //
470  // See also this bug: https://github.com/flutter/flutter/issues/144213
471  Point subpass_texture_position =
472  (save_layer_state.coverage.GetOrigin() - GetGlobalPassPosition())
473  .Round();
474 
475  Entity element_entity;
476  element_entity.SetClipDepth(++current_depth_);
477  element_entity.SetContents(std::move(contents));
478  element_entity.SetBlendMode(save_layer_state.paint.blend_mode);
479  element_entity.SetTransform(
480  Matrix::MakeTranslation(Vector3(subpass_texture_position)));
481 
482  if (element_entity.GetBlendMode() > Entity::kLastPipelineBlendMode) {
484  ApplyFramebufferBlend(element_entity);
485  } else {
486  VALIDATION_LOG << "Emulated advanced blends are currently unsupported.";
487  element_entity.SetBlendMode(BlendMode::kSourceOver);
488  }
489  }
490 
491  element_entity.Render(
492  renderer_, //
493  *render_passes_.back().inline_pass_context->GetRenderPass(0).pass //
494  );
495  clip_coverage_stack_.PopSubpass();
496  transform_stack_.pop_back();
497 
498  // We don't need to restore clips if a saveLayer was performed, as the clip
499  // state is per render target, and no more rendering operations will be
500  // performed as the render target workloaded is completed in the restore.
501  return true;
502  }
503 
504  size_t num_clips = transform_stack_.back().num_clips;
505  transform_stack_.pop_back();
506 
507  if (num_clips > 0) {
508  Entity entity;
509  entity.SetTransform(
510  Matrix::MakeTranslation(Vector3(-GetGlobalPassPosition())) *
512  // This path is empty because ClipRestoreContents just generates a quad that
513  // takes up the full render target.
514  auto clip_restore = std::make_shared<ClipRestoreContents>();
515  clip_restore->SetRestoreHeight(GetClipHeight());
516  entity.SetContents(std::move(clip_restore));
517 
518  auto current_clip_coverage = clip_coverage_stack_.CurrentClipCoverage();
519  if (current_clip_coverage.has_value()) {
520  // Entity transforms are relative to the current pass position, so we need
521  // to check clip coverage in the same space.
522  current_clip_coverage =
523  current_clip_coverage->Shift(-GetGlobalPassPosition());
524  }
525 
526  auto clip_coverage = entity.GetClipCoverage(current_clip_coverage);
527  if (clip_coverage.coverage.has_value()) {
528  clip_coverage.coverage =
529  clip_coverage.coverage->Shift(GetGlobalPassPosition());
530  }
531 
532  EntityPassClipStack::ClipStateResult clip_state_result =
533  clip_coverage_stack_.ApplyClipState(clip_coverage, entity,
534  GetClipHeightFloor(),
535  GetGlobalPassPosition());
536 
537  if (clip_state_result.clip_did_change) {
538  // We only need to update the pass scissor if the clip state has changed.
540  clip_coverage_stack_.CurrentClipCoverage(), //
541  *render_passes_.back().inline_pass_context->GetRenderPass(0).pass, //
542  GetGlobalPassPosition() //
543  );
544  }
545 
546  if (!clip_state_result.should_render) {
547  return true;
548  }
549 
550  entity.Render(
551  renderer_,
552  *render_passes_.back().inline_pass_context->GetRenderPass(0).pass);
553  }
554 
555  return true;
556 }

References impeller::EntityPassClipStack::ApplyClipState(), impeller::Paint::blend_mode, impeller::EntityPassClipStack::ClipStateResult::clip_did_change, impeller::Contents::ClipCoverage::coverage, impeller::ExperimentalCanvas::SaveLayerState::coverage, impeller::PaintPassDelegate::CreateContentsForSubpassTarget(), impeller::Canvas::current_depth_, impeller::EntityPassClipStack::CurrentClipCoverage(), impeller::Entity::GetBlendMode(), impeller::Entity::GetClipCoverage(), impeller::Canvas::GetClipHeight(), impeller::Canvas::GetCurrentTransform(), impeller::ContentContext::GetDeviceCapabilities(), impeller::TRect< T >::GetOrigin(), impeller::Entity::kLastPipelineBlendMode, impeller::kSourceOver, impeller::Entity::kSubpassAppendSnapshotTransform, impeller::Entity::kSubpassPrependSnapshotTransform, impeller::Matrix::MakeTranslation(), impeller::ExperimentalCanvas::SaveLayerState::paint, impeller::EntityPassClipStack::PopSubpass(), impeller::Entity::Render(), impeller::Entity::SetBlendMode(), impeller::Entity::SetClipDepth(), impeller::SetClipScissor(), impeller::Entity::SetContents(), impeller::Entity::SetTransform(), impeller::EntityPassClipStack::ClipStateResult::should_render, impeller::Capabilities::SupportsFramebufferFetch(), impeller::Canvas::transform_stack_, and VALIDATION_LOG.

◆ Save()

void impeller::ExperimentalCanvas::Save ( uint32_t  total_content_depth)
overridevirtual

Reimplemented from impeller::Canvas.

Definition at line 193 of file experimental_canvas.cc.

193  {
194  auto entry = CanvasStackEntry{};
195  entry.transform = transform_stack_.back().transform;
196  entry.cull_rect = transform_stack_.back().cull_rect;
197  entry.clip_depth = current_depth_ + total_content_depth;
198  entry.distributed_opacity = transform_stack_.back().distributed_opacity;
199  FML_CHECK(entry.clip_depth <= transform_stack_.back().clip_depth)
200  << entry.clip_depth << " <=? " << transform_stack_.back().clip_depth
201  << " after allocating " << total_content_depth;
202  entry.clip_height = transform_stack_.back().clip_height;
203  entry.rendering_mode = Entity::RenderingMode::kDirect;
204  transform_stack_.emplace_back(entry);
205 }

References impeller::Canvas::current_depth_, impeller::Entity::kDirect, impeller::CanvasStackEntry::transform, and impeller::Canvas::transform_stack_.

Referenced by SaveLayer().

◆ SaveLayer()

void impeller::ExperimentalCanvas::SaveLayer ( const Paint paint,
std::optional< Rect bounds,
const std::shared_ptr< ImageFilter > &  backdrop_filter,
ContentBoundsPromise  bounds_promise,
uint32_t  total_content_depth,
bool  can_distribute_opacity 
)
overridevirtual

Reimplemented from impeller::Canvas.

Definition at line 207 of file experimental_canvas.cc.

213  {
214  // Can we always guarantee that we get a bounds? Does a lack of bounds
215  // indicate something?
216  if (!bounds.has_value()) {
217  bounds = Rect::MakeSize(render_target_.GetRenderTargetSize());
218  }
219 
220  // SaveLayer is a no-op, depending on the bounds promise. Should/Can DL elide
221  // this?
222  if (bounds->IsEmpty()) {
223  Save(total_content_depth);
224  return;
225  }
226 
227  // The maximum coverage of the subpass. Subpasses textures should never
228  // extend outside the parent pass texture or the current clip coverage.
229  Rect coverage_limit = Rect::MakeOriginSize(
230  GetGlobalPassPosition(),
231  Size(render_passes_.back().inline_pass_context->GetTexture()->GetSize()));
232 
233  // BDF No-op. need to do some precomputation to ensure this is fully skipped.
234  if (backdrop_filter) {
235  if (!clip_coverage_stack_.HasCoverage()) {
236  Save(total_content_depth);
237  return;
238  }
239  auto maybe_clip_coverage = clip_coverage_stack_.CurrentClipCoverage();
240  if (!maybe_clip_coverage.has_value()) {
241  Save(total_content_depth);
242  return;
243  }
244  auto clip_coverage = maybe_clip_coverage.value();
245  if (clip_coverage.IsEmpty() ||
246  !coverage_limit.IntersectsWithRect(clip_coverage)) {
247  Save(total_content_depth);
248  return;
249  }
250  }
251 
252  if (can_distribute_opacity && !backdrop_filter &&
254  Save(total_content_depth);
255  transform_stack_.back().distributed_opacity *= paint.color.alpha;
256  return;
257  }
258 
259  // Backdrop filter state, ignored if there is no BDF.
260  std::shared_ptr<FilterContents> backdrop_filter_contents;
261  Point local_position = {0, 0};
262  if (backdrop_filter) {
263  auto current_clip_coverage = clip_coverage_stack_.CurrentClipCoverage();
264  if (current_clip_coverage.has_value()) {
265  local_position =
266  current_clip_coverage->GetOrigin() - GetGlobalPassPosition();
267  }
268  EntityPass::BackdropFilterProc backdrop_filter_proc =
269  [backdrop_filter = backdrop_filter->Clone()](
270  const FilterInput::Ref& input, const Matrix& effect_transform,
271  Entity::RenderingMode rendering_mode) {
272  auto filter = backdrop_filter->WrapInput(input);
273  filter->SetEffectTransform(effect_transform);
274  filter->SetRenderingMode(rendering_mode);
275  return filter;
276  };
277 
278  auto rendering_config = std::move(render_passes_.back());
279  render_passes_.pop_back();
280 
281  // If the very first thing we render in this EntityPass is a subpass that
282  // happens to have a backdrop filter, than that backdrop filter will end
283  // may wind up sampling from the raw, uncleared texture that came straight
284  // out of the texture cache. By calling `pass_context.GetRenderPass` here,
285  // we force the texture to pass through at least one RenderPass with the
286  // correct clear configuration before any sampling occurs.
287  rendering_config.inline_pass_context->GetRenderPass(0);
288 
289  ISize restore_size =
290  rendering_config.inline_pass_context->GetTexture()->GetSize();
291 
292  std::shared_ptr<Texture> input_texture =
293  rendering_config.entity_pass_target->Flip(
294  *renderer_.GetContext()->GetResourceAllocator());
295 
296  backdrop_filter_contents = backdrop_filter_proc(
297  FilterInput::Make(std::move(input_texture)),
298  transform_stack_.back().transform.Basis(),
299  // When the subpass has a translation that means the math with
300  // the snapshot has to be different.
301  transform_stack_.back().transform.HasTranslation()
304 
305  // The subpass will need to read from the current pass texture when
306  // rendering the backdrop, so if there's an active pass, end it prior to
307  // rendering the subpass.
308  rendering_config.inline_pass_context->EndPass();
309 
310  // Create a new render pass that the backdrop filter contents will be
311  // restored to in order to continue rendering.
312  render_passes_.push_back(LazyRenderingConfig(
313  renderer_, std::move(rendering_config.entity_pass_target)));
314  // Eagerly restore the BDF contents.
315 
316  // If the pass context returns a backdrop texture, we need to draw it to the
317  // current pass. We do this because it's faster and takes significantly less
318  // memory than storing/loading large MSAA textures. Also, it's not possible
319  // to blit the non-MSAA resolve texture of the previous pass to MSAA
320  // textures (let alone a transient one).
321  Rect size_rect = Rect::MakeSize(restore_size);
322  auto msaa_backdrop_contents = TextureContents::MakeRect(size_rect);
323  msaa_backdrop_contents->SetStencilEnabled(false);
324  msaa_backdrop_contents->SetLabel("MSAA backdrop");
325  msaa_backdrop_contents->SetSourceRect(size_rect);
326  msaa_backdrop_contents->SetTexture(
327  rendering_config.inline_pass_context->GetTexture());
328 
329  Entity msaa_backdrop_entity;
330  msaa_backdrop_entity.SetContents(std::move(msaa_backdrop_contents));
331  msaa_backdrop_entity.SetBlendMode(BlendMode::kSource);
332  msaa_backdrop_entity.SetClipDepth(std::numeric_limits<uint32_t>::max());
333  if (!msaa_backdrop_entity.Render(renderer_,
334  *render_passes_.back()
335  .inline_pass_context->GetRenderPass(0)
336  .pass)) {
337  VALIDATION_LOG << "Failed to render MSAA backdrop filter entity.";
338  return;
339  }
340 
341  // Restore any clips that were recorded before the backdrop filter was
342  // applied.
343  auto& replay_entities = clip_coverage_stack_.GetReplayEntities();
344  for (const auto& replay : replay_entities) {
346  clip_coverage_stack_.CurrentClipCoverage(),
347  *render_passes_.back().inline_pass_context->GetRenderPass(0).pass,
348  GetGlobalPassPosition());
349  if (!replay.entity.Render(renderer_,
350  *render_passes_.back()
351  .inline_pass_context->GetRenderPass(0)
352  .pass)) {
353  VALIDATION_LOG << "Failed to render entity for clip restore.";
354  }
355  }
356  }
357 
358  // When applying a save layer, absorb any pending distributed opacity.
359  Paint paint_copy = paint;
360  paint_copy.color.alpha *= transform_stack_.back().distributed_opacity;
361  transform_stack_.back().distributed_opacity = 1.0;
362 
363  // Backdrop Filter must expand bounds to at least the clip stack, otherwise
364  // the coverage of the parent render pass.
365  Rect subpass_coverage = bounds->TransformBounds(GetCurrentTransform());
366  if (backdrop_filter_contents) {
367  FML_CHECK(clip_coverage_stack_.HasCoverage());
368  // We should never hit this case as we check the intersection above.
369  // NOLINTBEGIN(bugprone-unchecked-optional-access)
370  subpass_coverage =
371  coverage_limit
372  .Intersection(clip_coverage_stack_.CurrentClipCoverage().value())
373  .value();
374  // NOLINTEND(bugprone-unchecked-optional-access)
375  }
376 
377  render_passes_.push_back(LazyRenderingConfig(
378  renderer_, //
379  CreateRenderTarget(renderer_, //
380  ISize(subpass_coverage.GetSize()), //
381  1u, Color::BlackTransparent())));
382  save_layer_state_.push_back(SaveLayerState{paint_copy, subpass_coverage});
383 
384  CanvasStackEntry entry;
385  entry.transform = transform_stack_.back().transform;
386  entry.cull_rect = transform_stack_.back().cull_rect;
387  entry.clip_depth = current_depth_ + total_content_depth;
388  FML_CHECK(entry.clip_depth <= transform_stack_.back().clip_depth)
389  << entry.clip_depth << " <=? " << transform_stack_.back().clip_depth
390  << " after allocating " << total_content_depth;
391  entry.clip_height = transform_stack_.back().clip_height;
393  transform_stack_.emplace_back(entry);
394 
395  // Start non-collapsed subpasses with a fresh clip coverage stack limited by
396  // the subpass coverage. This is important because image filters applied to
397  // save layers may transform the subpass texture after it's rendered,
398  // causing parent clip coverage to get misaligned with the actual area that
399  // the subpass will affect in the parent pass.
400  clip_coverage_stack_.PushSubpass(subpass_coverage, GetClipHeight());
401 
402  if (backdrop_filter_contents) {
403  // Render the backdrop entity.
404  Entity backdrop_entity;
405  backdrop_entity.SetContents(std::move(backdrop_filter_contents));
406  backdrop_entity.SetTransform(
407  Matrix::MakeTranslation(Vector3(-local_position)));
408  backdrop_entity.SetClipDepth(std::numeric_limits<uint32_t>::max());
409 
410  backdrop_entity.Render(
411  renderer_,
412  *render_passes_.back().inline_pass_context->GetRenderPass(0).pass);
413  }
414 }

References impeller::Color::alpha, impeller::Color::BlackTransparent(), impeller::Paint::CanApplyOpacityPeephole(), impeller::CanvasStackEntry::clip_depth, impeller::CanvasStackEntry::clip_height, impeller::Paint::color, impeller::CreateRenderTarget(), impeller::CanvasStackEntry::cull_rect, impeller::Canvas::current_depth_, impeller::EntityPassClipStack::CurrentClipCoverage(), impeller::Canvas::GetClipHeight(), impeller::ContentContext::GetContext(), impeller::Canvas::GetCurrentTransform(), impeller::RenderTarget::GetRenderTargetSize(), impeller::EntityPassClipStack::GetReplayEntities(), impeller::TRect< T >::GetSize(), impeller::EntityPassClipStack::HasCoverage(), impeller::TRect< T >::Intersection(), impeller::TRect< T >::IntersectsWithRect(), impeller::kSource, impeller::Entity::kSubpassAppendSnapshotTransform, impeller::Entity::kSubpassPrependSnapshotTransform, impeller::FilterInput::Make(), impeller::TRect< Scalar >::MakeOriginSize(), impeller::TextureContents::MakeRect(), impeller::TRect< Scalar >::MakeSize(), impeller::Matrix::MakeTranslation(), paint, impeller::EntityPassClipStack::PushSubpass(), impeller::Entity::Render(), impeller::CanvasStackEntry::rendering_mode, Save(), impeller::Entity::SetBlendMode(), impeller::Entity::SetClipDepth(), impeller::SetClipScissor(), impeller::Entity::SetContents(), impeller::Entity::SetTransform(), impeller::CanvasStackEntry::transform, impeller::Canvas::transform_stack_, impeller::TRect< T >::TransformBounds(), and VALIDATION_LOG.


The documentation for this class was generated from the following files:
impeller::ISize
ISize64 ISize
Definition: size.h:140
impeller::Entity::kLastPipelineBlendMode
static constexpr BlendMode kLastPipelineBlendMode
Definition: entity.h:22
impeller::EntityPass::BackdropFilterProc
std::function< std::shared_ptr< FilterContents >(FilterInput::Ref, const Matrix &effect_transform, Entity::RenderingMode rendering_mode)> BackdropFilterProc
Definition: entity_pass.h:59
impeller::EntityPassClipStack::PushSubpass
void PushSubpass(std::optional< Rect > subpass_coverage, size_t clip_height)
Definition: entity_pass_clip_stack.cc:31
impeller::Paint::Style::kStroke
@ kStroke
impeller::FilterInput::Make
static FilterInput::Ref Make(Variant input, bool msaa_enabled=true)
Definition: filter_input.cc:19
impeller::BlendMode::kSource
@ kSource
impeller::Entity::RenderingMode::kSubpassAppendSnapshotTransform
@ kSubpassAppendSnapshotTransform
impeller::TRect::TransformBounds
constexpr TRect TransformBounds(const Matrix &transform) const
Creates a new bounding box that contains this transformed rectangle.
Definition: rect.h:463
impeller::EntityPassClipStack::HasCoverage
bool HasCoverage() const
Definition: entity_pass_clip_stack.cc:27
impeller::FilterInput::Ref
std::shared_ptr< FilterInput > Ref
Definition: filter_input.h:32
impeller::ExperimentalCanvas::Save
void Save(uint32_t total_content_depth) override
Definition: experimental_canvas.cc:193
impeller::Size
TSize< Scalar > Size
Definition: size.h:137
impeller::Matrix::MakeTranslation
static constexpr Matrix MakeTranslation(const Vector3 &t)
Definition: matrix.h:95
impeller::Canvas::initial_cull_rect_
std::optional< Rect > initial_cull_rect_
Definition: canvas.h:182
impeller::Canvas::GetCurrentTransform
const Matrix & GetCurrentTransform() const
Definition: canvas.cc:298
impeller::Canvas::Initialize
void Initialize(std::optional< Rect > cull_rect)
Definition: canvas.cc:164
impeller::EntityPassClipStack::ApplyClipState
ClipStateResult ApplyClipState(Contents::ClipCoverage global_clip_coverage, Entity &entity, size_t clip_height_floor, Point global_pass_position)
Applies the current clip state to an Entity. If the given Entity is a clip operation,...
Definition: entity_pass_clip_stack.cc:51
impeller::EntityPassClipStack::GetReplayEntities
const std::vector< ReplayResult > & GetReplayEntities() const
Definition: entity_pass_clip_stack.cc:158
impeller::Point
TPoint< Scalar > Point
Definition: point.h:322
impeller::EntityPassClipStack::CurrentClipCoverage
std::optional< Rect > CurrentClipCoverage() const
Definition: entity_pass_clip_stack.cc:23
impeller::ContentContext::GetContext
std::shared_ptr< Context > GetContext() const
Definition: content_context.cc:553
impeller::TRect< Scalar >::MakeOriginSize
constexpr static TRect MakeOriginSize(const TPoint< Type > &origin, const TSize< Type > &size)
Definition: rect.h:140
impeller::CreateRenderTarget
static std::unique_ptr< EntityPassTarget > CreateRenderTarget(ContentContext &renderer, ISize size, int mip_count, const Color &clear_color)
Definition: experimental_canvas.cc:55
impeller::Entity::RenderingMode::kDirect
@ kDirect
impeller::Rect
TRect< Scalar > Rect
Definition: rect.h:769
impeller::SetClipScissor
static void SetClipScissor(std::optional< Rect > clip_coverage, RenderPass &pass, Point global_pass_position)
Definition: entity_pass.cc:725
impeller::Canvas::Canvas
Canvas()
Definition: canvas.cc:149
impeller::EntityPassClipStack::PopSubpass
void PopSubpass()
Definition: entity_pass_clip_stack.cc:42
impeller::Canvas::current_depth_
uint64_t current_depth_
Definition: canvas.h:183
impeller::RenderTarget::GetRenderTargetSize
ISize GetRenderTargetSize() const
Definition: render_target.cc:139
VALIDATION_LOG
#define VALIDATION_LOG
Definition: validation.h:73
impeller::Canvas::GetClipHeight
size_t GetClipHeight() const
Definition: canvas.cc:825
impeller::ContentContext::GetRenderTargetCache
const std::shared_ptr< RenderTargetAllocator > & GetRenderTargetCache() const
Definition: content_context.h:724
impeller::ContentContext::GetDeviceCapabilities
const Capabilities & GetDeviceCapabilities() const
Definition: content_context.cc:557
impeller::Entity::RenderingMode::kSubpassPrependSnapshotTransform
@ kSubpassPrependSnapshotTransform
impeller::TRect< Scalar >::MakeSize
constexpr static TRect MakeSize(const TSize< U > &size)
Definition: rect.h:146
impeller::Color::BlackTransparent
static constexpr Color BlackTransparent()
Definition: color.h:272
paint
const Paint & paint
Definition: color_source.cc:38
impeller::Paint::CanApplyOpacityPeephole
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:36
impeller::Entity::RenderingMode
RenderingMode
Definition: entity.h:27
impeller::Capabilities::SupportsFramebufferFetch
virtual bool SupportsFramebufferFetch() const =0
Whether the context backend is able to support pipelines with shaders that read from the framebuffer ...
impeller::TextureContents::MakeRect
static std::shared_ptr< TextureContents > MakeRect(Rect destination)
A common case factory that marks the texture contents as having a destination rectangle....
Definition: texture_contents.cc:27
impeller::Canvas::transform_stack_
std::deque< CanvasStackEntry > transform_stack_
Definition: canvas.h:181
impeller::BlendMode::kSourceOver
@ kSourceOver
impeller::Canvas::Reset
void Reset()
Definition: canvas.cc:177