Flutter Engine
The Flutter Engine
Classes | Public Member Functions | List of all members
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 ()
 
virtual void Save (uint32_t total_content_depth=kMaxDepth)
 
virtual void SaveLayer (const Paint &paint, std::optional< Rect > bounds=std::nullopt, const std::shared_ptr< ImageFilter > &backdrop_filter=nullptr, ContentBoundsPromise bounds_promise=ContentBoundsPromise::kUnknown, uint32_t total_content_depth=kMaxDepth, bool can_distribute_opacity=false)
 
virtual bool Restore ()
 
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)
 
virtual 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< 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:

Definition at line 28 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 110 of file experimental_canvas.cc.

113 : Canvas(),
114 renderer_(renderer),
115 render_target_(render_target),
116 requires_readback_(requires_readback),
117 clip_coverage_stack_(EntityPassClipStack(
118 Rect::MakeSize(render_target.GetRenderTargetSize()))) {
119 SetupRenderPass();
120}
static constexpr TRect MakeSize(const TSize< U > &size)
Definition: rect.h:146

◆ ExperimentalCanvas() [2/3]

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

Definition at line 122 of file experimental_canvas.cc.

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

◆ ExperimentalCanvas() [3/3]

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

Definition at line 135 of file experimental_canvas.cc.

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

◆ ~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 381 of file experimental_canvas.cc.

384 {
385 Entity entity;
386 entity.SetClipDepth(GetClipHeight());
387 entity.SetBlendMode(paint.blend_mode);
388
389 auto text_contents = std::make_shared<TextContents>();
390 text_contents->SetTextFrame(text_frame);
391 text_contents->SetForceTextColor(paint.mask_blur_descriptor.has_value());
392 text_contents->SetScale(GetCurrentTransform().GetMaxBasisLengthXY());
393 text_contents->SetColor(paint.color);
394 text_contents->SetOffset(position);
395 text_contents->SetTextProperties(paint.color, //
396 paint.style == Paint::Style::kStroke, //
397 paint.stroke_width, //
398 paint.stroke_cap, //
399 paint.stroke_join, //
400 paint.stroke_miter //
401 );
402
403 entity.SetTransform(GetCurrentTransform() *
404 Matrix::MakeTranslation(position));
405
406 // TODO(bdero): This mask blur application is a hack. It will always wind up
407 // doing a gaussian blur that affects the color source itself
408 // instead of just the mask. The color filter text support
409 // needs to be reworked in order to interact correctly with
410 // mask filters.
411 // https://github.com/flutter/flutter/issues/133297
412 entity.SetContents(paint.WithFilters(paint.WithMaskBlur(
413 std::move(text_contents), true, GetCurrentTransform())));
414
415 AddRenderEntityToCurrentPass(std::move(entity), false);
416}
const Matrix & GetCurrentTransform() const
Definition: canvas.cc:298
size_t GetClipHeight() const
Definition: canvas.cc:825
const Paint & paint
Definition: color_source.cc:38
static constexpr Matrix MakeTranslation(const Vector3 &t)
Definition: matrix.h:95

◆ EndReplay()

void impeller::ExperimentalCanvas::EndReplay ( )

Definition at line 553 of file experimental_canvas.cc.

553 {
554 FML_DCHECK(inline_pass_contexts_.size() == 1u);
555 inline_pass_contexts_.back()->EndPass();
556
557 // If requires_readback_ was true, then we rendered to an offscreen texture
558 // instead of to the onscreen provided in the render target. Now we need to
559 // draw or blit the offscreen back to the onscreen.
560 if (requires_readback_) {
561 BlitToOnscreen();
562 }
563
564 render_passes_.clear();
565 inline_pass_contexts_.clear();
566 renderer_.GetRenderTargetCache()->End();
567
568 Reset();
570}
void Initialize(std::optional< Rect > cull_rect)
Definition: canvas.cc:164
std::optional< Rect > initial_cull_rect_
Definition: canvas.h:182
void Reset()
Definition: canvas.cc:177
const std::shared_ptr< RenderTargetAllocator > & GetRenderTargetCache() const
#define FML_DCHECK(condition)
Definition: logging.h:103

◆ Restore()

bool impeller::ExperimentalCanvas::Restore ( )
overridevirtual

Reimplemented from impeller::Canvas.

Definition at line 265 of file experimental_canvas.cc.

265 {
266 FML_DCHECK(transform_stack_.size() > 0);
267 if (transform_stack_.size() == 1) {
268 return false;
269 }
270
271 // This check is important to make sure we didn't exceed the depth
272 // that the clips were rendered at while rendering any of the
273 // rendering ops. It is OK for the current depth to equal the
274 // outgoing clip depth because that means the clipping would have
275 // been successful up through the last rendering op, but it cannot
276 // be greater.
277 // Also, we bump the current rendering depth to the outgoing clip
278 // depth so that future rendering operations are not clipped by
279 // any of the pixels set by the expiring clips. It is OK for the
280 // estimates used to determine the clip depth in save/saveLayer
281 // to be overly conservative, but we need to jump the depth to
282 // the clip depth so that the next rendering op will get a
283 // larger depth (it will pre-increment the current_depth_ value).
284 FML_CHECK(current_depth_ <= transform_stack_.back().clip_depth)
285 << current_depth_ << " <=? " << transform_stack_.back().clip_depth;
286 current_depth_ = transform_stack_.back().clip_depth;
287
288 if (transform_stack_.back().rendering_mode ==
290 transform_stack_.back().rendering_mode ==
292 auto inline_pass = std::move(inline_pass_contexts_.back());
293
294 SaveLayerState save_layer_state = save_layer_state_.back();
295 save_layer_state_.pop_back();
296
297 std::shared_ptr<Contents> contents =
298 PaintPassDelegate(save_layer_state.paint)
299 .CreateContentsForSubpassTarget(inline_pass->GetTexture(),
300 transform_stack_.back().transform);
301
302 inline_pass->EndPass();
303 render_passes_.pop_back();
304 inline_pass_contexts_.pop_back();
305
306 Entity element_entity;
307 element_entity.SetClipDepth(++current_depth_);
308 element_entity.SetContents(std::move(contents));
309 element_entity.SetBlendMode(save_layer_state.paint.blend_mode);
310 element_entity.SetTransform(Matrix::MakeTranslation(
311 Vector3(save_layer_state.coverage.GetOrigin())));
312
313 if (element_entity.GetBlendMode() > Entity::kLastPipelineBlendMode) {
315 ApplyFramebufferBlend(element_entity);
316 } else {
317 VALIDATION_LOG << "Emulated advanced blends are currently unsupported.";
318 element_entity.SetBlendMode(BlendMode::kSourceOver);
319 }
320 }
321
322 element_entity.Render(renderer_, *render_passes_.back());
323 clip_coverage_stack_.PopSubpass();
324 transform_stack_.pop_back();
325
326 // We don't need to restore clips if a saveLayer was performed, as the clip
327 // state is per render target, and no more rendering operations will be
328 // performed as the render target workloaded is completed in the restore.
329 return true;
330 }
331
332 size_t num_clips = transform_stack_.back().num_clips;
333 transform_stack_.pop_back();
334
335 if (num_clips > 0) {
336 Entity entity;
337 entity.SetTransform(
338 Matrix::MakeTranslation(Vector3(-GetGlobalPassPosition())) *
340 // This path is empty because ClipRestoreContents just generates a quad that
341 // takes up the full render target.
342 auto clip_restore = std::make_shared<ClipRestoreContents>();
343 clip_restore->SetRestoreHeight(GetClipHeight());
344 entity.SetContents(std::move(clip_restore));
345
346 auto current_clip_coverage = clip_coverage_stack_.CurrentClipCoverage();
347 if (current_clip_coverage.has_value()) {
348 // Entity transforms are relative to the current pass position, so we need
349 // to check clip coverage in the same space.
350 current_clip_coverage =
351 current_clip_coverage->Shift(-GetGlobalPassPosition());
352 }
353
354 auto clip_coverage = entity.GetClipCoverage(current_clip_coverage);
355 if (clip_coverage.coverage.has_value()) {
356 clip_coverage.coverage =
357 clip_coverage.coverage->Shift(GetGlobalPassPosition());
358 }
359
360 EntityPassClipStack::ClipStateResult clip_state_result =
361 clip_coverage_stack_.ApplyClipState(clip_coverage, entity,
362 GetClipHeightFloor(),
363 GetGlobalPassPosition());
364
365 if (clip_state_result.clip_did_change) {
366 // We only need to update the pass scissor if the clip state has changed.
367 SetClipScissor(clip_coverage_stack_.CurrentClipCoverage(),
368 *render_passes_.back(), GetGlobalPassPosition());
369 }
370
371 if (!clip_state_result.should_render) {
372 return true;
373 }
374
375 entity.Render(renderer_, *render_passes_.back());
376 }
377
378 return true;
379}
std::deque< CanvasStackEntry > transform_stack_
Definition: canvas.h:181
uint64_t current_depth_
Definition: canvas.h:183
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
std::optional< Rect > CurrentClipCoverage() const
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,...
static constexpr BlendMode kLastPipelineBlendMode
Definition: entity.h:22
#define FML_CHECK(condition)
Definition: logging.h:85
static void SetClipScissor(std::optional< Rect > clip_coverage, RenderPass &pass, Point global_pass_position)
Definition: entity_pass.cc:725
#define VALIDATION_LOG
Definition: validation.h:73

◆ Save()

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

Reimplemented from impeller::Canvas.

Definition at line 192 of file experimental_canvas.cc.

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

◆ 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 206 of file experimental_canvas.cc.

212 {
213 if (can_distribute_opacity && !backdrop_filter &&
215 Save(total_content_depth);
216 transform_stack_.back().distributed_opacity *= paint.color.alpha;
217 return;
218 }
219 // Can we always guarantee that we get a bounds? Does a lack of bounds
220 // indicate something?
221 if (!bounds.has_value()) {
222 bounds = Rect::MakeSize(render_target_.GetRenderTargetSize());
223 }
224
225 // When applying a save layer, absorb any pending distributed opacity.
226 Paint paint_copy = paint;
227 paint_copy.color.alpha *= transform_stack_.back().distributed_opacity;
228 transform_stack_.back().distributed_opacity = 1.0;
229
230 Rect subpass_coverage = bounds->TransformBounds(GetCurrentTransform());
231 auto target =
232 CreateRenderTarget(renderer_,
233 ISize::MakeWH(subpass_coverage.GetSize().width,
234 subpass_coverage.GetSize().height),
236 entity_pass_targets_.push_back(std::move(target));
237 save_layer_state_.push_back(SaveLayerState{paint_copy, subpass_coverage});
238
239 CanvasStackEntry entry;
240 entry.transform = transform_stack_.back().transform;
241 entry.cull_rect = transform_stack_.back().cull_rect;
242 entry.clip_depth = current_depth_ + total_content_depth;
243 FML_CHECK(entry.clip_depth <= transform_stack_.back().clip_depth)
244 << entry.clip_depth << " <=? " << transform_stack_.back().clip_depth
245 << " after allocating " << total_content_depth;
246 entry.clip_height = transform_stack_.back().clip_height;
248 transform_stack_.emplace_back(entry);
249
250 auto inline_pass = std::make_unique<InlinePassContext>(
251 renderer_, *entity_pass_targets_.back(), 0);
252 inline_pass_contexts_.emplace_back(std::move(inline_pass));
253
254 auto result = inline_pass_contexts_.back()->GetRenderPass(0u);
255 render_passes_.push_back(result.pass);
256
257 // Start non-collapsed subpasses with a fresh clip coverage stack limited by
258 // the subpass coverage. This is important because image filters applied to
259 // save layers may transform the subpass texture after it's rendered,
260 // causing parent clip coverage to get misaligned with the actual area that
261 // the subpass will affect in the parent pass.
262 clip_coverage_stack_.PushSubpass(subpass_coverage, GetClipHeight());
263}
void PushSubpass(std::optional< Rect > subpass_coverage, size_t clip_height)
void Save(uint32_t total_content_depth) override
ISize GetRenderTargetSize() const
GAsyncResult * result
uint32_t * target
Optional< SkRect > bounds
Definition: SkRecords.h:189
static std::unique_ptr< EntityPassTarget > CreateRenderTarget(ContentContext &renderer, ISize size, int mip_count, const Color &clear_color)
TRect< Scalar > Rect
Definition: rect.h:769
static constexpr Color BlackTransparent()
Definition: color.h:272
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
static constexpr TSize MakeWH(Type width, Type height)
Definition: size.h:34

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