From d1800ba088709aa0ca08c377c7da34a73955cc26 Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Thu, 17 Oct 2024 19:15:58 -0700 Subject: [PATCH 1/2] [Impeller] allocate the impeller onscreen texture from the render target cache. --- impeller/display_list/canvas.cc | 59 +++++++++++------------- impeller/display_list/canvas.h | 2 +- impeller/entity/entity_pass_target.cc | 7 ++- impeller/entity/entity_pass_target.h | 3 +- impeller/entity/inline_pass_context.cc | 64 ++++++-------------------- impeller/entity/inline_pass_context.h | 16 ++----- 6 files changed, 53 insertions(+), 98 deletions(-) diff --git a/impeller/display_list/canvas.cc b/impeller/display_list/canvas.cc index dedb9c31cf27c..2deb03da9775e 100644 --- a/impeller/display_list/canvas.cc +++ b/impeller/display_list/canvas.cc @@ -98,7 +98,7 @@ static std::shared_ptr FlipBackdrop( Point global_pass_position, EntityPassClipStack& clip_coverage_stack, ContentContext& renderer) { - auto rendering_config = std::move(render_passes.back()); + LazyRenderingConfig 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 @@ -112,7 +112,7 @@ static std::shared_ptr FlipBackdrop( // In cases where there are no contents, we // could instead check the clear color and initialize a 1x2 CPU texture // instead of ending the pass. - rendering_config.inline_pass_context->GetRenderPass(0); + rendering_config.inline_pass_context->GetRenderPass(); if (!rendering_config.inline_pass_context->EndPass()) { VALIDATION_LOG << "Failed to end the current render pass in order to read from " @@ -127,7 +127,7 @@ static std::shared_ptr FlipBackdrop( return nullptr; } - std::shared_ptr input_texture = + const std::shared_ptr& input_texture = rendering_config.inline_pass_context->GetTexture(); if (!input_texture) { @@ -164,7 +164,7 @@ static std::shared_ptr FlipBackdrop( msaa_backdrop_entity.SetClipDepth(std::numeric_limits::max()); if (!msaa_backdrop_entity.Render( renderer, - *render_passes.back().inline_pass_context->GetRenderPass(0).pass)) { + *render_passes.back().inline_pass_context->GetRenderPass())) { VALIDATION_LOG << "Failed to render MSAA backdrop entity."; return nullptr; } @@ -173,13 +173,12 @@ static std::shared_ptr FlipBackdrop( // applied. auto& replay_entities = clip_coverage_stack.GetReplayEntities(); for (const auto& replay : replay_entities) { - SetClipScissor( - replay.clip_coverage, - *render_passes.back().inline_pass_context->GetRenderPass(0).pass, - global_pass_position); + SetClipScissor(replay.clip_coverage, + *render_passes.back().inline_pass_context->GetRenderPass(), + global_pass_position); if (!replay.entity.Render( renderer, - *render_passes.back().inline_pass_context->GetRenderPass(0).pass)) { + *render_passes.back().inline_pass_context->GetRenderPass())) { VALIDATION_LOG << "Failed to render entity for clip restore."; } } @@ -1128,8 +1127,7 @@ void Canvas::SaveLayer(const Paint& paint, backdrop_entity.SetClipDepth(std::numeric_limits::max()); backdrop_entity.Render( - renderer_, - *render_passes_.back().inline_pass_context->GetRenderPass(0).pass); + renderer_, *render_passes_.back().inline_pass_context->GetRenderPass()); } } @@ -1168,7 +1166,7 @@ bool Canvas::Restore() { 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); + lazy_render_pass.inline_pass_context->GetRenderPass(); SaveLayerState save_layer_state = save_layer_state_.back(); save_layer_state_.pop_back(); @@ -1242,8 +1240,8 @@ bool Canvas::Restore() { } element_entity.Render( - renderer_, // - *render_passes_.back().inline_pass_context->GetRenderPass(0).pass // + renderer_, // + *render_passes_.back().inline_pass_context->GetRenderPass() // ); clip_coverage_stack_.PopSubpass(); transform_stack_.pop_back(); @@ -1290,9 +1288,9 @@ bool Canvas::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().inline_pass_context->GetRenderPass(0).pass, // - GetGlobalPassPosition() // + clip_coverage_stack_.CurrentClipCoverage(), // + *render_passes_.back().inline_pass_context->GetRenderPass(), // + GetGlobalPassPosition() // ); } @@ -1300,9 +1298,8 @@ bool Canvas::Restore() { return true; } - entity.Render( - renderer_, - *render_passes_.back().inline_pass_context->GetRenderPass(0).pass); + entity.Render(renderer_, + *render_passes_.back().inline_pass_context->GetRenderPass()); } return true; @@ -1509,16 +1506,16 @@ void Canvas::AddRenderEntityToCurrentPass(Entity& entity, bool reuse_depth) { } } - InlinePassContext::RenderPassResult result = - render_passes_.back().inline_pass_context->GetRenderPass(0); - if (!result.pass) { + const std::shared_ptr& result = + render_passes_.back().inline_pass_context->GetRenderPass(); + if (!result) { // 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); + entity.Render(renderer_, *result); } void Canvas::AddClipEntityToCurrentPass(Entity& entity) { @@ -1564,19 +1561,17 @@ void Canvas::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().inline_pass_context->GetRenderPass(0).pass, - GetGlobalPassPosition()); + SetClipScissor(clip_coverage_stack_.CurrentClipCoverage(), + *render_passes_.back().inline_pass_context->GetRenderPass(), + GetGlobalPassPosition()); } if (!clip_state_result.should_render) { return; } - entity.Render( - renderer_, - *render_passes_.back().inline_pass_context->GetRenderPass(0).pass); + entity.Render(renderer_, + *render_passes_.back().inline_pass_context->GetRenderPass()); } bool Canvas::BlitToOnscreen() { @@ -1640,7 +1635,7 @@ bool Canvas::BlitToOnscreen() { void Canvas::EndReplay() { FML_DCHECK(render_passes_.size() == 1u); - render_passes_.back().inline_pass_context->GetRenderPass(0); + render_passes_.back().inline_pass_context->GetRenderPass(); render_passes_.back().inline_pass_context->EndPass(); // If requires_readback_ was true, then we rendered to an offscreen texture diff --git a/impeller/display_list/canvas.h b/impeller/display_list/canvas.h index 387cb5c81dc33..3e43caed8e381 100644 --- a/impeller/display_list/canvas.h +++ b/impeller/display_list/canvas.h @@ -88,7 +88,7 @@ struct LazyRenderingConfig { 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); + std::make_unique(renderer, *entity_pass_target); } LazyRenderingConfig(ContentContext& renderer, diff --git a/impeller/entity/entity_pass_target.cc b/impeller/entity/entity_pass_target.cc index c92a84a76a718..913fc03f7c2ed 100644 --- a/impeller/entity/entity_pass_target.cc +++ b/impeller/entity/entity_pass_target.cc @@ -17,7 +17,8 @@ EntityPassTarget::EntityPassTarget(const RenderTarget& render_target, supports_read_from_resolve_(supports_read_from_resolve), supports_implicit_msaa_(supports_implicit_msaa) {} -std::shared_ptr EntityPassTarget::Flip(Allocator& allocator) { +std::shared_ptr EntityPassTarget::Flip( + const ContentContext& renderer) { auto color0 = target_.GetColorAttachments().find(0)->second; if (!color0.resolve_texture) { VALIDATION_LOG << "EntityPassTarget Flip should never be called for a " @@ -40,7 +41,9 @@ std::shared_ptr EntityPassTarget::Flip(Allocator& allocator) { // The second texture is allocated lazily to avoid unused allocations. TextureDescriptor new_descriptor = color0.resolve_texture->GetTextureDescriptor(); - secondary_color_texture_ = allocator.CreateTexture(new_descriptor); + RenderTarget target = renderer.GetRenderTargetCache()->CreateOffscreenMSAA( + *renderer.GetContext(), new_descriptor.size, 1); + secondary_color_texture_ = target.GetRenderTargetTexture(); if (!secondary_color_texture_) { return nullptr; diff --git a/impeller/entity/entity_pass_target.h b/impeller/entity/entity_pass_target.h index e82bad573874a..7f4d1123433ae 100644 --- a/impeller/entity/entity_pass_target.h +++ b/impeller/entity/entity_pass_target.h @@ -5,6 +5,7 @@ #ifndef FLUTTER_IMPELLER_ENTITY_ENTITY_PASS_TARGET_H_ #define FLUTTER_IMPELLER_ENTITY_ENTITY_PASS_TARGET_H_ +#include "impeller/entity/contents/content_context.h" #include "impeller/renderer/render_target.h" namespace impeller { @@ -24,7 +25,7 @@ class EntityPassTarget { /// result of `GetRenderTarget` is guaranteed to be able to read the /// previous pass's backdrop texture (which is returned by this /// method). - std::shared_ptr Flip(Allocator& allocator); + std::shared_ptr Flip(const ContentContext& renderer); RenderTarget& GetRenderTarget(); diff --git a/impeller/entity/inline_pass_context.cc b/impeller/entity/inline_pass_context.cc index 1a1e2a92d88e5..147f292b83a28 100644 --- a/impeller/entity/inline_pass_context.cc +++ b/impeller/entity/inline_pass_context.cc @@ -7,29 +7,19 @@ #include #include "flutter/fml/status.h" -#include "impeller/base/allocation.h" #include "impeller/base/validation.h" #include "impeller/core/formats.h" #include "impeller/entity/contents/content_context.h" #include "impeller/entity/entity_pass_target.h" #include "impeller/renderer/command_buffer.h" +#include "impeller/renderer/render_pass.h" #include "impeller/renderer/texture_mipmap.h" namespace impeller { -InlinePassContext::InlinePassContext( - const ContentContext& renderer, - EntityPassTarget& pass_target, - uint32_t entity_count, - std::optional collapsed_parent_pass) - : renderer_(renderer), - pass_target_(pass_target), - entity_count_(entity_count), - is_collapsed_(collapsed_parent_pass.has_value()) { - if (collapsed_parent_pass.has_value()) { - pass_ = collapsed_parent_pass.value().pass; - } -} +InlinePassContext::InlinePassContext(const ContentContext& renderer, + EntityPassTarget& pass_target) + : renderer_(renderer), pass_target_(pass_target) {} InlinePassContext::~InlinePassContext() { if (!is_collapsed_) { @@ -90,10 +80,9 @@ EntityPassTarget& InlinePassContext::GetPassTarget() const { return pass_target_; } -InlinePassContext::RenderPassResult InlinePassContext::GetRenderPass( - uint32_t pass_depth) { +const std::shared_ptr& InlinePassContext::GetRenderPass() { if (IsActive()) { - return {.pass = pass_}; + return pass_; } /// Create a new render pass if one isn't active. This path will run the first @@ -103,20 +92,17 @@ InlinePassContext::RenderPassResult InlinePassContext::GetRenderPass( command_buffer_ = renderer_.GetContext()->CreateCommandBuffer(); if (!command_buffer_) { VALIDATION_LOG << "Could not create command buffer."; - return {}; + return pass_; } if (pass_target_.GetRenderTarget().GetColorAttachments().empty()) { VALIDATION_LOG << "Color attachment unexpectedly missing from the " "EntityPass render target."; - return {}; + return pass_; } - command_buffer_->SetLabel( - "EntityPass Command Buffer: Depth=" + std::to_string(pass_depth) + - " Count=" + std::to_string(pass_count_)); + command_buffer_->SetLabel("EntityPass Command Buffer"); - RenderPassResult result; { // If the pass target has a resolve texture, then we're using MSAA. bool is_msaa = pass_target_.GetRenderTarget() @@ -124,11 +110,7 @@ InlinePassContext::RenderPassResult InlinePassContext::GetRenderPass( .find(0) ->second.resolve_texture != nullptr; if (pass_count_ > 0 && is_msaa) { - result.backdrop_texture = - pass_target_.Flip(*renderer_.GetContext()->GetResourceAllocator()); - if (!result.backdrop_texture) { - VALIDATION_LOG << "Could not flip the EntityPass render target."; - } + pass_target_.Flip(renderer_); } } @@ -154,7 +136,7 @@ InlinePassContext::RenderPassResult InlinePassContext::GetRenderPass( if (!depth.has_value()) { VALIDATION_LOG << "Depth attachment unexpectedly missing from the " "EntityPass render target."; - return {}; + return pass_; } depth->load_action = LoadAction::kClear; depth->store_action = StoreAction::kDontCare; @@ -164,7 +146,7 @@ InlinePassContext::RenderPassResult InlinePassContext::GetRenderPass( if (!depth.has_value() || !stencil.has_value()) { VALIDATION_LOG << "Stencil/Depth attachment unexpectedly missing from the " "EntityPass render target."; - return {}; + return pass_; } stencil->load_action = LoadAction::kClear; stencil->store_action = StoreAction::kDontCare; @@ -177,28 +159,12 @@ InlinePassContext::RenderPassResult InlinePassContext::GetRenderPass( pass_ = command_buffer_->CreateRenderPass(pass_target_.GetRenderTarget()); if (!pass_) { VALIDATION_LOG << "Could not create render pass."; - return {}; - } - // Commands are fairly large (500B) objects, so re-allocation of the command - // buffer while encoding can add a surprising amount of overhead. We make a - // conservative npot estimate to avoid this case. - pass_->ReserveCommands(Allocation::NextPowerOfTwoSize(entity_count_)); - pass_->SetLabel( - "EntityPass Render Pass: Depth=" + std::to_string(pass_depth) + - " Count=" + std::to_string(pass_count_)); - - result.pass = pass_; - result.just_created = true; - - if (!renderer_.GetContext()->GetCapabilities()->SupportsReadFromResolve() && - result.backdrop_texture == - result.pass->GetRenderTarget().GetRenderTargetTexture()) { - VALIDATION_LOG << "EntityPass backdrop restore configuration is not valid " - "for the current graphics backend."; + return pass_; } + pass_->SetLabel("EntityPass Render Pass: Depth="); ++pass_count_; - return result; + return pass_; } uint32_t InlinePassContext::GetPassCount() const { diff --git a/impeller/entity/inline_pass_context.h b/impeller/entity/inline_pass_context.h index a1cc84645a558..3bed2de7e89f5 100644 --- a/impeller/entity/inline_pass_context.h +++ b/impeller/entity/inline_pass_context.h @@ -16,17 +16,8 @@ namespace impeller { class InlinePassContext { public: - struct RenderPassResult { - bool just_created = false; - std::shared_ptr pass; - std::shared_ptr backdrop_texture; - }; - - InlinePassContext( - const ContentContext& renderer, - EntityPassTarget& pass_target, - uint32_t entity_count, - std::optional collapsed_parent_pass = std::nullopt); + InlinePassContext(const ContentContext& renderer, + EntityPassTarget& pass_target); ~InlinePassContext(); @@ -42,7 +33,7 @@ class InlinePassContext { uint32_t GetPassCount() const; - RenderPassResult GetRenderPass(uint32_t pass_depth); + const std::shared_ptr& GetRenderPass(); private: const ContentContext& renderer_; @@ -50,7 +41,6 @@ class InlinePassContext { std::shared_ptr command_buffer_; std::shared_ptr pass_; uint32_t pass_count_ = 0; - uint32_t entity_count_ = 0; // Whether this context is collapsed into a parent entity pass. bool is_collapsed_ = false; From a6b6b323e0e58b308573637906d9227c0453b7d6 Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Fri, 18 Oct 2024 14:13:35 -0700 Subject: [PATCH 2/2] add null checks. --- impeller/entity/entity_pass_target_unittests.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/impeller/entity/entity_pass_target_unittests.cc b/impeller/entity/entity_pass_target_unittests.cc index ad11d32d106aa..cd22acbffdb5a 100644 --- a/impeller/entity/entity_pass_target_unittests.cc +++ b/impeller/entity/entity_pass_target_unittests.cc @@ -38,6 +38,7 @@ TEST_P(EntityPassTargetTest, SwapWithMSAATexture) { auto msaa_tex = color0.texture; auto resolve_tex = color0.resolve_texture; + FML_DCHECK(content_context); entity_pass_target.Flip(*content_context); color0 = entity_pass_target.GetRenderTarget() @@ -97,6 +98,7 @@ TEST_P(EntityPassTargetTest, SwapWithMSAAImplicitResolve) { ASSERT_EQ(msaa_tex, resolve_tex); + FML_DCHECK(content_context); entity_pass_target.Flip(*content_context); color0 = entity_pass_target.GetRenderTarget()