Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit 0c2de1e

Browse files
author
Jonah Williams
authored
[Impeller] preallocate command buffer to next power of two of entity list. (#48185)
Commands are massive 500 byte objects, re-allocating this vector while recording them can actually add a substantial amount of overhead to applications with lots of drawing commands. Sizing to npot so that underestimating by a few commands doesn't force us to immediately copy all command objects. This is still a herustic driven approach. An alternative exact approach would have entities/contents describe how many commands they would add. This may be more important for stencil then cover (depending on how we do it) since some contents would need to create two commands.
1 parent 746697c commit 0c2de1e

File tree

6 files changed

+43
-7
lines changed

6 files changed

+43
-7
lines changed

impeller/entity/entity_pass.cc

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -835,8 +835,9 @@ bool EntityPass::OnRender(
835835
TRACE_EVENT0("impeller", "EntityPass::OnRender");
836836

837837
auto context = renderer.GetContext();
838-
InlinePassContext pass_context(
839-
context, pass_target, GetTotalPassReads(renderer), collapsed_parent_pass);
838+
InlinePassContext pass_context(context, pass_target,
839+
GetTotalPassReads(renderer), GetElementCount(),
840+
collapsed_parent_pass);
840841
if (!pass_context.IsValid()) {
841842
VALIDATION_LOG << SPrintF("Pass context invalid (Depth=%d)", pass_depth);
842843
return false;

impeller/entity/inline_pass_context.cc

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,11 @@ InlinePassContext::InlinePassContext(
1818
std::shared_ptr<Context> context,
1919
EntityPassTarget& pass_target,
2020
uint32_t pass_texture_reads,
21+
uint32_t entity_count,
2122
std::optional<RenderPassResult> collapsed_parent_pass)
2223
: context_(std::move(context)),
2324
pass_target_(pass_target),
25+
entity_count_(entity_count),
2426
is_collapsed_(collapsed_parent_pass.has_value()) {
2527
if (collapsed_parent_pass.has_value()) {
2628
pass_ = collapsed_parent_pass.value().pass;
@@ -149,7 +151,10 @@ InlinePassContext::RenderPassResult InlinePassContext::GetRenderPass(
149151
VALIDATION_LOG << "Could not create render pass.";
150152
return {};
151153
}
152-
154+
// Commands are fairly large (500B) objects, so re-allocation of the command
155+
// buffer while encoding can add a surprising amount of overhead. We make a
156+
// conservative npot estimate to avoid this case.
157+
pass_->ReserveCommands(Allocation::NextPowerOfTwoSize(entity_count_));
153158
pass_->SetLabel(
154159
"EntityPass Render Pass: Depth=" + std::to_string(pass_depth) +
155160
" Count=" + std::to_string(pass_count_));

impeller/entity/inline_pass_context.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,14 +24,21 @@ class InlinePassContext {
2424
std::shared_ptr<Context> context,
2525
EntityPassTarget& pass_target,
2626
uint32_t pass_texture_reads,
27+
uint32_t entity_count,
2728
std::optional<RenderPassResult> collapsed_parent_pass = std::nullopt);
29+
2830
~InlinePassContext();
2931

3032
bool IsValid() const;
33+
3134
bool IsActive() const;
35+
3236
std::shared_ptr<Texture> GetTexture();
37+
3338
bool EndPass();
39+
3440
EntityPassTarget& GetPassTarget() const;
41+
3542
uint32_t GetPassCount() const;
3643

3744
RenderPassResult GetRenderPass(uint32_t pass_depth);
@@ -42,6 +49,7 @@ class InlinePassContext {
4249
std::shared_ptr<CommandBuffer> command_buffer_;
4350
std::shared_ptr<RenderPass> pass_;
4451
uint32_t pass_count_ = 0;
52+
uint32_t entity_count_ = 0;
4553

4654
// Whether this context is collapsed into a parent entity pass.
4755
bool is_collapsed_ = false;

impeller/renderer/command.h

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -92,10 +92,9 @@ struct Bindings {
9292
/// * Specify any stage bindings.
9393
/// * (Optional) Specify a debug label.
9494
///
95-
/// Command are very lightweight objects and can be created
96-
/// frequently and on demand. The resources referenced in commands
97-
/// views into buffers managed by other allocators and resource
98-
/// managers.
95+
/// Command can be created frequently and on demand. The resources
96+
/// referenced in commands views into buffers managed by other
97+
/// allocators and resource managers.
9998
///
10099
struct Command : public ResourceBinder {
101100
//----------------------------------------------------------------------------

impeller/renderer/render_pass.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,13 @@ class RenderPass {
3636

3737
void SetLabel(std::string label);
3838

39+
/// @brief Reserve [command_count] commands in the HAL command buffer.
40+
///
41+
/// Note: this is not the native command buffer.
42+
void ReserveCommands(size_t command_count) {
43+
commands_.reserve(command_count);
44+
}
45+
3946
HostBuffer& GetTransientsBuffer();
4047

4148
//----------------------------------------------------------------------------

impeller/renderer/renderer_unittests.cc

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
#include "impeller/renderer/command_buffer.h"
3434
#include "impeller/renderer/pipeline_builder.h"
3535
#include "impeller/renderer/pipeline_library.h"
36+
#include "impeller/renderer/render_target.h"
3637
#include "impeller/renderer/renderer.h"
3738
#include "impeller/renderer/sampler_library.h"
3839
#include "impeller/renderer/surface.h"
@@ -1257,6 +1258,21 @@ TEST_P(RendererTest, StencilMask) {
12571258
OpenPlaygroundHere(callback);
12581259
}
12591260

1261+
TEST_P(RendererTest, CanPreAllocateCommands) {
1262+
auto context = GetContext();
1263+
auto cmd_buffer = context->CreateCommandBuffer();
1264+
auto render_target_cache = std::make_shared<RenderTargetAllocator>(
1265+
GetContext()->GetResourceAllocator());
1266+
1267+
auto render_target =
1268+
RenderTarget::CreateOffscreen(*context, *render_target_cache, {100, 100});
1269+
auto render_pass = cmd_buffer->CreateRenderPass(render_target);
1270+
1271+
render_pass->ReserveCommands(100u);
1272+
1273+
EXPECT_EQ(render_pass->GetCommands().capacity(), 100u);
1274+
}
1275+
12601276
} // namespace testing
12611277
} // namespace impeller
12621278

0 commit comments

Comments
 (0)