Flutter Engine
The Flutter Engine
experimental_canvas.cc
Go to the documentation of this file.
1// Copyright 2013 The Flutter Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
6#include "fml/logging.h"
16
17namespace impeller {
18
19namespace {
20
21static void SetClipScissor(std::optional<Rect> clip_coverage,
22 RenderPass& pass,
23 Point global_pass_position) {
24 // Set the scissor to the clip coverage area. We do this prior to rendering
25 // the clip itself and all its contents.
26 IRect scissor;
27 if (clip_coverage.has_value()) {
28 clip_coverage = clip_coverage->Shift(-global_pass_position);
29 scissor = IRect::RoundOut(clip_coverage.value());
30 // The scissor rect must not exceed the size of the render target.
31 scissor = scissor.Intersection(IRect::MakeSize(pass.GetRenderTargetSize()))
32 .value_or(IRect());
33 }
34 pass.SetScissor(scissor);
35}
36
37static void ApplyFramebufferBlend(Entity& entity) {
38 auto src_contents = entity.GetContents();
39 auto contents = std::make_shared<FramebufferBlendContents>();
40 contents->SetChildContents(src_contents);
41 contents->SetBlendMode(entity.GetBlendMode());
42 entity.SetContents(std::move(contents));
43 entity.SetBlendMode(BlendMode::kSource);
44}
45
46} // namespace
47
51 .load_action = LoadAction::kDontCare,
52 .store_action = StoreAction::kDontCare,
53 };
54
55static std::unique_ptr<EntityPassTarget> CreateRenderTarget(
57 ISize size,
58 int mip_count,
59 const Color& clear_color) {
60 const std::shared_ptr<Context>& context = renderer.GetContext();
61
62 /// All of the load/store actions are managed by `InlinePassContext` when
63 /// `RenderPasses` are created, so we just set them to `kDontCare` here.
64 /// What's important is the `StorageMode` of the textures, which cannot be
65 /// changed for the lifetime of the textures.
66
67 if (context->GetBackendType() == Context::BackendType::kOpenGLES) {
68 // TODO(https://github.com/flutter/flutter/issues/141732): Implement mip map
69 // generation on opengles.
70 mip_count = 1;
71 }
72
74 if (context->GetCapabilities()->SupportsOffscreenMSAA()) {
75 target = renderer.GetRenderTargetCache()->CreateOffscreenMSAA(
76 /*context=*/*context,
77 /*size=*/size,
78 /*mip_count=*/mip_count,
79 /*label=*/"EntityPass",
80 /*color_attachment_config=*/
83 .resolve_storage_mode = StorageMode::kDevicePrivate,
84 .load_action = LoadAction::kDontCare,
86 .clear_color = clear_color},
87 /*stencil_attachment_config=*/
89 } else {
90 target = renderer.GetRenderTargetCache()->CreateOffscreen(
91 *context, // context
92 size, // size
93 /*mip_count=*/mip_count,
94 "EntityPass", // label
97 .load_action = LoadAction::kDontCare,
98 .store_action = StoreAction::kDontCare,
99 .clear_color = clear_color,
100 }, // color_attachment_config
101 kDefaultStencilConfig // stencil_attachment_config
102 );
103 }
104
105 return std::make_unique<EntityPassTarget>(
106 target, renderer.GetDeviceCapabilities().SupportsReadFromResolve(),
107 renderer.GetDeviceCapabilities().SupportsImplicitResolvingMSAA());
108}
109
111 RenderTarget& render_target,
112 bool requires_readback)
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}
121
123 RenderTarget& render_target,
124 bool requires_readback,
125 Rect cull_rect)
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}
134
136 RenderTarget& render_target,
137 bool requires_readback,
138 IRect cull_rect)
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}
147
148void ExperimentalCanvas::SetupRenderPass() {
149 renderer_.GetRenderTargetCache()->Start();
150 auto color0 = render_target_.GetColorAttachments().find(0u)->second;
151
152 auto& stencil_attachment = render_target_.GetStencilAttachment();
153 auto& depth_attachment = render_target_.GetDepthAttachment();
154 if (!stencil_attachment.has_value() || !depth_attachment.has_value()) {
155 // Setup a new root stencil with an optimal configuration if one wasn't
156 // provided by the caller.
157 render_target_.SetupDepthStencilAttachments(
158 *renderer_.GetContext(),
159 *renderer_.GetContext()->GetResourceAllocator(),
160 color0.texture->GetSize(),
161 renderer_.GetContext()->GetCapabilities()->SupportsOffscreenMSAA(),
162 "ImpellerOnscreen", kDefaultStencilConfig);
163 }
164
165 // Set up the clear color of the root pass.
166 color0.clear_color = Color::BlackTransparent();
167 render_target_.SetColorAttachment(color0, 0);
168
169 // If requires_readback is true, then there is a backdrop filter or emulated
170 // advanced blend in the first save layer. This requires a readback, which
171 // isn't supported by onscreen textures. To support this, we immediately begin
172 // a second save layer with the same dimensions as the onscreen. When
173 // rendering is completed, we must blit this saveLayer to the onscreen.
174 if (requires_readback_) {
175 entity_pass_targets_.push_back(CreateRenderTarget(
176 renderer_, color0.texture->GetSize(), /*mip_count=*/1,
177 /*clear_color=*/Color::BlackTransparent()));
178 } else {
179 entity_pass_targets_.push_back(std::make_unique<EntityPassTarget>(
180 render_target_,
183 }
184
185 auto inline_pass = std::make_unique<InlinePassContext>(
186 renderer_, *entity_pass_targets_.back(), 0);
187 inline_pass_contexts_.emplace_back(std::move(inline_pass));
188 auto result = inline_pass_contexts_.back()->GetRenderPass(0u);
189 render_passes_.push_back(result.pass);
190}
191
192void ExperimentalCanvas::Save(uint32_t total_content_depth) {
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}
205
207 const Paint& paint,
208 std::optional<Rect> bounds,
209 const std::shared_ptr<ImageFilter>& backdrop_filter,
210 ContentBoundsPromise bounds_promise,
211 uint32_t total_content_depth,
212 bool can_distribute_opacity) {
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}
264
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);
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}
380
382 const std::shared_ptr<TextFrame>& text_frame,
383 Point position,
384 const Paint& paint) {
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
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}
417
418void ExperimentalCanvas::AddRenderEntityToCurrentPass(Entity entity,
419 bool reuse_depth) {
420 entity.SetInheritedOpacity(transform_stack_.back().distributed_opacity);
421
422 auto transform = entity.GetTransform();
423 entity.SetTransform(
424 Matrix::MakeTranslation(Vector3(-GetGlobalPassPosition())) * transform);
425 if (!reuse_depth) {
427 }
428 // We can render at a depth up to and including the depth of the currently
429 // active clips and we will still be clipped out, but we cannot render at
430 // a depth that is greater than the current clips or we will not be clipped.
431 FML_CHECK(current_depth_ <= transform_stack_.back().clip_depth)
432 << current_depth_ << " <=? " << transform_stack_.back().clip_depth;
434
437 ApplyFramebufferBlend(entity);
438 } else {
439 VALIDATION_LOG << "Emulated advanced blends are currently unsupported.";
440 return;
441 }
442 }
443
444 entity.Render(renderer_, *render_passes_.back());
445}
446
447void ExperimentalCanvas::AddClipEntityToCurrentPass(Entity entity) {
448 auto transform = entity.GetTransform();
449 entity.SetTransform(
450 Matrix::MakeTranslation(Vector3(-GetGlobalPassPosition())) * transform);
451 // Ideally the clip depth would be greater than the current rendering
452 // depth because any rendering calls that follow this clip operation will
453 // pre-increment the depth and then be rendering above our clip depth,
454 // but that case will be caught by the CHECK in AddRenderEntity above.
455 // In practice we sometimes have a clip set with no rendering after it
456 // and in such cases the current depth will equal the clip depth.
457 // Eventually the DisplayList should optimize these out, but it is hard
458 // to know if a clip will actually be used in advance of storing it in
459 // the DisplayList buffer.
460 // See https://github.com/flutter/flutter/issues/147021
461 FML_CHECK(current_depth_ <= transform_stack_.back().clip_depth)
462 << current_depth_ << " <=? " << transform_stack_.back().clip_depth;
463 entity.SetClipDepth(transform_stack_.back().clip_depth);
464
465 auto current_clip_coverage = clip_coverage_stack_.CurrentClipCoverage();
466 if (current_clip_coverage.has_value()) {
467 // Entity transforms are relative to the current pass position, so we need
468 // to check clip coverage in the same space.
469 current_clip_coverage =
470 current_clip_coverage->Shift(-GetGlobalPassPosition());
471 }
472
473 auto clip_coverage = entity.GetClipCoverage(current_clip_coverage);
474 if (clip_coverage.coverage.has_value()) {
475 clip_coverage.coverage =
476 clip_coverage.coverage->Shift(GetGlobalPassPosition());
477 }
478
479 EntityPassClipStack::ClipStateResult clip_state_result =
480 clip_coverage_stack_.ApplyClipState(
481 clip_coverage, entity, GetClipHeightFloor(), GetGlobalPassPosition());
482
483 if (clip_state_result.clip_did_change) {
484 // We only need to update the pass scissor if the clip state has changed.
485 SetClipScissor(clip_coverage_stack_.CurrentClipCoverage(),
486 *render_passes_.back(), GetGlobalPassPosition());
487 }
488
489 if (!clip_state_result.should_render) {
490 return;
491 }
492
493 entity.Render(renderer_, *render_passes_.back());
494}
495
496bool ExperimentalCanvas::BlitToOnscreen() {
497 auto command_buffer = renderer_.GetContext()->CreateCommandBuffer();
498 command_buffer->SetLabel("EntityPass Root Command Buffer");
499 auto offscreen_target = entity_pass_targets_.back()->GetRenderTarget();
500
501 if (renderer_.GetContext()
502 ->GetCapabilities()
503 ->SupportsTextureToTextureBlits()) {
504 auto blit_pass = command_buffer->CreateBlitPass();
505 blit_pass->AddCopy(offscreen_target.GetRenderTargetTexture(),
506 render_target_.GetRenderTargetTexture());
507 if (!blit_pass->EncodeCommands(
508 renderer_.GetContext()->GetResourceAllocator())) {
509 VALIDATION_LOG << "Failed to encode root pass blit command.";
510 return false;
511 }
512 if (!renderer_.GetContext()
513 ->GetCommandQueue()
514 ->Submit({command_buffer})
515 .ok()) {
516 return false;
517 }
518 } else {
519 auto render_pass = command_buffer->CreateRenderPass(render_target_);
520 render_pass->SetLabel("EntityPass Root Render Pass");
521
522 {
523 auto size_rect = Rect::MakeSize(offscreen_target.GetRenderTargetSize());
524 auto contents = TextureContents::MakeRect(size_rect);
525 contents->SetTexture(offscreen_target.GetRenderTargetTexture());
526 contents->SetSourceRect(size_rect);
527 contents->SetLabel("Root pass blit");
528
529 Entity entity;
530 entity.SetContents(contents);
531 entity.SetBlendMode(BlendMode::kSource);
532
533 if (!entity.Render(renderer_, *render_pass)) {
534 VALIDATION_LOG << "Failed to render EntityPass root blit.";
535 return false;
536 }
537 }
538
539 if (!render_pass->EncodeCommands()) {
540 VALIDATION_LOG << "Failed to encode root pass command buffer.";
541 return false;
542 }
543 if (!renderer_.GetContext()
544 ->GetCommandQueue()
545 ->Submit({command_buffer})
546 .ok()) {
547 return false;
548 }
549 }
550 return true;
551}
552
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}
571
572} // namespace impeller
void Initialize(std::optional< Rect > cull_rect)
Definition: canvas.cc:164
const Matrix & GetCurrentTransform() const
Definition: canvas.cc:298
size_t GetClipHeight() const
Definition: canvas.cc:825
std::optional< Rect > initial_cull_rect_
Definition: canvas.h:182
std::deque< CanvasStackEntry > transform_stack_
Definition: canvas.h:181
uint64_t current_depth_
Definition: canvas.h:183
void Reset()
Definition: canvas.cc:177
virtual bool SupportsImplicitResolvingMSAA() const =0
Whether the context backend supports multisampled rendering to the on-screen surface without requirin...
virtual bool SupportsFramebufferFetch() const =0
Whether the context backend is able to support pipelines with shaders that read from the framebuffer ...
virtual bool SupportsReadFromResolve() const =0
Whether the context backend supports binding the current RenderPass attachments. This is supported if...
const std::shared_ptr< RenderTargetAllocator > & GetRenderTargetCache() const
const Capabilities & GetDeviceCapabilities() const
std::shared_ptr< Context > GetContext() const
A class that tracks all clips that have been recorded in the current entity pass stencil.
std::optional< Rect > CurrentClipCoverage() const
void PushSubpass(std::optional< Rect > subpass_coverage, size_t clip_height)
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,...
void SetTransform(const Matrix &transform)
Set the global transform matrix for this Entity.
Definition: entity.cc:62
bool SetInheritedOpacity(Scalar alpha)
Definition: entity.cc:134
void SetClipDepth(uint32_t clip_depth)
Definition: entity.cc:98
BlendMode GetBlendMode() const
Definition: entity.cc:119
void SetContents(std::shared_ptr< Contents > contents)
Definition: entity.cc:90
void SetBlendMode(BlendMode blend_mode)
Definition: entity.cc:115
bool Render(const ContentContext &renderer, RenderPass &parent_pass) const
Definition: entity.cc:173
const Matrix & GetTransform() const
Get the global transform matrix for this Entity.
Definition: entity.cc:46
static constexpr BlendMode kLastPipelineBlendMode
Definition: entity.h:22
Contents::ClipCoverage GetClipCoverage(const std::optional< Rect > &current_clip_coverage) const
Definition: entity.cc:74
void DrawTextFrame(const std::shared_ptr< TextFrame > &text_frame, Point position, const Paint &paint) override
ExperimentalCanvas(ContentContext &renderer, RenderTarget &render_target, bool requires_readback)
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
std::shared_ptr< Contents > CreateContentsForSubpassTarget(std::shared_ptr< Texture > target, const Matrix &effect_transform) override
std::shared_ptr< Texture > GetRenderTargetTexture() const
const std::map< size_t, ColorAttachment > & GetColorAttachments() const
RenderTarget & SetColorAttachment(const ColorAttachment &attachment, size_t index)
void SetupDepthStencilAttachments(const Context &context, Allocator &allocator, ISize size, bool msaa, const std::string &label="Offscreen", RenderTarget::AttachmentConfig stencil_attachment_config=RenderTarget::kDefaultStencilAttachmentConfig, const std::shared_ptr< Texture > &depth_stencil_texture=nullptr)
ISize GetRenderTargetSize() const
const std::optional< DepthAttachment > & GetDepthAttachment() const
const std::optional< StencilAttachment > & GetStencilAttachment() const
static std::shared_ptr< TextureContents > MakeRect(Rect destination)
A common case factory that marks the texture contents as having a destination rectangle....
const Paint & paint
Definition: color_source.cc:38
GAsyncResult * result
uint32_t * target
#define FML_CHECK(condition)
Definition: logging.h:85
#define FML_DCHECK(condition)
Definition: logging.h:103
Optional< SkRect > bounds
Definition: SkRecords.h:189
it will be possible to load the file into Perfetto s trace viewer 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
Definition: switches.h:259
static void SetClipScissor(std::optional< Rect > clip_coverage, RenderPass &pass, Point global_pass_position)
Definition: entity_pass.cc:725
static std::unique_ptr< EntityPassTarget > CreateRenderTarget(ContentContext &renderer, ISize size, int mip_count, const Color &clear_color)
TPoint< Scalar > Point
Definition: point.h:322
IRect64 IRect
Definition: rect.h:772
ContentBoundsPromise
Definition: entity_pass.h:28
static const constexpr RenderTarget::AttachmentConfig kDefaultStencilConfig
static SkColor4f transform(SkColor4f c, SkColorSpace *src, SkColorSpace *dst)
Definition: p3.cpp:47
Entity::RenderingMode rendering_mode
Definition: canvas.h:40
std::optional< Rect > cull_rect
Definition: canvas.h:34
static constexpr Color BlackTransparent()
Definition: color.h:272
Scalar alpha
Definition: color.h:143
std::optional< Rect > coverage
Definition: contents.h:41
static constexpr Matrix MakeTranslation(const Vector3 &t)
Definition: matrix.h:95
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
Color color
Definition: paint.h:68
BlendMode blend_mode
Definition: paint.h:76
constexpr TSize< Type > GetSize() const
Returns the size of the rectangle which may be negative in either width or height and may have been c...
Definition: rect.h:317
RoundOut(const TRect< U > &r)
Definition: rect.h:666
static constexpr TRect MakeSize(const TSize< U > &size)
Definition: rect.h:146
constexpr TRect< T > Shift(T dx, T dy) const
Returns a new rectangle translated by the given offset.
Definition: rect.h:589
constexpr TPoint< Type > GetOrigin() const
Returns the upper left corner of the rectangle as specified by the left/top or x/y values when it was...
Definition: rect.h:310
static constexpr TSize MakeWH(Type width, Type height)
Definition: size.h:34
#define VALIDATION_LOG
Definition: validation.h:73