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

[Impeller] preallocate command buffer to next power of two of entity list. #48185

Merged
merged 4 commits into from
Nov 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions impeller/entity/entity_pass.cc
Original file line number Diff line number Diff line change
Expand Up @@ -835,8 +835,9 @@ bool EntityPass::OnRender(
TRACE_EVENT0("impeller", "EntityPass::OnRender");

auto context = renderer.GetContext();
InlinePassContext pass_context(
context, pass_target, GetTotalPassReads(renderer), collapsed_parent_pass);
InlinePassContext pass_context(context, pass_target,
GetTotalPassReads(renderer), GetElementCount(),
collapsed_parent_pass);
if (!pass_context.IsValid()) {
VALIDATION_LOG << SPrintF("Pass context invalid (Depth=%d)", pass_depth);
return false;
Expand Down
7 changes: 6 additions & 1 deletion impeller/entity/inline_pass_context.cc
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,11 @@ InlinePassContext::InlinePassContext(
std::shared_ptr<Context> context,
EntityPassTarget& pass_target,
uint32_t pass_texture_reads,
uint32_t entity_count,
std::optional<RenderPassResult> collapsed_parent_pass)
: context_(std::move(context)),
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;
Expand Down Expand Up @@ -149,7 +151,10 @@ InlinePassContext::RenderPassResult InlinePassContext::GetRenderPass(
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_));
Expand Down
8 changes: 8 additions & 0 deletions impeller/entity/inline_pass_context.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,21 @@ class InlinePassContext {
std::shared_ptr<Context> context,
EntityPassTarget& pass_target,
uint32_t pass_texture_reads,
uint32_t entity_count,
std::optional<RenderPassResult> collapsed_parent_pass = std::nullopt);

~InlinePassContext();

bool IsValid() const;

bool IsActive() const;

std::shared_ptr<Texture> GetTexture();

bool EndPass();

EntityPassTarget& GetPassTarget() const;

uint32_t GetPassCount() const;

RenderPassResult GetRenderPass(uint32_t pass_depth);
Expand All @@ -42,6 +49,7 @@ class InlinePassContext {
std::shared_ptr<CommandBuffer> command_buffer_;
std::shared_ptr<RenderPass> 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;
Expand Down
7 changes: 3 additions & 4 deletions impeller/renderer/command.h
Original file line number Diff line number Diff line change
Expand Up @@ -92,10 +92,9 @@ struct Bindings {
/// * Specify any stage bindings.
/// * (Optional) Specify a debug label.
///
/// Command are very lightweight objects and can be created
/// frequently and on demand. The resources referenced in commands
/// views into buffers managed by other allocators and resource
/// managers.
/// Command can be created frequently and on demand. The resources
/// referenced in commands views into buffers managed by other
/// allocators and resource managers.
///
struct Command : public ResourceBinder {
//----------------------------------------------------------------------------
Expand Down
7 changes: 7 additions & 0 deletions impeller/renderer/render_pass.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,13 @@ class RenderPass {

void SetLabel(std::string label);

/// @brief Reserve [command_count] commands in the HAL command buffer.
///
/// Note: this is not the native command buffer.
void ReserveCommands(size_t command_count) {
commands_.reserve(command_count);
}

HostBuffer& GetTransientsBuffer();

//----------------------------------------------------------------------------
Expand Down
16 changes: 16 additions & 0 deletions impeller/renderer/renderer_unittests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
#include "impeller/renderer/command_buffer.h"
#include "impeller/renderer/pipeline_builder.h"
#include "impeller/renderer/pipeline_library.h"
#include "impeller/renderer/render_target.h"
#include "impeller/renderer/renderer.h"
#include "impeller/renderer/sampler_library.h"
#include "impeller/renderer/surface.h"
Expand Down Expand Up @@ -1257,6 +1258,21 @@ TEST_P(RendererTest, StencilMask) {
OpenPlaygroundHere(callback);
}

TEST_P(RendererTest, CanPreAllocateCommands) {
auto context = GetContext();
auto cmd_buffer = context->CreateCommandBuffer();
auto render_target_cache = std::make_shared<RenderTargetAllocator>(
GetContext()->GetResourceAllocator());

auto render_target =
RenderTarget::CreateOffscreen(*context, *render_target_cache, {100, 100});
auto render_pass = cmd_buffer->CreateRenderPass(render_target);

render_pass->ReserveCommands(100u);

EXPECT_EQ(render_pass->GetCommands().capacity(), 100u);
}

} // namespace testing
} // namespace impeller

Expand Down