diff --git a/common/config.gni b/common/config.gni index 4f8f690811c38..6c2354e7c9128 100644 --- a/common/config.gni +++ b/common/config.gni @@ -37,7 +37,7 @@ declare_args() { slimpeller = false # Opt into new DL dispatcher that skips AIKS layer - experimental_canvas = false + experimental_canvas = true } # feature_defines_list --------------------------------------------------------- diff --git a/impeller/aiks/aiks_playground.cc b/impeller/aiks/aiks_playground.cc index 82f76bf3372a4..882e0d66a99c2 100644 --- a/impeller/aiks/aiks_playground.cc +++ b/impeller/aiks/aiks_playground.cc @@ -75,10 +75,7 @@ bool AiksPlayground::ImGuiBegin(const char* name, bool AiksPlayground::OpenPlaygroundHere( const sk_sp& list) { - DlDispatcher dispatcher; - list->Dispatch(dispatcher); - Picture picture = dispatcher.EndRecordingAsPicture(); - return OpenPlaygroundHere(std::move(picture)); + return OpenPlaygroundHere([list]() { return list; }); } bool AiksPlayground::OpenPlaygroundHere( @@ -91,12 +88,28 @@ bool AiksPlayground::OpenPlaygroundHere( return Playground::OpenPlaygroundHere( [&renderer, &callback](RenderTarget& render_target) -> bool { +#if EXPERIMENTAL_CANVAS + auto display_list = callback(); + TextFrameDispatcher collector(renderer.GetContentContext(), Matrix()); + display_list->Dispatch(collector); + + ExperimentalDlDispatcher impeller_dispatcher( + renderer.GetContentContext(), render_target, + display_list->root_has_backdrop_filter(), + display_list->max_root_blend_mode(), IRect::MakeMaximum()); + display_list->Dispatch(impeller_dispatcher); + impeller_dispatcher.FinishRecording(); + renderer.GetContentContext().GetTransientsBuffer().Reset(); + renderer.GetContentContext().GetLazyGlyphAtlas()->ResetTextFrames(); + return true; +#else auto display_list = callback(); DlDispatcher dispatcher; display_list->Dispatch(dispatcher); Picture picture = dispatcher.EndRecordingAsPicture(); return renderer.Render(picture, render_target, true); +#endif // EXPERIMENTAL_CANVAS }); } diff --git a/impeller/aiks/canvas.cc b/impeller/aiks/canvas.cc index a1a5704736260..714b6d70331bb 100644 --- a/impeller/aiks/canvas.cc +++ b/impeller/aiks/canvas.cc @@ -813,7 +813,8 @@ void Canvas::SaveLayer(const Paint& paint, const std::shared_ptr& backdrop_filter, ContentBoundsPromise bounds_promise, uint32_t total_content_depth, - bool can_distribute_opacity) { + bool can_distribute_opacity, + bool bounds_from_caller) { if (can_distribute_opacity && !backdrop_filter && Paint::CanApplyOpacityPeephole(paint) && bounds_promise != ContentBoundsPromise::kMayClipContents) { diff --git a/impeller/aiks/canvas.h b/impeller/aiks/canvas.h index e5bdc379b0622..834b3d118e1e2 100644 --- a/impeller/aiks/canvas.h +++ b/impeller/aiks/canvas.h @@ -77,7 +77,8 @@ class Canvas { const std::shared_ptr& backdrop_filter = nullptr, ContentBoundsPromise bounds_promise = ContentBoundsPromise::kUnknown, uint32_t total_content_depth = kMaxDepth, - bool can_distribute_opacity = false); + bool can_distribute_opacity = false, + bool bounds_from_caller = false); virtual bool Restore(); diff --git a/impeller/aiks/experimental_canvas.cc b/impeller/aiks/experimental_canvas.cc index 5c028f35d8680..b9cd19a12afcd 100644 --- a/impeller/aiks/experimental_canvas.cc +++ b/impeller/aiks/experimental_canvas.cc @@ -4,6 +4,7 @@ #include "impeller/aiks/experimental_canvas.h" #include "fml/logging.h" +#include "fml/trace_event.h" #include "impeller/aiks/canvas.h" #include "impeller/aiks/paint_pass_delegate.h" #include "impeller/base/validation.h" @@ -82,13 +83,13 @@ static std::shared_ptr FlipBackdrop( // unbalanced save layers. Ideally, this method would return false and the // renderer could handle that by terminating dispatch. render_passes.push_back(LazyRenderingConfig( - renderer, std::move(rendering_config.entity_pass_target))); + renderer, std::move(rendering_config.entity_pass_target), + std::move(rendering_config.inline_pass_context))); return nullptr; } std::shared_ptr input_texture = - rendering_config.entity_pass_target->Flip( - *renderer.GetContext()->GetResourceAllocator()); + rendering_config.inline_pass_context->GetTexture(); if (!input_texture) { VALIDATION_LOG << "Failed to fetch the color texture in order to " @@ -96,12 +97,14 @@ static std::shared_ptr FlipBackdrop( // Note: see above. render_passes.push_back(LazyRenderingConfig( - renderer, std::move(rendering_config.entity_pass_target))); + renderer, std::move(rendering_config.entity_pass_target), + std::move(rendering_config.inline_pass_context))); return nullptr; } render_passes.push_back(LazyRenderingConfig( - renderer, std::move(rendering_config.entity_pass_target))); + renderer, std::move(rendering_config.entity_pass_target), + std::move(rendering_config.inline_pass_context))); // Eagerly restore the BDF contents. // If the pass context returns a backdrop texture, we need to draw it to the @@ -157,7 +160,6 @@ static const constexpr RenderTarget::AttachmentConfig kDefaultStencilConfig = static std::unique_ptr CreateRenderTarget( ContentContext& renderer, ISize size, - int mip_count, const Color& clear_color) { const std::shared_ptr& context = renderer.GetContext(); @@ -166,18 +168,12 @@ static std::unique_ptr CreateRenderTarget( /// What's important is the `StorageMode` of the textures, which cannot be /// changed for the lifetime of the textures. - if (context->GetBackendType() == Context::BackendType::kOpenGLES) { - // TODO(https://github.com/flutter/flutter/issues/141732): Implement mip map - // generation on opengles. - mip_count = 1; - } - RenderTarget target; if (context->GetCapabilities()->SupportsOffscreenMSAA()) { target = renderer.GetRenderTargetCache()->CreateOffscreenMSAA( /*context=*/*context, /*size=*/size, - /*mip_count=*/mip_count, + /*mip_count=*/1, /*label=*/"EntityPass", /*color_attachment_config=*/ RenderTarget::AttachmentConfigMSAA{ @@ -191,7 +187,7 @@ static std::unique_ptr CreateRenderTarget( target = renderer.GetRenderTargetCache()->CreateOffscreen( *context, // context size, // size - /*mip_count=*/mip_count, + /*mip_count=*/1, "EntityPass", // label RenderTarget::AttachmentConfig{ .storage_mode = StorageMode::kDevicePrivate, @@ -273,12 +269,10 @@ 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(), // - // Note: this is incorrect, we also need to know what kind of filter. - /*mip_count=*/4, // - /*clear_color=*/Color::BlackTransparent()); + auto entity_pass_target = + CreateRenderTarget(renderer_, // + color0.texture->GetSize(), // + /*clear_color=*/Color::BlackTransparent()); render_passes_.push_back( LazyRenderingConfig(renderer_, std::move(entity_pass_target))); } else { @@ -312,47 +306,54 @@ void ExperimentalCanvas::SaveLayer( const std::shared_ptr& backdrop_filter, 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()); + bool can_distribute_opacity, + bool bounds_from_caller) { + TRACE_EVENT0("flutter", "Canvas::saveLayer"); + + if (bounds.has_value() && bounds->IsEmpty()) { + Save(total_content_depth); + return; + } + + if (!clip_coverage_stack_.HasCoverage()) { + // The current clip is empty. This means the pass texture won't be + // visible, so skip it. + Save(total_content_depth); + return; } - // SaveLayer is a no-op, depending on the bounds promise. Should/Can DL elide - // this? - if (bounds->IsEmpty()) { + auto maybe_current_clip_coverage = clip_coverage_stack_.CurrentClipCoverage(); + if (!maybe_current_clip_coverage.has_value()) { Save(total_content_depth); return; } + auto current_clip_coverage = maybe_current_clip_coverage.value(); // 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())); + std::optional maybe_coverage_limit = + Rect::MakeOriginSize(GetGlobalPassPosition(), + Size(render_passes_.back() + .inline_pass_context->GetTexture() + ->GetSize())) + .Intersection(current_clip_coverage); + + if (!maybe_coverage_limit.has_value()) { + Save(total_content_depth); + return; + } + maybe_coverage_limit = maybe_coverage_limit->Intersection( + Rect::MakeSize(render_target_.GetRenderTargetSize())); - // BDF No-op. need to do some precomputation to ensure this is fully skipped. - if (backdrop_filter) { - if (!clip_coverage_stack_.HasCoverage()) { - Save(total_content_depth); - return; - } - auto maybe_clip_coverage = clip_coverage_stack_.CurrentClipCoverage(); - if (!maybe_clip_coverage.has_value()) { - Save(total_content_depth); - return; - } - auto clip_coverage = maybe_clip_coverage.value(); - if (clip_coverage.IsEmpty() || - !coverage_limit.IntersectsWithRect(clip_coverage)) { - Save(total_content_depth); - return; - } + if (!maybe_coverage_limit.has_value() || maybe_coverage_limit->IsEmpty()) { + Save(total_content_depth); + return; } + auto coverage_limit = maybe_coverage_limit.value(); if (can_distribute_opacity && !backdrop_filter && - Paint::CanApplyOpacityPeephole(paint)) { + Paint::CanApplyOpacityPeephole(paint) && + bounds_promise != ContentBoundsPromise::kMayClipContents) { Save(total_content_depth); transform_stack_.back().distributed_opacity *= paint.color.alpha; return; @@ -362,11 +363,8 @@ void ExperimentalCanvas::SaveLayer( std::shared_ptr backdrop_filter_contents; Point local_position = {0, 0}; if (backdrop_filter) { - auto current_clip_coverage = clip_coverage_stack_.CurrentClipCoverage(); - if (current_clip_coverage.has_value()) { - local_position = - current_clip_coverage->GetOrigin() - GetGlobalPassPosition(); - } + 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, @@ -401,23 +399,25 @@ void ExperimentalCanvas::SaveLayer( // 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) { - 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(); - // NOLINTEND(bugprone-unchecked-optional-access) + Rect subpass_coverage; + if (backdrop_filter_contents || + Entity::IsBlendModeDestructive(paint.blend_mode) || !bounds.has_value()) { + subpass_coverage = coverage_limit; + // TODO(jonahwilliams): if we have tight bounds we should be able to reduce + // this size here. if (bounds.has_value() && bounds_from_caller) { + // subpass_coverage = + // coverage_limit.Intersection(bounds.value()).value_or(bounds.value()); + // } + } else { + subpass_coverage = bounds->TransformBounds(GetCurrentTransform()); } render_passes_.push_back(LazyRenderingConfig( renderer_, // CreateRenderTarget(renderer_, // ISize(subpass_coverage.GetSize()), // - 1u, Color::BlackTransparent()))); + Color::BlackTransparent() // + ))); save_layer_state_.push_back(SaveLayerState{paint_copy, subpass_coverage}); CanvasStackEntry entry; @@ -491,7 +491,8 @@ bool ExperimentalCanvas::Restore() { PaintPassDelegate(save_layer_state.paint) .CreateContentsForSubpassTarget( lazy_render_pass.inline_pass_context->GetTexture(), - transform_stack_.back().transform); + Matrix::MakeTranslation(Vector3{-GetGlobalPassPosition()}) * + transform_stack_.back().transform); lazy_render_pass.inline_pass_context->EndPass(); @@ -669,20 +670,22 @@ void ExperimentalCanvas::AddRenderEntityToCurrentPass(Entity entity, // conditionally update the backdrop color to its solid color value blended // with the current backdrop. if (render_passes_.back().IsApplyingClearColor()) { - std::optional maybe_color = - entity.AsBackgroundColor(render_passes_.back() - .entity_pass_target->GetRenderTarget() - .GetRenderTargetSize()); + std::optional maybe_color = entity.AsBackgroundColor( + render_passes_.back().inline_pass_context->GetTexture()->GetSize()); if (maybe_color.has_value()) { Color color = maybe_color.value(); - RenderTarget& render_target = - render_passes_.back().entity_pass_target->GetRenderTarget(); + RenderTarget& render_target = render_passes_.back() + .inline_pass_context->GetPassTarget() + .GetRenderTarget(); ColorAttachment attachment = render_target.GetColorAttachments().find(0u)->second; + // Attachment.clear color needs to be premultiplied at all times, but the + // Color::Blend function requires unpremultiplied colors. attachment.clear_color = attachment.clear_color.Unpremultiply() .Blend(color, entity.GetBlendMode()) .Premultiply(); render_target.SetColorAttachment(attachment, 0u); + return; } } @@ -700,8 +703,36 @@ void ExperimentalCanvas::AddRenderEntityToCurrentPass(Entity entity, if (renderer_.GetDeviceCapabilities().SupportsFramebufferFetch()) { ApplyFramebufferBlend(entity); } else { - VALIDATION_LOG << "Emulated advanced blends are currently unsupported."; - return; + // End the active pass and flush the buffer before rendering "advanced" + // blends. Advanced blends work by binding the current render target + // texture as an input ("destination"), blending with a second texture + // input ("source"), writing the result to an intermediate texture, and + // finally copying the data from the intermediate texture back to the + // render target texture. And so all of the commands that have written + // to the render target texture so far need to execute before it's bound + // for blending (otherwise the blend pass will end up executing before + // all the previous commands in the active pass). + auto input_texture = FlipBackdrop(render_passes_, GetGlobalPassPosition(), + clip_coverage_stack_, renderer_); + if (!input_texture) { + return; + } + + // The coverage hint tells the rendered Contents which portion of the + // rendered output will actually be used, and so we set this to the + // current clip coverage (which is the max clip bounds). The contents may + // optionally use this hint to avoid unnecessary rendering work. + auto element_coverage_hint = entity.GetContents()->GetCoverageHint(); + entity.GetContents()->SetCoverageHint(Rect::Intersection( + element_coverage_hint, clip_coverage_stack_.CurrentClipCoverage())); + + FilterInput::Vector inputs = { + FilterInput::Make(input_texture, entity.GetTransform().Invert()), + FilterInput::Make(entity.GetContents())}; + auto contents = + ColorFilterContents::MakeBlend(entity.GetBlendMode(), inputs); + entity.SetContents(std::move(contents)); + entity.SetBlendMode(BlendMode::kSource); } } @@ -831,6 +862,7 @@ bool ExperimentalCanvas::BlitToOnscreen() { void ExperimentalCanvas::EndReplay() { FML_DCHECK(render_passes_.size() == 1u); + render_passes_.back().inline_pass_context->GetRenderPass(0); render_passes_.back().inline_pass_context->EndPass(); // If requires_readback_ was true, then we rendered to an offscreen texture diff --git a/impeller/aiks/experimental_canvas.h b/impeller/aiks/experimental_canvas.h index d1868441b7545..8ec5e18b7c1e2 100644 --- a/impeller/aiks/experimental_canvas.h +++ b/impeller/aiks/experimental_canvas.h @@ -31,6 +31,12 @@ struct LazyRenderingConfig { inline_pass_context = std::make_unique(renderer, *entity_pass_target, 0); } + + LazyRenderingConfig(ContentContext& renderer, + std::unique_ptr entity_pass_target, + std::unique_ptr inline_pass_context) + : entity_pass_target(std::move(entity_pass_target)), + inline_pass_context(std::move(inline_pass_context)) {} }; /// This Canvas attempts to translate from display lists to draw calls directly. @@ -65,7 +71,8 @@ class ExperimentalCanvas : public Canvas { const std::shared_ptr& backdrop_filter, ContentBoundsPromise bounds_promise, uint32_t total_content_depth, - bool can_distribute_opacity) override; + bool can_distribute_opacity, + bool bounds_from_caller) override; bool Restore() override; diff --git a/impeller/display_list/aiks_dl_unittests.cc b/impeller/display_list/aiks_dl_unittests.cc index 1773932497291..911996ebe26c7 100644 --- a/impeller/display_list/aiks_dl_unittests.cc +++ b/impeller/display_list/aiks_dl_unittests.cc @@ -748,6 +748,12 @@ TEST_P(AiksTest, MatrixBackdropFilter) { DlPaint paint; paint.setColor(DlColor::kGreen().withAlpha(0.5 * 255)); paint.setBlendMode(DlBlendMode::kPlus); + + DlPaint rect_paint; + rect_paint.setColor(DlColor::kRed()); + rect_paint.setStrokeWidth(4); + rect_paint.setDrawStyle(DlDrawStyle::kStroke); + builder.DrawRect(SkRect::MakeLTRB(0, 0, 300, 300), rect_paint); builder.DrawCircle(SkPoint::Make(200, 200), 100, paint); // Should render a second circle, centered on the bottom-right-most edge of // the circle. @@ -771,7 +777,7 @@ TEST_P(AiksTest, MatrixSaveLayerFilter) { DlPaint paint; paint.setColor(DlColor::kBlack()); builder.DrawPaint(paint); - builder.SaveLayer({}, nullptr); + builder.SaveLayer(nullptr, nullptr); { paint.setColor(DlColor::kGreen().withAlpha(255 * 0.5)); paint.setBlendMode(DlBlendMode::kPlus); diff --git a/impeller/display_list/dl_dispatcher.cc b/impeller/display_list/dl_dispatcher.cc index d66867ff01e01..08ec303fee366 100644 --- a/impeller/display_list/dl_dispatcher.cc +++ b/impeller/display_list/dl_dispatcher.cc @@ -627,9 +627,18 @@ void DlDispatcherBase::saveLayer(const SkRect& bounds, impeller_bounds = skia_conversions::ToRect(bounds); } + // Empty bounds on a save layer that contains a BDF or destructive blend + // should be treated as unbounded. All other empty bounds can be skipped. + if (impeller_bounds.has_value() && impeller_bounds->IsEmpty() && + (backdrop != nullptr || + Entity::IsBlendModeDestructive(paint.blend_mode))) { + impeller_bounds = std::nullopt; + } + GetCanvas().SaveLayer(paint, impeller_bounds, ToImageFilter(backdrop), promise, total_content_depth, - options.can_distribute_opacity()); + options.can_distribute_opacity(), + options.bounds_from_caller()); } // |flutter::DlOpReceiver| @@ -1125,6 +1134,7 @@ void DlDispatcherBase::drawTextBlob(const sk_sp blob, UNIMPLEMENTED; } +// |flutter::DlOpReceiver| void DlDispatcherBase::drawTextFrame( const std::shared_ptr& text_frame, SkScalar x, @@ -1324,7 +1334,9 @@ void TextFrameDispatcher::drawTextFrame( properties.stroke_width = paint_.stroke_width; } if (text_frame->HasColor()) { - properties.color = paint_.color; + // Alpha is always applied when rendering, remove it here so + // we do not double-apply the alpha. + properties.color = paint_.color.WithAlpha(1.0); } auto scale = (matrix_ * Matrix::MakeTranslation(Point(x, y))).GetMaxBasisLengthXY(); @@ -1340,8 +1352,11 @@ void TextFrameDispatcher::drawDisplayList( SkScalar opacity) { [[maybe_unused]] size_t stack_depth = stack_.size(); save(); + Paint old_paint = paint_; + paint_ = Paint{}; display_list->Dispatch(*this); restore(); + paint_ = old_paint; FML_DCHECK(stack_depth == stack_.size()); } diff --git a/impeller/golden_tests/golden_playground_test_mac.cc b/impeller/golden_tests/golden_playground_test_mac.cc index 4d61cf74cc78f..8893b4e7842b4 100644 --- a/impeller/golden_tests/golden_playground_test_mac.cc +++ b/impeller/golden_tests/golden_playground_test_mac.cc @@ -24,8 +24,6 @@ #define GLFW_INCLUDE_NONE #include "third_party/glfw/include/GLFW/glfw3.h" -#define EXPERIMENTAL_CANVAS false - namespace impeller { namespace { @@ -91,18 +89,18 @@ std::shared_ptr DisplayListToTexture( ); } + SkIRect sk_cull_rect = SkIRect::MakeWH(size.width, size.height); impeller::TextFrameDispatcher collector(context.GetContentContext(), impeller::Matrix()); - display_list->Dispatch( - collector, SkIRect::MakeSize(SkISize::Make(size.width, size.height))); + display_list->Dispatch(collector, sk_cull_rect); impeller::ExperimentalDlDispatcher impeller_dispatcher( context.GetContentContext(), target, display_list->root_has_backdrop_filter(), display_list->max_root_blend_mode(), impeller::IRect::MakeSize(size)); - display_list->Dispatch(impeller_dispatcher, SkIRect::MakeSize(SkISize::Make( - size.width, size.height))); + display_list->Dispatch(impeller_dispatcher, sk_cull_rect); impeller_dispatcher.FinishRecording(); + context.GetContentContext().GetTransientsBuffer().Reset(); context.GetContentContext().GetLazyGlyphAtlas()->ResetTextFrames(); return target.GetRenderTargetTexture(); diff --git a/shell/common/snapshot_controller_impeller.cc b/shell/common/snapshot_controller_impeller.cc index 3f926b5025bcd..68bc9ac46a3c8 100644 --- a/shell/common/snapshot_controller_impeller.cc +++ b/shell/common/snapshot_controller_impeller.cc @@ -48,7 +48,6 @@ sk_sp DoMakeRasterSnapshot( #if EXPERIMENTAL_CANVAS // Do not use the render target cache as the lifecycle of this texture // will outlive a particular frame. - impeller::ISize impeller_size = impeller::ISize(size.width(), size.height()); impeller::RenderTargetAllocator render_target_allocator = impeller::RenderTargetAllocator( context->GetContext()->GetResourceAllocator()); @@ -56,7 +55,7 @@ sk_sp DoMakeRasterSnapshot( if (context->GetContext()->GetCapabilities()->SupportsOffscreenMSAA()) { target = render_target_allocator.CreateOffscreenMSAA( *context->GetContext(), // context - impeller_size, // size + render_target_size, // size /*mip_count=*/1, "Picture Snapshot MSAA", // label impeller::RenderTarget:: @@ -65,7 +64,7 @@ sk_sp DoMakeRasterSnapshot( } else { target = render_target_allocator.CreateOffscreen( *context->GetContext(), // context - impeller_size, // size + render_target_size, // size /*mip_count=*/1, "Picture Snapshot", // label impeller::RenderTarget:: @@ -80,7 +79,7 @@ sk_sp DoMakeRasterSnapshot( context->GetContentContext(), target, display_list->root_has_backdrop_filter(), display_list->max_root_blend_mode(), - impeller::IRect::MakeSize(impeller_size)); + impeller::IRect::MakeSize(render_target_size)); display_list->Dispatch(impeller_dispatcher, SkIRect::MakeSize(size)); impeller_dispatcher.FinishRecording(); diff --git a/shell/gpu/gpu_surface_metal_impeller.mm b/shell/gpu/gpu_surface_metal_impeller.mm index f9cb5dd30b3e2..6c6e4f9e9c17e 100644 --- a/shell/gpu/gpu_surface_metal_impeller.mm +++ b/shell/gpu/gpu_surface_metal_impeller.mm @@ -166,8 +166,9 @@ impeller::IRect cull_rect = surface->coverage(); SkIRect sk_cull_rect = SkIRect::MakeWH(cull_rect.GetWidth(), cull_rect.GetHeight()); + const bool reset_host_buffer = surface_frame.submit_info().frame_boundary; - const impeller::RenderTarget& render_target = surface->GetTargetRenderPassDescriptor(); + impeller::RenderTarget render_target = surface->GetTargetRenderPassDescriptor(); surface->SetFrameBoundary(surface_frame.submit_info().frame_boundary); #if EXPERIMENTAL_CANVAS @@ -181,8 +182,10 @@ cull_rect); display_list->Dispatch(impeller_dispatcher, sk_cull_rect); impeller_dispatcher.FinishRecording(); - aiks_context->GetContentContext().GetTransientsBuffer().Reset(); aiks_context->GetContentContext().GetLazyGlyphAtlas()->ResetTextFrames(); + if (reset_host_buffer) { + aiks_context->GetContentContext().GetTransientsBuffer().Reset(); + } if (!surface->PreparePresent()) { return false; @@ -193,8 +196,6 @@ impeller::DlDispatcher impeller_dispatcher(cull_rect); display_list->Dispatch(impeller_dispatcher, sk_cull_rect); auto picture = impeller_dispatcher.EndRecordingAsPicture(); - const bool reset_host_buffer = surface_frame.submit_info().frame_boundary; - auto result = aiks_context->Render(picture, render_target, reset_host_buffer); if (!surface->PreparePresent()) { @@ -304,7 +305,7 @@ impeller::TextFrameDispatcher collector(aiks_context->GetContentContext(), impeller::Matrix()); display_list->Dispatch(collector, sk_cull_rect); - const impeller::RenderTarget& render_target = surface->GetTargetRenderPassDescriptor(); + impeller::RenderTarget render_target = surface->GetTargetRenderPassDescriptor(); impeller::ExperimentalDlDispatcher impeller_dispatcher( aiks_context->GetContentContext(), render_target, display_list->root_has_backdrop_filter(), display_list->max_root_blend_mode(), diff --git a/shell/gpu/gpu_surface_vulkan_impeller.cc b/shell/gpu/gpu_surface_vulkan_impeller.cc index 33cf1dd35e4ec..02a9a4dfd5908 100644 --- a/shell/gpu/gpu_surface_vulkan_impeller.cc +++ b/shell/gpu/gpu_surface_vulkan_impeller.cc @@ -62,7 +62,7 @@ std::unique_ptr GPUSurfaceVulkanImpeller::AcquireFrame( auto cull_rect = surface->GetTargetRenderPassDescriptor().GetRenderTargetSize(); - const impeller::RenderTarget& render_target = + impeller::RenderTarget render_target = surface->GetTargetRenderPassDescriptor(); SurfaceFrame::EncodeCallback encode_callback = [aiks_context = @@ -80,6 +80,7 @@ std::unique_ptr GPUSurfaceVulkanImpeller::AcquireFrame( return false; } + const bool reset_host_buffer = surface_frame.submit_info().frame_boundary; #if EXPERIMENTAL_CANVAS impeller::TextFrameDispatcher collector(aiks_context->GetContentContext(), impeller::Matrix()); @@ -95,6 +96,9 @@ std::unique_ptr GPUSurfaceVulkanImpeller::AcquireFrame( impeller_dispatcher.FinishRecording(); aiks_context->GetContentContext().GetTransientsBuffer().Reset(); aiks_context->GetContentContext().GetLazyGlyphAtlas()->ResetTextFrames(); + if (reset_host_buffer) { + aiks_context->GetContentContext().GetTransientsBuffer().Reset(); + } return true; #else impeller::Rect dl_cull_rect = impeller::Rect::MakeSize(cull_rect); @@ -102,7 +106,6 @@ std::unique_ptr GPUSurfaceVulkanImpeller::AcquireFrame( display_list->Dispatch(impeller_dispatcher, SkIRect::MakeWH(cull_rect.width, cull_rect.height)); auto picture = impeller_dispatcher.EndRecordingAsPicture(); - const bool reset_host_buffer = surface_frame.submit_info().frame_boundary; return aiks_context->Render(picture, render_target, reset_host_buffer); #endif };