From c4feb4bf475b678bf230fa3ee31b0bea4154d030 Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Wed, 26 Jun 2024 15:13:45 -0700 Subject: [PATCH 01/17] [Impeller] experimental canvas bdf support. --- impeller/aiks/experimental_canvas.cc | 237 +++++++++++++++++++----- impeller/aiks/experimental_canvas.h | 16 +- impeller/aiks/image_filter.h | 8 + impeller/display_list/dl_playground.cc | 2 +- impeller/entity/entity_pass.cc | 42 ++--- shell/gpu/gpu_surface_metal_impeller.mm | 6 +- 6 files changed, 233 insertions(+), 78 deletions(-) diff --git a/impeller/aiks/experimental_canvas.cc b/impeller/aiks/experimental_canvas.cc index 6d6565e92da7d..6dcc842132d38 100644 --- a/impeller/aiks/experimental_canvas.cc +++ b/impeller/aiks/experimental_canvas.cc @@ -63,6 +63,9 @@ static std::unique_ptr CreateRenderTarget( /// `RenderPasses` are created, so we just set them to `kDontCare` here. /// What's important is the `StorageMode` of the textures, which cannot be /// changed for the lifetime of the textures. + if (size.IsEmpty()) { + FML_LOG(ERROR) << "WARNING EMPTY RT"; + } if (context->GetBackendType() == Context::BackendType::kOpenGLES) { // TODO(https://github.com/flutter/flutter/issues/141732): Implement mip map @@ -172,21 +175,23 @@ void ExperimentalCanvas::SetupRenderPass() { // a second save layer with the same dimensions as the onscreen. When // rendering is completed, we must blit this saveLayer to the onscreen. if (requires_readback_) { - entity_pass_targets_.push_back(CreateRenderTarget( - renderer_, color0.texture->GetSize(), /*mip_count=*/1, - /*clear_color=*/Color::BlackTransparent())); + auto entity_pass_target = + CreateRenderTarget(renderer_, // + color0.texture->GetSize(), // + /*mip_count=*/1, // + /*clear_color=*/Color::BlackTransparent() // + ); + render_passes_.push_back( + LazyRenderingConfig(renderer_, std::move(entity_pass_target))); } else { - entity_pass_targets_.push_back(std::make_unique( - render_target_, - renderer_.GetDeviceCapabilities().SupportsReadFromResolve(), - renderer_.GetDeviceCapabilities().SupportsImplicitResolvingMSAA())); + auto entity_pass_target = std::make_unique( + render_target_, // + renderer_.GetDeviceCapabilities().SupportsReadFromResolve(), // + renderer_.GetDeviceCapabilities().SupportsImplicitResolvingMSAA() // + ); + render_passes_.push_back( + LazyRenderingConfig(renderer_, std::move(entity_pass_target))); } - - auto inline_pass = std::make_unique( - renderer_, *entity_pass_targets_.back(), 0); - inline_pass_contexts_.emplace_back(std::move(inline_pass)); - auto result = inline_pass_contexts_.back()->GetRenderPass(0u); - render_passes_.push_back(result.pass); } void ExperimentalCanvas::Save(uint32_t total_content_depth) { @@ -195,9 +200,9 @@ void ExperimentalCanvas::Save(uint32_t total_content_depth) { entry.cull_rect = transform_stack_.back().cull_rect; entry.clip_depth = current_depth_ + total_content_depth; entry.distributed_opacity = transform_stack_.back().distributed_opacity; - FML_CHECK(entry.clip_depth <= transform_stack_.back().clip_depth) - << entry.clip_depth << " <=? " << transform_stack_.back().clip_depth - << " after allocating " << total_content_depth; + // FML_CHECK(entry.clip_depth <= transform_stack_.back().clip_depth) + // << entry.clip_depth << " <=? " << transform_stack_.back().clip_depth + // << " after allocating " << total_content_depth; entry.clip_height = transform_stack_.back().clip_height; entry.rendering_mode = Entity::RenderingMode::kDirect; transform_stack_.emplace_back(entry); @@ -210,16 +215,116 @@ void ExperimentalCanvas::SaveLayer( ContentBoundsPromise bounds_promise, uint32_t total_content_depth, bool can_distribute_opacity) { + // Can we always guarantee that we get a bounds? Does a lack of bounds + // indicate something? + if (!bounds.has_value()) { + bounds = Rect::MakeSize(render_target_.GetRenderTargetSize()); + } + + if (bounds->IsEmpty()) { + return; + } + if (can_distribute_opacity && !backdrop_filter && Paint::CanApplyOpacityPeephole(paint)) { Save(total_content_depth); transform_stack_.back().distributed_opacity *= paint.color.alpha; return; } - // Can we always guarantee that we get a bounds? Does a lack of bounds - // indicate something? - if (!bounds.has_value()) { - bounds = Rect::MakeSize(render_target_.GetRenderTargetSize()); + + int required_mip_count = 1; + std::shared_ptr backdrop_filter_contents_; + if (backdrop_filter) { + EntityPass::BackdropFilterProc backdrop_filter_proc = + [backdrop_filter = backdrop_filter->Clone()]( + const FilterInput::Ref& input, const Matrix& effect_transform, + Entity::RenderingMode rendering_mode) { + auto filter = backdrop_filter->WrapInput(input); + filter->SetEffectTransform(effect_transform); + filter->SetRenderingMode(rendering_mode); + return filter; + }; + required_mip_count = backdrop_filter->GetRequiredMipCount(); + + auto rendering_config = std::move(render_passes_.back()); + render_passes_.pop_back(); + + // If the very first thing we render in this EntityPass is a subpass that + // happens to have a backdrop filter, than that backdrop filter will end + // may wind up sampling from the raw, uncleared texture that came straight + // out of the texture cache. By calling `pass_context.GetRenderPass` here, + // we force the texture to pass through at least one RenderPass with the + // correct clear configuration before any sampling occurs. + rendering_config.inline_pass_context->GetRenderPass(0); + + ISize restore_size = + rendering_config.inline_pass_context->GetTexture()->GetSize(); + backdrop_filter_contents_ = backdrop_filter_proc( + FilterInput::Make(rendering_config.inline_pass_context->GetTexture()), + transform_stack_.back().transform.Basis(), + // When the subpass has a translation that means the math with + // the snapshot has to be different. + transform_stack_.back().transform.HasTranslation() + ? Entity::RenderingMode::kSubpassPrependSnapshotTransform + : Entity::RenderingMode::kSubpassAppendSnapshotTransform); + + // The subpass will need to read from the current pass texture when + // rendering the backdrop, so if there's an active pass, end it prior to + // rendering the subpass. + rendering_config.inline_pass_context->EndPass(); + + // Create a new render pass that the backdrop filter contents will be + // restored to in order to continue rendering. + render_passes_.push_back( + LazyRenderingConfig(renderer_, // + CreateRenderTarget(renderer_, // + restore_size, // + 1, + Color::BlackTransparent() // + ))); + + // Eagerly restore the BDF contents. + + // If the pass context returns a backdrop texture, we need to draw it to the + // current pass. We do this because it's faster and takes significantly less + // memory than storing/loading large MSAA textures. Also, it's not possible + // to blit the non-MSAA resolve texture of the previous pass to MSAA + // textures (let alone a transient one). + Rect size_rect = Rect::MakeSize(restore_size); + auto msaa_backdrop_contents = TextureContents::MakeRect(size_rect); + msaa_backdrop_contents->SetStencilEnabled(false); + msaa_backdrop_contents->SetLabel("MSAA backdrop"); + msaa_backdrop_contents->SetSourceRect(size_rect); + msaa_backdrop_contents->SetTexture( + rendering_config.inline_pass_context->GetTexture()); + + Entity msaa_backdrop_entity; + msaa_backdrop_entity.SetContents(std::move(msaa_backdrop_contents)); + msaa_backdrop_entity.SetBlendMode(BlendMode::kSource); + msaa_backdrop_entity.SetClipDepth(std::numeric_limits::max()); + if (!msaa_backdrop_entity.Render(renderer_, + *render_passes_.back() + .inline_pass_context->GetRenderPass(0) + .pass)) { + VALIDATION_LOG << "Failed to render MSAA backdrop filter entity."; + return; + } + + // Restore any clips that were recorded before the backdrop filter was + // applied. + auto& replay_entities = clip_coverage_stack_.GetReplayEntities(); + for (const auto& replay : replay_entities) { + SetClipScissor( + clip_coverage_stack_.CurrentClipCoverage(), + *render_passes_.back().inline_pass_context->GetRenderPass(0).pass, + GetGlobalPassPosition()); + if (!replay.entity.Render(renderer_, + *render_passes_.back() + .inline_pass_context->GetRenderPass(0) + .pass)) { + VALIDATION_LOG << "Failed to render entity for clip restore."; + } + } } // When applying a save layer, absorb any pending distributed opacity. @@ -228,12 +333,12 @@ void ExperimentalCanvas::SaveLayer( transform_stack_.back().distributed_opacity = 1.0; Rect subpass_coverage = bounds->TransformBounds(GetCurrentTransform()); - auto target = - CreateRenderTarget(renderer_, - ISize::MakeWH(subpass_coverage.GetSize().width, - subpass_coverage.GetSize().height), - 1u, Color::BlackTransparent()); - entity_pass_targets_.push_back(std::move(target)); + render_passes_.push_back(LazyRenderingConfig( + renderer_, // + CreateRenderTarget(renderer_, // + ISize(subpass_coverage.GetSize()), // + required_mip_count, Color::BlackTransparent() // + ))); save_layer_state_.push_back(SaveLayerState{paint_copy, subpass_coverage}); CanvasStackEntry entry; @@ -247,19 +352,25 @@ void ExperimentalCanvas::SaveLayer( entry.rendering_mode = Entity::RenderingMode::kSubpassAppendSnapshotTransform; transform_stack_.emplace_back(entry); - auto inline_pass = std::make_unique( - renderer_, *entity_pass_targets_.back(), 0); - inline_pass_contexts_.emplace_back(std::move(inline_pass)); - - auto result = inline_pass_contexts_.back()->GetRenderPass(0u); - render_passes_.push_back(result.pass); - // Start non-collapsed subpasses with a fresh clip coverage stack limited by // the subpass coverage. This is important because image filters applied to // save layers may transform the subpass texture after it's rendered, // causing parent clip coverage to get misaligned with the actual area that // the subpass will affect in the parent pass. clip_coverage_stack_.PushSubpass(subpass_coverage, GetClipHeight()); + + if (backdrop_filter_contents_) { + // Render the backdrop entity. + Entity backdrop_entity; + backdrop_entity.SetContents(std::move(backdrop_filter_contents_)); + backdrop_entity.SetTransform(Matrix::MakeTranslation( + Vector3(-GetGlobalPassPosition()))); + backdrop_entity.SetClipDepth(std::numeric_limits::max()); + + backdrop_entity.Render( + renderer_, + *render_passes_.back().inline_pass_context->GetRenderPass(0).pass); + } } bool ExperimentalCanvas::Restore() { @@ -289,19 +400,21 @@ bool ExperimentalCanvas::Restore() { Entity::RenderingMode::kSubpassAppendSnapshotTransform || transform_stack_.back().rendering_mode == Entity::RenderingMode::kSubpassPrependSnapshotTransform) { - auto inline_pass = std::move(inline_pass_contexts_.back()); + auto lazy_render_pass = std::move(render_passes_.back()); + render_passes_.pop_back(); + // Force the render pass to be constructed if it never was. + lazy_render_pass.inline_pass_context->GetRenderPass(0); SaveLayerState save_layer_state = save_layer_state_.back(); save_layer_state_.pop_back(); std::shared_ptr contents = PaintPassDelegate(save_layer_state.paint) - .CreateContentsForSubpassTarget(inline_pass->GetTexture(), - transform_stack_.back().transform); + .CreateContentsForSubpassTarget( + lazy_render_pass.inline_pass_context->GetTexture(), + transform_stack_.back().transform); - inline_pass->EndPass(); - render_passes_.pop_back(); - inline_pass_contexts_.pop_back(); + lazy_render_pass.inline_pass_context->EndPass(); Entity element_entity; element_entity.SetClipDepth(++current_depth_); @@ -319,7 +432,10 @@ bool ExperimentalCanvas::Restore() { } } - element_entity.Render(renderer_, *render_passes_.back()); + element_entity.Render( + renderer_, // + *render_passes_.back().inline_pass_context->GetRenderPass(0).pass // + ); clip_coverage_stack_.PopSubpass(); transform_stack_.pop_back(); @@ -364,15 +480,20 @@ bool ExperimentalCanvas::Restore() { if (clip_state_result.clip_did_change) { // We only need to update the pass scissor if the clip state has changed. - SetClipScissor(clip_coverage_stack_.CurrentClipCoverage(), - *render_passes_.back(), GetGlobalPassPosition()); + SetClipScissor( + clip_coverage_stack_.CurrentClipCoverage(), // + *render_passes_.back().inline_pass_context->GetRenderPass(0).pass, // + GetGlobalPassPosition() // + ); } if (!clip_state_result.should_render) { return true; } - entity.Render(renderer_, *render_passes_.back()); + entity.Render( + renderer_, + *render_passes_.back().inline_pass_context->GetRenderPass(0).pass); } return true; @@ -441,7 +562,16 @@ void ExperimentalCanvas::AddRenderEntityToCurrentPass(Entity entity, } } - entity.Render(renderer_, *render_passes_.back()); + InlinePassContext::RenderPassResult result = + render_passes_.back().inline_pass_context->GetRenderPass(0); + if (!result.pass) { + // Failure to produce a render pass should be explained by specific errors + // in `InlinePassContext::GetRenderPass()`, so avoid log spam and don't + // append a validation log here. + return; + } + + entity.Render(renderer_, *result.pass); } void ExperimentalCanvas::AddClipEntityToCurrentPass(Entity entity) { @@ -482,21 +612,27 @@ void ExperimentalCanvas::AddClipEntityToCurrentPass(Entity entity) { if (clip_state_result.clip_did_change) { // We only need to update the pass scissor if the clip state has changed. - SetClipScissor(clip_coverage_stack_.CurrentClipCoverage(), - *render_passes_.back(), GetGlobalPassPosition()); + SetClipScissor( + clip_coverage_stack_.CurrentClipCoverage(), + *render_passes_.back().inline_pass_context->GetRenderPass(0).pass, + GetGlobalPassPosition()); } if (!clip_state_result.should_render) { return; } - entity.Render(renderer_, *render_passes_.back()); + entity.Render( + renderer_, + *render_passes_.back().inline_pass_context->GetRenderPass(0).pass); } bool ExperimentalCanvas::BlitToOnscreen() { auto command_buffer = renderer_.GetContext()->CreateCommandBuffer(); command_buffer->SetLabel("EntityPass Root Command Buffer"); - auto offscreen_target = entity_pass_targets_.back()->GetRenderTarget(); + auto offscreen_target = render_passes_.back() + .inline_pass_context->GetPassTarget() + .GetRenderTarget(); if (renderer_.GetContext() ->GetCapabilities() @@ -551,8 +687,8 @@ bool ExperimentalCanvas::BlitToOnscreen() { } void ExperimentalCanvas::EndReplay() { - FML_DCHECK(inline_pass_contexts_.size() == 1u); - inline_pass_contexts_.back()->EndPass(); + FML_DCHECK(render_passes_.size() == 1u); + render_passes_.back().inline_pass_context->EndPass(); // If requires_readback_ was true, then we rendered to an offscreen texture // instead of to the onscreen provided in the render target. Now we need to @@ -562,7 +698,6 @@ void ExperimentalCanvas::EndReplay() { } render_passes_.clear(); - inline_pass_contexts_.clear(); renderer_.GetRenderTargetCache()->End(); Reset(); diff --git a/impeller/aiks/experimental_canvas.h b/impeller/aiks/experimental_canvas.h index 4595207dda723..64264e0681c4c 100644 --- a/impeller/aiks/experimental_canvas.h +++ b/impeller/aiks/experimental_canvas.h @@ -18,6 +18,18 @@ namespace impeller { +struct LazyRenderingConfig { + std::unique_ptr entity_pass_target; + std::unique_ptr inline_pass_context; + + LazyRenderingConfig(ContentContext& renderer, + std::unique_ptr p_entity_pass_target) + : entity_pass_target(std::move(p_entity_pass_target)) { + inline_pass_context = + std::make_unique(renderer, *entity_pass_target, 0); + } +}; + /// 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 @@ -78,10 +90,8 @@ class ExperimentalCanvas : public Canvas { RenderTarget& render_target_; const bool requires_readback_; EntityPassClipStack clip_coverage_stack_; - std::vector> inline_pass_contexts_; - std::vector> entity_pass_targets_; + std::vector render_passes_; std::vector save_layer_state_; - std::vector> render_passes_; void SetupRenderPass(); diff --git a/impeller/aiks/image_filter.h b/impeller/aiks/image_filter.h index 9d72c14d1a522..d82f9c7cf5b23 100644 --- a/impeller/aiks/image_filter.h +++ b/impeller/aiks/image_filter.h @@ -87,6 +87,10 @@ class ImageFilter { virtual std::shared_ptr Clone() const = 0; virtual void Visit(ImageFilterVisitor& visitor) = 0; + + virtual int GetRequiredMipCount() const { + return 1; + } }; /******************************************************************************* @@ -112,6 +116,10 @@ class BlurImageFilter : public ImageFilter { // |ImageFilter| void Visit(ImageFilterVisitor& visitor) override { visitor.Visit(*this); } + int GetRequiredMipCount() const override { + return 4; + } + private: Sigma sigma_x_; Sigma sigma_y_; diff --git a/impeller/display_list/dl_playground.cc b/impeller/display_list/dl_playground.cc index d31526c51cec2..e9ec474d1cbac 100644 --- a/impeller/display_list/dl_playground.cc +++ b/impeller/display_list/dl_playground.cc @@ -15,7 +15,7 @@ #include "third_party/skia/include/core/SkTypeface.h" #include "txt/platform.h" -#define ENABLE_EXPERIMENTAL_CANVAS false +#define ENABLE_EXPERIMENTAL_CANVAS true namespace impeller { diff --git a/impeller/entity/entity_pass.cc b/impeller/entity/entity_pass.cc index 22a6aafeb68a2..d858369a987c4 100644 --- a/impeller/entity/entity_pass.cc +++ b/impeller/entity/entity_pass.cc @@ -544,27 +544,27 @@ EntityPass::EntityResult EntityPass::GetEntityForElement( return EntityPass::EntityResult::Skip(); } - if (!subpass->backdrop_filter_proc_ && - subpass->delegate_->CanCollapseIntoParentPass(subpass)) { - // Directly render into the parent target and move on. - if (!subpass->OnRender( - renderer, // renderer - root_pass_size, // root_pass_size - pass_context.GetPassTarget(), // pass_target - global_pass_position, // global_pass_position - Point(), // local_pass_position - pass_depth, // pass_depth - clip_coverage_stack, // clip_coverage_stack - clip_height_, // clip_height_floor - nullptr, // backdrop_filter_contents - pass_context.GetRenderPass(pass_depth) // collapsed_parent_pass - )) { - // Validation error messages are triggered for all `OnRender()` failure - // cases. - return EntityPass::EntityResult::Failure(); - } - return EntityPass::EntityResult::Skip(); - } + // if (!subpass->backdrop_filter_proc_ && + // subpass->delegate_->CanCollapseIntoParentPass(subpass)) { + // // Directly render into the parent target and move on. + // if (!subpass->OnRender( + // renderer, // renderer + // root_pass_size, // root_pass_size + // pass_context.GetPassTarget(), // pass_target + // global_pass_position, // global_pass_position + // Point(), // local_pass_position + // pass_depth, // pass_depth + // clip_coverage_stack, // clip_coverage_stack + // clip_height_, // clip_height_floor + // nullptr, // backdrop_filter_contents + // pass_context.GetRenderPass(pass_depth) // collapsed_parent_pass + // )) { + // // Validation error messages are triggered for all `OnRender()` failure + // // cases. + // return EntityPass::EntityResult::Failure(); + // } + // return EntityPass::EntityResult::Skip(); + // } std::shared_ptr subpass_backdrop_filter_contents = nullptr; if (subpass->backdrop_filter_proc_) { diff --git a/shell/gpu/gpu_surface_metal_impeller.mm b/shell/gpu/gpu_surface_metal_impeller.mm index 8664aed5e7c9a..ac4886c820a4b 100644 --- a/shell/gpu/gpu_surface_metal_impeller.mm +++ b/shell/gpu/gpu_surface_metal_impeller.mm @@ -17,7 +17,7 @@ static_assert(!__has_feature(objc_arc), "ARC must be disabled."); -#define ENABLE_EXPERIMENTAL_CANVAS false +#define ENABLE_EXPERIMENTAL_CANVAS true namespace flutter { @@ -293,7 +293,9 @@ fml::MakeCopyable([aiks_context, &display_list, &cull_rect, &sk_cull_rect](impeller::RenderTarget& render_target) -> bool { impeller::ExperimentalDlDispatcher impeller_dispatcher( - aiks_context->GetContentContext(), render_target, cull_rect); + aiks_context->GetContentContext(), render_target, + display_list->root_has_backdrop_filter(), display_list->max_root_blend_mode(), + cull_rect); display_list->Dispatch(impeller_dispatcher, sk_cull_rect); impeller_dispatcher.FinishRecording(); aiks_context->GetContentContext().GetTransientsBuffer().Reset(); From 42343d3b89da29d76b8aea82271311a07e550b8c Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Wed, 26 Jun 2024 21:06:08 -0700 Subject: [PATCH 02/17] fix subpass offset. --- impeller/aiks/experimental_canvas.cc | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/impeller/aiks/experimental_canvas.cc b/impeller/aiks/experimental_canvas.cc index 6dcc842132d38..e99e17cc8f71a 100644 --- a/impeller/aiks/experimental_canvas.cc +++ b/impeller/aiks/experimental_canvas.cc @@ -416,12 +416,27 @@ bool ExperimentalCanvas::Restore() { lazy_render_pass.inline_pass_context->EndPass(); + // Round the subpass texture position for pixel alignment with the parent + // pass render target. By default, we draw subpass textures with nearest + // sampling, so aligning here is important for avoiding visual nearest + // sampling errors caused by limited floating point precision when + // straddling a half pixel boundary. + // + // We do this in lieu of expanding/rounding out the subpass coverage in + // order to keep the bounds wrapping consistently tight around subpass + // elements. Which is necessary to avoid intense flickering in cases + // where a subpass texture has a large blur filter with clamp sampling. + // + // See also this bug: https://github.com/flutter/flutter/issues/144213 + Point subpass_texture_position = + (save_layer_state.coverage.GetOrigin() - GetGlobalPassPosition()).Round(); + Entity element_entity; element_entity.SetClipDepth(++current_depth_); element_entity.SetContents(std::move(contents)); element_entity.SetBlendMode(save_layer_state.paint.blend_mode); element_entity.SetTransform(Matrix::MakeTranslation( - Vector3(save_layer_state.coverage.GetOrigin()))); + Vector3(subpass_texture_position))); if (element_entity.GetBlendMode() > Entity::kLastPipelineBlendMode) { if (renderer_.GetDeviceCapabilities().SupportsFramebufferFetch()) { From 3d73c9d93659da4076641c8511aa1c3ef2e83899 Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Thu, 27 Jun 2024 08:59:22 -0700 Subject: [PATCH 03/17] fix bdfs. --- impeller/aiks/experimental_canvas.cc | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/impeller/aiks/experimental_canvas.cc b/impeller/aiks/experimental_canvas.cc index e99e17cc8f71a..bdc2c525e5f6e 100644 --- a/impeller/aiks/experimental_canvas.cc +++ b/impeller/aiks/experimental_canvas.cc @@ -234,7 +234,10 @@ void ExperimentalCanvas::SaveLayer( int required_mip_count = 1; std::shared_ptr backdrop_filter_contents_; + Point local_position = {0, 0}; if (backdrop_filter) { + local_position = clip_coverage_stack_.CurrentClipCoverage()->GetOrigin() - + GetGlobalPassPosition(); EntityPass::BackdropFilterProc backdrop_filter_proc = [backdrop_filter = backdrop_filter->Clone()]( const FilterInput::Ref& input, const Matrix& effect_transform, @@ -332,7 +335,13 @@ void ExperimentalCanvas::SaveLayer( paint_copy.color.alpha *= transform_stack_.back().distributed_opacity; transform_stack_.back().distributed_opacity = 1.0; + // Backdrop Filter must expand bounds to at least the clip stack. Rect subpass_coverage = bounds->TransformBounds(GetCurrentTransform()); + if (backdrop_filter_contents_) { + subpass_coverage = + clip_coverage_stack_.CurrentClipCoverage().value_or(subpass_coverage); + } + render_passes_.push_back(LazyRenderingConfig( renderer_, // CreateRenderTarget(renderer_, // @@ -363,8 +372,8 @@ void ExperimentalCanvas::SaveLayer( // Render the backdrop entity. Entity backdrop_entity; backdrop_entity.SetContents(std::move(backdrop_filter_contents_)); - backdrop_entity.SetTransform(Matrix::MakeTranslation( - Vector3(-GetGlobalPassPosition()))); + backdrop_entity.SetTransform( + Matrix::MakeTranslation(Vector3(-local_position))); backdrop_entity.SetClipDepth(std::numeric_limits::max()); backdrop_entity.Render( @@ -429,14 +438,15 @@ bool ExperimentalCanvas::Restore() { // // See also this bug: https://github.com/flutter/flutter/issues/144213 Point subpass_texture_position = - (save_layer_state.coverage.GetOrigin() - GetGlobalPassPosition()).Round(); + (save_layer_state.coverage.GetOrigin() - GetGlobalPassPosition()) + .Round(); Entity element_entity; element_entity.SetClipDepth(++current_depth_); element_entity.SetContents(std::move(contents)); element_entity.SetBlendMode(save_layer_state.paint.blend_mode); - element_entity.SetTransform(Matrix::MakeTranslation( - Vector3(subpass_texture_position))); + element_entity.SetTransform( + Matrix::MakeTranslation(Vector3(subpass_texture_position))); if (element_entity.GetBlendMode() > Entity::kLastPipelineBlendMode) { if (renderer_.GetDeviceCapabilities().SupportsFramebufferFetch()) { From 95905065c608ee13eb791bb6421f5e39a5f8c013 Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Thu, 27 Jun 2024 10:30:31 -0700 Subject: [PATCH 04/17] ++ --- impeller/display_list/dl_playground.cc | 4 ++-- impeller/entity/entity_pass_clip_stack.cc | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/impeller/display_list/dl_playground.cc b/impeller/display_list/dl_playground.cc index e9ec474d1cbac..e8486ea079fb5 100644 --- a/impeller/display_list/dl_playground.cc +++ b/impeller/display_list/dl_playground.cc @@ -56,8 +56,8 @@ bool DlPlayground::OpenPlaygroundHere(DisplayListPlaygroundCallback callback) { ExperimentalDlDispatcher impeller_dispatcher( context.GetContentContext(), render_target, - display_list->root_has_backdrop_filter(), - display_list->max_root_blend_mode(), IRect::MakeMaximum()); + list->root_has_backdrop_filter(), + list->max_root_blend_mode(), IRect::MakeMaximum()); list->Dispatch(impeller_dispatcher); impeller_dispatcher.FinishRecording(); context.GetContentContext().GetTransientsBuffer().Reset(); diff --git a/impeller/entity/entity_pass_clip_stack.cc b/impeller/entity/entity_pass_clip_stack.cc index 54a30aceef209..eab0565b3d382 100644 --- a/impeller/entity/entity_pass_clip_stack.cc +++ b/impeller/entity/entity_pass_clip_stack.cc @@ -4,7 +4,6 @@ #include "impeller/entity/entity_pass_clip_stack.h" #include "impeller/entity/contents/clip_contents.h" -#include "impeller/entity/contents/content_context.h" #include "impeller/entity/entity.h" namespace impeller { From eb0d4dbb61c16891e5b0586dc92c7cbc16d2b679 Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Thu, 27 Jun 2024 10:55:39 -0700 Subject: [PATCH 05/17] format --- impeller/aiks/image_filter.h | 8 ++------ impeller/display_list/dl_playground.cc | 4 ++-- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/impeller/aiks/image_filter.h b/impeller/aiks/image_filter.h index d82f9c7cf5b23..23911cad878d0 100644 --- a/impeller/aiks/image_filter.h +++ b/impeller/aiks/image_filter.h @@ -88,9 +88,7 @@ class ImageFilter { virtual void Visit(ImageFilterVisitor& visitor) = 0; - virtual int GetRequiredMipCount() const { - return 1; - } + virtual int GetRequiredMipCount() const { return 1; } }; /******************************************************************************* @@ -116,9 +114,7 @@ class BlurImageFilter : public ImageFilter { // |ImageFilter| void Visit(ImageFilterVisitor& visitor) override { visitor.Visit(*this); } - int GetRequiredMipCount() const override { - return 4; - } + int GetRequiredMipCount() const override { return 4; } private: Sigma sigma_x_; diff --git a/impeller/display_list/dl_playground.cc b/impeller/display_list/dl_playground.cc index e8486ea079fb5..19b7a0bc2b7de 100644 --- a/impeller/display_list/dl_playground.cc +++ b/impeller/display_list/dl_playground.cc @@ -56,8 +56,8 @@ bool DlPlayground::OpenPlaygroundHere(DisplayListPlaygroundCallback callback) { ExperimentalDlDispatcher impeller_dispatcher( context.GetContentContext(), render_target, - list->root_has_backdrop_filter(), - list->max_root_blend_mode(), IRect::MakeMaximum()); + list->root_has_backdrop_filter(), list->max_root_blend_mode(), + IRect::MakeMaximum()); list->Dispatch(impeller_dispatcher); impeller_dispatcher.FinishRecording(); context.GetContentContext().GetTransientsBuffer().Reset(); From 2a23c4ceaf464ad8e350240d2f8d7ca31fd671aa Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Thu, 27 Jun 2024 10:56:41 -0700 Subject: [PATCH 06/17] ++ --- impeller/entity/entity_pass.cc | 42 +++++++++++++++++----------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/impeller/entity/entity_pass.cc b/impeller/entity/entity_pass.cc index d858369a987c4..22a6aafeb68a2 100644 --- a/impeller/entity/entity_pass.cc +++ b/impeller/entity/entity_pass.cc @@ -544,27 +544,27 @@ EntityPass::EntityResult EntityPass::GetEntityForElement( return EntityPass::EntityResult::Skip(); } - // if (!subpass->backdrop_filter_proc_ && - // subpass->delegate_->CanCollapseIntoParentPass(subpass)) { - // // Directly render into the parent target and move on. - // if (!subpass->OnRender( - // renderer, // renderer - // root_pass_size, // root_pass_size - // pass_context.GetPassTarget(), // pass_target - // global_pass_position, // global_pass_position - // Point(), // local_pass_position - // pass_depth, // pass_depth - // clip_coverage_stack, // clip_coverage_stack - // clip_height_, // clip_height_floor - // nullptr, // backdrop_filter_contents - // pass_context.GetRenderPass(pass_depth) // collapsed_parent_pass - // )) { - // // Validation error messages are triggered for all `OnRender()` failure - // // cases. - // return EntityPass::EntityResult::Failure(); - // } - // return EntityPass::EntityResult::Skip(); - // } + if (!subpass->backdrop_filter_proc_ && + subpass->delegate_->CanCollapseIntoParentPass(subpass)) { + // Directly render into the parent target and move on. + if (!subpass->OnRender( + renderer, // renderer + root_pass_size, // root_pass_size + pass_context.GetPassTarget(), // pass_target + global_pass_position, // global_pass_position + Point(), // local_pass_position + pass_depth, // pass_depth + clip_coverage_stack, // clip_coverage_stack + clip_height_, // clip_height_floor + nullptr, // backdrop_filter_contents + pass_context.GetRenderPass(pass_depth) // collapsed_parent_pass + )) { + // Validation error messages are triggered for all `OnRender()` failure + // cases. + return EntityPass::EntityResult::Failure(); + } + return EntityPass::EntityResult::Skip(); + } std::shared_ptr subpass_backdrop_filter_contents = nullptr; if (subpass->backdrop_filter_proc_) { From 5363f4a7050499c9f099a1feae7c53f03cf5c66e Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Thu, 27 Jun 2024 13:54:13 -0700 Subject: [PATCH 07/17] ++ --- impeller/aiks/experimental_canvas.cc | 33 ++++++++++++++-------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/impeller/aiks/experimental_canvas.cc b/impeller/aiks/experimental_canvas.cc index bdc2c525e5f6e..e5b2de2c54d4e 100644 --- a/impeller/aiks/experimental_canvas.cc +++ b/impeller/aiks/experimental_canvas.cc @@ -63,9 +63,6 @@ static std::unique_ptr CreateRenderTarget( /// `RenderPasses` are created, so we just set them to `kDontCare` here. /// What's important is the `StorageMode` of the textures, which cannot be /// changed for the lifetime of the textures. - if (size.IsEmpty()) { - FML_LOG(ERROR) << "WARNING EMPTY RT"; - } if (context->GetBackendType() == Context::BackendType::kOpenGLES) { // TODO(https://github.com/flutter/flutter/issues/141732): Implement mip map @@ -200,9 +197,9 @@ void ExperimentalCanvas::Save(uint32_t total_content_depth) { entry.cull_rect = transform_stack_.back().cull_rect; entry.clip_depth = current_depth_ + total_content_depth; entry.distributed_opacity = transform_stack_.back().distributed_opacity; - // FML_CHECK(entry.clip_depth <= transform_stack_.back().clip_depth) - // << entry.clip_depth << " <=? " << transform_stack_.back().clip_depth - // << " after allocating " << total_content_depth; + FML_CHECK(entry.clip_depth <= transform_stack_.back().clip_depth) + << entry.clip_depth << " <=? " << transform_stack_.back().clip_depth + << " after allocating " << total_content_depth; entry.clip_height = transform_stack_.back().clip_height; entry.rendering_mode = Entity::RenderingMode::kDirect; transform_stack_.emplace_back(entry); @@ -233,11 +230,14 @@ void ExperimentalCanvas::SaveLayer( } int required_mip_count = 1; - std::shared_ptr backdrop_filter_contents_; + std::shared_ptr backdrop_filter_contents; Point local_position = {0, 0}; if (backdrop_filter) { - local_position = clip_coverage_stack_.CurrentClipCoverage()->GetOrigin() - - GetGlobalPassPosition(); + auto current_clip_coverage = clip_coverage_stack_.CurrentClipCoverage(); + if (current_clip_coverage.has_value()) { + local_position = + current_clip_coverage->GetOrigin() - GetGlobalPassPosition(); + } EntityPass::BackdropFilterProc backdrop_filter_proc = [backdrop_filter = backdrop_filter->Clone()]( const FilterInput::Ref& input, const Matrix& effect_transform, @@ -262,7 +262,7 @@ void ExperimentalCanvas::SaveLayer( ISize restore_size = rendering_config.inline_pass_context->GetTexture()->GetSize(); - backdrop_filter_contents_ = backdrop_filter_proc( + backdrop_filter_contents = backdrop_filter_proc( FilterInput::Make(rendering_config.inline_pass_context->GetTexture()), transform_stack_.back().transform.Basis(), // When the subpass has a translation that means the math with @@ -335,11 +335,12 @@ void ExperimentalCanvas::SaveLayer( paint_copy.color.alpha *= transform_stack_.back().distributed_opacity; transform_stack_.back().distributed_opacity = 1.0; - // Backdrop Filter must expand bounds to at least the clip stack. + // Backdrop Filter must expand bounds to at least the clip stack, otherwise + // the coverage of the parent render pass. Rect subpass_coverage = bounds->TransformBounds(GetCurrentTransform()); - if (backdrop_filter_contents_) { - subpass_coverage = - clip_coverage_stack_.CurrentClipCoverage().value_or(subpass_coverage); + if (backdrop_filter_contents) { + subpass_coverage = clip_coverage_stack_.CurrentClipCoverage().value_or( + save_layer_state_.back().coverage); } render_passes_.push_back(LazyRenderingConfig( @@ -368,10 +369,10 @@ void ExperimentalCanvas::SaveLayer( // the subpass will affect in the parent pass. clip_coverage_stack_.PushSubpass(subpass_coverage, GetClipHeight()); - if (backdrop_filter_contents_) { + if (backdrop_filter_contents) { // Render the backdrop entity. Entity backdrop_entity; - backdrop_entity.SetContents(std::move(backdrop_filter_contents_)); + backdrop_entity.SetContents(std::move(backdrop_filter_contents)); backdrop_entity.SetTransform( Matrix::MakeTranslation(Vector3(-local_position))); backdrop_entity.SetClipDepth(std::numeric_limits::max()); From 34aef9045d99dc57e5b8246932c3fb335d59cf3d Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Thu, 27 Jun 2024 14:07:22 -0700 Subject: [PATCH 08/17] handle no-op BDFS. --- impeller/aiks/experimental_canvas.cc | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/impeller/aiks/experimental_canvas.cc b/impeller/aiks/experimental_canvas.cc index e5b2de2c54d4e..f0293fe3c9956 100644 --- a/impeller/aiks/experimental_canvas.cc +++ b/impeller/aiks/experimental_canvas.cc @@ -218,7 +218,12 @@ void ExperimentalCanvas::SaveLayer( bounds = Rect::MakeSize(render_target_.GetRenderTargetSize()); } - if (bounds->IsEmpty()) { + // SaveLayer is a no-op, depending on the bounds promise. Should DL elide + // this? + if (bounds->IsEmpty() || + (backdrop_filter && + clip_coverage_stack_.CurrentClipCoverage().has_value() && + clip_coverage_stack_.CurrentClipCoverage()->IsEmpty())) { return; } From b398795abb06476abb8c66d3f7c21c077bd5d1d1 Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Thu, 27 Jun 2024 17:43:11 -0700 Subject: [PATCH 09/17] texture reuse. --- impeller/aiks/experimental_canvas.cc | 78 +++++++++++++++-------- impeller/entity/entity_pass_clip_stack.cc | 8 +++ 2 files changed, 60 insertions(+), 26 deletions(-) diff --git a/impeller/aiks/experimental_canvas.cc b/impeller/aiks/experimental_canvas.cc index f0293fe3c9956..de3199005b09a 100644 --- a/impeller/aiks/experimental_canvas.cc +++ b/impeller/aiks/experimental_canvas.cc @@ -56,7 +56,8 @@ static std::unique_ptr CreateRenderTarget( ContentContext& renderer, ISize size, int mip_count, - const Color& clear_color) { + const Color& clear_color, + const std::shared_ptr& texture) { const std::shared_ptr& context = renderer.GetContext(); /// All of the load/store actions are managed by `InlinePassContext` when @@ -84,8 +85,9 @@ static std::unique_ptr CreateRenderTarget( .load_action = LoadAction::kDontCare, .store_action = StoreAction::kMultisampleResolve, .clear_color = clear_color}, - /*stencil_attachment_config=*/ - kDefaultStencilConfig); + /*stencil_attachment_config=*/kDefaultStencilConfig, // + /*existing_color_msaa_texture=*/nullptr, // + /*existing_color_resolve_texture=*/texture); } else { target = renderer.GetRenderTargetCache()->CreateOffscreen( *context, // context @@ -97,9 +99,9 @@ static std::unique_ptr CreateRenderTarget( .load_action = LoadAction::kDontCare, .store_action = StoreAction::kDontCare, .clear_color = clear_color, - }, // color_attachment_config - kDefaultStencilConfig // stencil_attachment_config - ); + }, // color_attachment_config + kDefaultStencilConfig, // stencil_attachment_config + /*existing_color_texture=*/texture); } return std::make_unique( @@ -173,11 +175,11 @@ void ExperimentalCanvas::SetupRenderPass() { // rendering is completed, we must blit this saveLayer to the onscreen. if (requires_readback_) { auto entity_pass_target = - CreateRenderTarget(renderer_, // - color0.texture->GetSize(), // - /*mip_count=*/1, // - /*clear_color=*/Color::BlackTransparent() // - ); + CreateRenderTarget(renderer_, // + color0.texture->GetSize(), // + /*mip_count=*/1, // + /*clear_color=*/Color::BlackTransparent(), // + /*texture=*/nullptr); render_passes_.push_back( LazyRenderingConfig(renderer_, std::move(entity_pass_target))); } else { @@ -218,15 +220,31 @@ void ExperimentalCanvas::SaveLayer( bounds = Rect::MakeSize(render_target_.GetRenderTargetSize()); } - // SaveLayer is a no-op, depending on the bounds promise. Should DL elide + // SaveLayer is a no-op, depending on the bounds promise. Should/Can DL elide // this? - if (bounds->IsEmpty() || - (backdrop_filter && - clip_coverage_stack_.CurrentClipCoverage().has_value() && - clip_coverage_stack_.CurrentClipCoverage()->IsEmpty())) { + if (bounds->IsEmpty()) { + Save(total_content_depth); return; } + // The maximum coverage of the subpass. Subpasses textures should never + // extend outside the parent pass texture or the current clip coverage. + Rect coverage_limit = Rect::MakeOriginSize( + GetGlobalPassPosition(), + Size(render_passes_.back().inline_pass_context->GetTexture()->GetSize())); + + // BDF No-op. need to do some precomputation to ensure this is fully skipped. + if (backdrop_filter) { + if (!clip_coverage_stack_.HasCoverage() || + clip_coverage_stack_.CurrentClipCoverage()->IsEmpty() || + coverage_limit + .Intersection(clip_coverage_stack_.CurrentClipCoverage().value()) + ->IsEmpty()) { + Save(total_content_depth); + return; + } + } + if (can_distribute_opacity && !backdrop_filter && Paint::CanApplyOpacityPeephole(paint)) { Save(total_content_depth); @@ -234,6 +252,7 @@ void ExperimentalCanvas::SaveLayer( return; } + // Backdrop filter state, ignored if there is no BDF. int required_mip_count = 1; std::shared_ptr backdrop_filter_contents; Point local_position = {0, 0}; @@ -267,8 +286,11 @@ void ExperimentalCanvas::SaveLayer( ISize restore_size = rendering_config.inline_pass_context->GetTexture()->GetSize(); + + auto input_texture = rendering_config.inline_pass_context->GetTexture(); + backdrop_filter_contents = backdrop_filter_proc( - FilterInput::Make(rendering_config.inline_pass_context->GetTexture()), + FilterInput::Make(input_texture), transform_stack_.back().transform.Basis(), // When the subpass has a translation that means the math with // the snapshot has to be different. @@ -288,9 +310,8 @@ void ExperimentalCanvas::SaveLayer( CreateRenderTarget(renderer_, // restore_size, // 1, - Color::BlackTransparent() // - ))); - + Color::BlackTransparent(), // + input_texture))); // Eagerly restore the BDF contents. // If the pass context returns a backdrop texture, we need to draw it to the @@ -344,15 +365,20 @@ void ExperimentalCanvas::SaveLayer( // the coverage of the parent render pass. Rect subpass_coverage = bounds->TransformBounds(GetCurrentTransform()); if (backdrop_filter_contents) { - subpass_coverage = clip_coverage_stack_.CurrentClipCoverage().value_or( - save_layer_state_.back().coverage); + FML_CHECK(clip_coverage_stack_.HasCoverage()); + // We should never hit this case as we check the intersection above. + subpass_coverage = + coverage_limit + .Intersection(clip_coverage_stack_.CurrentClipCoverage().value()) + .value(); } render_passes_.push_back(LazyRenderingConfig( - renderer_, // - CreateRenderTarget(renderer_, // - ISize(subpass_coverage.GetSize()), // - required_mip_count, Color::BlackTransparent() // + renderer_, // + CreateRenderTarget(renderer_, // + ISize(subpass_coverage.GetSize()), // + required_mip_count, Color::BlackTransparent(), // + nullptr // ))); save_layer_state_.push_back(SaveLayerState{paint_copy, subpass_coverage}); diff --git a/impeller/entity/entity_pass_clip_stack.cc b/impeller/entity/entity_pass_clip_stack.cc index eab0565b3d382..9f1db60ce4b59 100644 --- a/impeller/entity/entity_pass_clip_stack.cc +++ b/impeller/entity/entity_pass_clip_stack.cc @@ -3,6 +3,7 @@ // found in the LICENSE file. #include "impeller/entity/entity_pass_clip_stack.h" +#include "fml/logging.h" #include "impeller/entity/contents/clip_contents.h" #include "impeller/entity/entity.h" @@ -21,6 +22,12 @@ EntityPassClipStack::EntityPassClipStack(const Rect& initial_coverage_rect) { } std::optional EntityPassClipStack::CurrentClipCoverage() const { + if (subpass_state_.empty()) { + return std::nullopt; + } + if (subpass_state_.back().clip_coverage.empty()) { + return std::nullopt; + } return subpass_state_.back().clip_coverage.back().coverage; } @@ -41,6 +48,7 @@ void EntityPassClipStack::PushSubpass(std::optional subpass_coverage, void EntityPassClipStack::PopSubpass() { subpass_state_.pop_back(); + FML_CHECK(!subpass_state_.empty()); } const std::vector From 810dcdb7c17c0c57c6c71a49417d17f5fee1be16 Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Thu, 27 Jun 2024 18:41:05 -0700 Subject: [PATCH 10/17] fix texture flip. --- impeller/aiks/experimental_canvas.cc | 52 +++++++++++----------------- 1 file changed, 21 insertions(+), 31 deletions(-) diff --git a/impeller/aiks/experimental_canvas.cc b/impeller/aiks/experimental_canvas.cc index de3199005b09a..017146dbaf1ff 100644 --- a/impeller/aiks/experimental_canvas.cc +++ b/impeller/aiks/experimental_canvas.cc @@ -56,8 +56,7 @@ static std::unique_ptr CreateRenderTarget( ContentContext& renderer, ISize size, int mip_count, - const Color& clear_color, - const std::shared_ptr& texture) { + const Color& clear_color) { const std::shared_ptr& context = renderer.GetContext(); /// All of the load/store actions are managed by `InlinePassContext` when @@ -85,9 +84,7 @@ static std::unique_ptr CreateRenderTarget( .load_action = LoadAction::kDontCare, .store_action = StoreAction::kMultisampleResolve, .clear_color = clear_color}, - /*stencil_attachment_config=*/kDefaultStencilConfig, // - /*existing_color_msaa_texture=*/nullptr, // - /*existing_color_resolve_texture=*/texture); + /*stencil_attachment_config=*/kDefaultStencilConfig); } else { target = renderer.GetRenderTargetCache()->CreateOffscreen( *context, // context @@ -99,9 +96,9 @@ static std::unique_ptr CreateRenderTarget( .load_action = LoadAction::kDontCare, .store_action = StoreAction::kDontCare, .clear_color = clear_color, - }, // color_attachment_config - kDefaultStencilConfig, // stencil_attachment_config - /*existing_color_texture=*/texture); + }, // color_attachment_config + kDefaultStencilConfig // + ); } return std::make_unique( @@ -174,12 +171,12 @@ void ExperimentalCanvas::SetupRenderPass() { // a second save layer with the same dimensions as the onscreen. When // rendering is completed, we must blit this saveLayer to the onscreen. if (requires_readback_) { - auto entity_pass_target = - CreateRenderTarget(renderer_, // - color0.texture->GetSize(), // - /*mip_count=*/1, // - /*clear_color=*/Color::BlackTransparent(), // - /*texture=*/nullptr); + auto entity_pass_target = CreateRenderTarget( + renderer_, // + color0.texture->GetSize(), // + // Note: this is incorrect, we also need to know what kind of filter. + /*mip_count=*/4, // + /*clear_color=*/Color::BlackTransparent()); render_passes_.push_back( LazyRenderingConfig(renderer_, std::move(entity_pass_target))); } else { @@ -253,7 +250,6 @@ void ExperimentalCanvas::SaveLayer( } // Backdrop filter state, ignored if there is no BDF. - int required_mip_count = 1; std::shared_ptr backdrop_filter_contents; Point local_position = {0, 0}; if (backdrop_filter) { @@ -271,7 +267,6 @@ void ExperimentalCanvas::SaveLayer( filter->SetRenderingMode(rendering_mode); return filter; }; - required_mip_count = backdrop_filter->GetRequiredMipCount(); auto rendering_config = std::move(render_passes_.back()); render_passes_.pop_back(); @@ -287,10 +282,12 @@ void ExperimentalCanvas::SaveLayer( ISize restore_size = rendering_config.inline_pass_context->GetTexture()->GetSize(); - auto input_texture = rendering_config.inline_pass_context->GetTexture(); + std::shared_ptr input_texture = + rendering_config.entity_pass_target->Flip( + *renderer_.GetContext()->GetResourceAllocator()); backdrop_filter_contents = backdrop_filter_proc( - FilterInput::Make(input_texture), + FilterInput::Make(std::move(input_texture)), transform_stack_.back().transform.Basis(), // When the subpass has a translation that means the math with // the snapshot has to be different. @@ -305,13 +302,8 @@ void ExperimentalCanvas::SaveLayer( // Create a new render pass that the backdrop filter contents will be // restored to in order to continue rendering. - render_passes_.push_back( - LazyRenderingConfig(renderer_, // - CreateRenderTarget(renderer_, // - restore_size, // - 1, - Color::BlackTransparent(), // - input_texture))); + render_passes_.push_back(LazyRenderingConfig( + renderer_, std::move(rendering_config.entity_pass_target))); // Eagerly restore the BDF contents. // If the pass context returns a backdrop texture, we need to draw it to the @@ -374,12 +366,10 @@ void ExperimentalCanvas::SaveLayer( } render_passes_.push_back(LazyRenderingConfig( - renderer_, // - CreateRenderTarget(renderer_, // - ISize(subpass_coverage.GetSize()), // - required_mip_count, Color::BlackTransparent(), // - nullptr // - ))); + renderer_, // + CreateRenderTarget(renderer_, // + ISize(subpass_coverage.GetSize()), // + 1u, Color::BlackTransparent()))); save_layer_state_.push_back(SaveLayerState{paint_copy, subpass_coverage}); CanvasStackEntry entry; From b1cd4868aedd9deb29b1f6eee49804e0b80e4b76 Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Thu, 27 Jun 2024 21:22:09 -0700 Subject: [PATCH 11/17] re-arrange. --- impeller/aiks/experimental_canvas.cc | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/impeller/aiks/experimental_canvas.cc b/impeller/aiks/experimental_canvas.cc index 017146dbaf1ff..ae1ca651958d5 100644 --- a/impeller/aiks/experimental_canvas.cc +++ b/impeller/aiks/experimental_canvas.cc @@ -232,11 +232,16 @@ void ExperimentalCanvas::SaveLayer( // BDF No-op. need to do some precomputation to ensure this is fully skipped. if (backdrop_filter) { - if (!clip_coverage_stack_.HasCoverage() || - clip_coverage_stack_.CurrentClipCoverage()->IsEmpty() || - coverage_limit - .Intersection(clip_coverage_stack_.CurrentClipCoverage().value()) - ->IsEmpty()) { + if (!clip_coverage_stack_.HasCoverage()) { + Save(total_content_depth); + return; + } + auto clip_coverage = clip_coverage_stack_.CurrentClipCoverage(); + if (!clip_coverage.has_value() || clip_coverage->IsEmpty()) { + Save(total_content_depth); + return; + } + if (coverage_limit.Intersection(clip_coverage.value())->IsEmpty()) { Save(total_content_depth); return; } From 2cab9ec2b99552eda2a7453dda499836e60acf48 Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Thu, 27 Jun 2024 22:18:41 -0700 Subject: [PATCH 12/17] ++ --- impeller/aiks/experimental_canvas.cc | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/impeller/aiks/experimental_canvas.cc b/impeller/aiks/experimental_canvas.cc index ae1ca651958d5..f766999593497 100644 --- a/impeller/aiks/experimental_canvas.cc +++ b/impeller/aiks/experimental_canvas.cc @@ -236,12 +236,14 @@ void ExperimentalCanvas::SaveLayer( Save(total_content_depth); return; } - auto clip_coverage = clip_coverage_stack_.CurrentClipCoverage(); - if (!clip_coverage.has_value() || clip_coverage->IsEmpty()) { + auto maybe_clip_coverage = clip_coverage_stack_.CurrentClipCoverage(); + if (!maybe_clip_coverage.has_value()) { Save(total_content_depth); return; } - if (coverage_limit.Intersection(clip_coverage.value())->IsEmpty()) { + auto clip_coverage = maybe_clip_coverage.value(); + if (clip_coverage.IsEmpty() || + coverage_limit.Intersection(clip_coverage)->IsEmpty()) { Save(total_content_depth); return; } @@ -364,10 +366,12 @@ void ExperimentalCanvas::SaveLayer( if (backdrop_filter_contents) { FML_CHECK(clip_coverage_stack_.HasCoverage()); // We should never hit this case as we check the intersection above. + // NOLINTBEGIN(bugprone-unchecked-optional-access) subpass_coverage = coverage_limit .Intersection(clip_coverage_stack_.CurrentClipCoverage().value()) .value(); + // NOLINTEMD(bugprone-unchecked-optional-access) } render_passes_.push_back(LazyRenderingConfig( From 7deef3f5fe41b72c291079bd5e40683dcb480d69 Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Thu, 27 Jun 2024 23:06:39 -0700 Subject: [PATCH 13/17] fix max basis scale transform. --- impeller/display_list/dl_dispatcher.cc | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/impeller/display_list/dl_dispatcher.cc b/impeller/display_list/dl_dispatcher.cc index aaed5e44f647b..f1b6552b34c97 100644 --- a/impeller/display_list/dl_dispatcher.cc +++ b/impeller/display_list/dl_dispatcher.cc @@ -1313,10 +1313,12 @@ void TextFrameDispatcher::drawTextFrame( if (text_frame->HasColor()) { properties.color = paint_.color; } - renderer_.GetLazyGlyphAtlas()->AddTextFrame(*text_frame, // - matrix_.GetMaxBasisLengthXY(), // - Point(x, y), // - properties // + auto scale = + (matrix_ * Matrix::MakeTranslation(Point(x, y))).GetMaxBasisLengthXY(); + renderer_.GetLazyGlyphAtlas()->AddTextFrame(*text_frame, // + scale, // + Point(x, y), // + properties // ); } From 8f186630dda96464e94efadc3ca5ee550408bd3c Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Fri, 28 Jun 2024 09:06:46 -0700 Subject: [PATCH 14/17] ++ --- impeller/aiks/experimental_canvas.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/impeller/aiks/experimental_canvas.cc b/impeller/aiks/experimental_canvas.cc index f766999593497..0659607cd2b02 100644 --- a/impeller/aiks/experimental_canvas.cc +++ b/impeller/aiks/experimental_canvas.cc @@ -371,7 +371,7 @@ void ExperimentalCanvas::SaveLayer( coverage_limit .Intersection(clip_coverage_stack_.CurrentClipCoverage().value()) .value(); - // NOLINTEMD(bugprone-unchecked-optional-access) + // NOLINTEND(bugprone-unchecked-optional-access) } render_passes_.push_back(LazyRenderingConfig( From 0aaee7654df873146dbcb8584861bf96bd65c07f Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Fri, 28 Jun 2024 11:03:04 -0700 Subject: [PATCH 15/17] ++ --- impeller/aiks/experimental_canvas.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/impeller/aiks/experimental_canvas.cc b/impeller/aiks/experimental_canvas.cc index 0659607cd2b02..7ed3ed1bb38b1 100644 --- a/impeller/aiks/experimental_canvas.cc +++ b/impeller/aiks/experimental_canvas.cc @@ -243,7 +243,7 @@ void ExperimentalCanvas::SaveLayer( } auto clip_coverage = maybe_clip_coverage.value(); if (clip_coverage.IsEmpty() || - coverage_limit.Intersection(clip_coverage)->IsEmpty()) { + !coverage_limit.IntersectsWithRect(clip_coverage)) { Save(total_content_depth); return; } From 9ba9ce5d967f02761ebca19add09a965bef95439 Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Fri, 28 Jun 2024 11:48:11 -0700 Subject: [PATCH 16/17] turn off exp canvas. --- impeller/display_list/dl_playground.cc | 2 +- shell/gpu/gpu_surface_metal_impeller.mm | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/impeller/display_list/dl_playground.cc b/impeller/display_list/dl_playground.cc index 19b7a0bc2b7de..97779e05cefc1 100644 --- a/impeller/display_list/dl_playground.cc +++ b/impeller/display_list/dl_playground.cc @@ -15,7 +15,7 @@ #include "third_party/skia/include/core/SkTypeface.h" #include "txt/platform.h" -#define ENABLE_EXPERIMENTAL_CANVAS true +#define ENABLE_EXPERIMENTAL_CANVAS false namespace impeller { diff --git a/shell/gpu/gpu_surface_metal_impeller.mm b/shell/gpu/gpu_surface_metal_impeller.mm index ac4886c820a4b..67bd3997ef96c 100644 --- a/shell/gpu/gpu_surface_metal_impeller.mm +++ b/shell/gpu/gpu_surface_metal_impeller.mm @@ -17,7 +17,7 @@ static_assert(!__has_feature(objc_arc), "ARC must be disabled."); -#define ENABLE_EXPERIMENTAL_CANVAS true +#define ENABLE_EXPERIMENTAL_CANVAS false namespace flutter { From 3b5e58f4854bb4e70e143edee3d74c4b2f023619 Mon Sep 17 00:00:00 2001 From: Jonah Williams Date: Fri, 28 Jun 2024 12:30:05 -0700 Subject: [PATCH 17/17] Update entity_pass_clip_stack.cc --- impeller/entity/entity_pass_clip_stack.cc | 8 -------- 1 file changed, 8 deletions(-) diff --git a/impeller/entity/entity_pass_clip_stack.cc b/impeller/entity/entity_pass_clip_stack.cc index 9f1db60ce4b59..eab0565b3d382 100644 --- a/impeller/entity/entity_pass_clip_stack.cc +++ b/impeller/entity/entity_pass_clip_stack.cc @@ -3,7 +3,6 @@ // found in the LICENSE file. #include "impeller/entity/entity_pass_clip_stack.h" -#include "fml/logging.h" #include "impeller/entity/contents/clip_contents.h" #include "impeller/entity/entity.h" @@ -22,12 +21,6 @@ EntityPassClipStack::EntityPassClipStack(const Rect& initial_coverage_rect) { } std::optional EntityPassClipStack::CurrentClipCoverage() const { - if (subpass_state_.empty()) { - return std::nullopt; - } - if (subpass_state_.back().clip_coverage.empty()) { - return std::nullopt; - } return subpass_state_.back().clip_coverage.back().coverage; } @@ -48,7 +41,6 @@ void EntityPassClipStack::PushSubpass(std::optional subpass_coverage, void EntityPassClipStack::PopSubpass() { subpass_state_.pop_back(); - FML_CHECK(!subpass_state_.empty()); } const std::vector