From c453bac49b1caaeafd970ea0609bf0241b9d18a9 Mon Sep 17 00:00:00 2001 From: Jonah Williams Date: Wed, 22 Nov 2023 11:16:11 -0800 Subject: [PATCH] [Impeller] cache render target properties on Render Pass. (flutter/engine#48323) Otherwise we do three hashmap lookups everything we call OptionsFromPass(AndEntity) in a contents. ## Before 16 / 392 = 4% ![image](https://github.com/flutter/engine/assets/8975114/cf02778c-22da-4849-a98a-75bac7536284) ## After 6/ 458 = 1.3% ![image](https://github.com/flutter/engine/assets/8975114/13b58267-a25a-483d-a632-55f505070996) --- .../impeller/entity/contents/contents.cc | 8 +++---- .../flutter/impeller/renderer/render_pass.cc | 18 ++++++++++++++- .../flutter/impeller/renderer/render_pass.h | 22 +++++++++++++++++++ .../impeller/renderer/renderer_unittests.cc | 19 ++++++++++++++++ 4 files changed, 61 insertions(+), 6 deletions(-) diff --git a/engine/src/flutter/impeller/entity/contents/contents.cc b/engine/src/flutter/impeller/entity/contents/contents.cc index ba9b0efa10b..06178fb6010 100644 --- a/engine/src/flutter/impeller/entity/contents/contents.cc +++ b/engine/src/flutter/impeller/entity/contents/contents.cc @@ -19,11 +19,9 @@ namespace impeller { ContentContextOptions OptionsFromPass(const RenderPass& pass) { ContentContextOptions opts; - opts.sample_count = pass.GetRenderTarget().GetSampleCount(); - opts.color_attachment_pixel_format = - pass.GetRenderTarget().GetRenderTargetPixelFormat(); - opts.has_stencil_attachment = - pass.GetRenderTarget().GetStencilAttachment().has_value(); + opts.sample_count = pass.GetSampleCount(); + opts.color_attachment_pixel_format = pass.GetRenderTargetPixelFormat(); + opts.has_stencil_attachment = pass.HasStencilAttachment(); return opts; } diff --git a/engine/src/flutter/impeller/renderer/render_pass.cc b/engine/src/flutter/impeller/renderer/render_pass.cc index b5b19f1f0b2..8cc60b93eac 100644 --- a/engine/src/flutter/impeller/renderer/render_pass.cc +++ b/engine/src/flutter/impeller/renderer/render_pass.cc @@ -9,6 +9,10 @@ namespace impeller { RenderPass::RenderPass(std::weak_ptr context, const RenderTarget& target) : context_(std::move(context)), + sample_count_(target.GetSampleCount()), + pixel_format_(target.GetRenderTargetPixelFormat()), + has_stencil_attachment_(target.GetStencilAttachment().has_value()), + render_target_size_(target.GetRenderTargetSize()), render_target_(target), transients_buffer_() { auto strong_context = context_.lock(); @@ -23,12 +27,24 @@ RenderPass::~RenderPass() { } } +SampleCount RenderPass::GetSampleCount() const { + return sample_count_; +} + +PixelFormat RenderPass::GetRenderTargetPixelFormat() const { + return pixel_format_; +} + +bool RenderPass::HasStencilAttachment() const { + return has_stencil_attachment_; +} + const RenderTarget& RenderPass::GetRenderTarget() const { return render_target_; } ISize RenderPass::GetRenderTargetSize() const { - return render_target_.GetRenderTargetSize(); + return render_target_size_; } HostBuffer& RenderPass::GetTransientsBuffer() { diff --git a/engine/src/flutter/impeller/renderer/render_pass.h b/engine/src/flutter/impeller/renderer/render_pass.h index f9e9629e3d9..658eb071636 100644 --- a/engine/src/flutter/impeller/renderer/render_pass.h +++ b/engine/src/flutter/impeller/renderer/render_pass.h @@ -6,6 +6,7 @@ #include +#include "impeller/core/formats.h" #include "impeller/renderer/command.h" #include "impeller/renderer/command_buffer.h" #include "impeller/renderer/render_target.h" @@ -71,8 +72,29 @@ class RenderPass { /// const std::vector& GetCommands() const { return commands_; } + //---------------------------------------------------------------------------- + /// @brief The sample count of the attached render target. + SampleCount GetSampleCount() const; + + //---------------------------------------------------------------------------- + /// @brief The pixel format of the attached render target. + PixelFormat GetRenderTargetPixelFormat() const; + + //---------------------------------------------------------------------------- + /// @brief Whether the render target has an stencil attachment. + bool HasStencilAttachment() const; + protected: const std::weak_ptr context_; + // The following properties: sample_count, pixel_format, + // has_stencil_attachment, and render_target_size are cached on the + // RenderTarget to speed up numerous lookups during rendering. This is safe as + // the RenderTarget itself is copied into the RenderTarget and only exposed as + // a const reference. + const SampleCount sample_count_; + const PixelFormat pixel_format_; + const bool has_stencil_attachment_; + const ISize render_target_size_; const RenderTarget render_target_; std::shared_ptr transients_buffer_; std::vector commands_; diff --git a/engine/src/flutter/impeller/renderer/renderer_unittests.cc b/engine/src/flutter/impeller/renderer/renderer_unittests.cc index aa7eb82036d..9ca1ed2caeb 100644 --- a/engine/src/flutter/impeller/renderer/renderer_unittests.cc +++ b/engine/src/flutter/impeller/renderer/renderer_unittests.cc @@ -1273,6 +1273,25 @@ TEST_P(RendererTest, CanPreAllocateCommands) { EXPECT_EQ(render_pass->GetCommands().capacity(), 100u); } +TEST_P(RendererTest, CanLookupRenderTargetProperties) { + auto context = GetContext(); + auto cmd_buffer = context->CreateCommandBuffer(); + auto render_target_cache = std::make_shared( + GetContext()->GetResourceAllocator()); + + auto render_target = + RenderTarget::CreateOffscreen(*context, *render_target_cache, {100, 100}); + auto render_pass = cmd_buffer->CreateRenderPass(render_target); + + EXPECT_EQ(render_pass->GetSampleCount(), render_target.GetSampleCount()); + EXPECT_EQ(render_pass->GetRenderTargetPixelFormat(), + render_target.GetRenderTargetPixelFormat()); + EXPECT_EQ(render_pass->HasStencilAttachment(), + render_target.GetStencilAttachment().has_value()); + EXPECT_EQ(render_pass->GetRenderTargetSize(), + render_target.GetRenderTargetSize()); +} + } // namespace testing } // namespace impeller