Jonah Williams 97e3fdb511 [Impeller] Encode directly to command buffer for Vulkan. (flutter/engine#49780)
Part of https://github.com/flutter/flutter/issues/140804

Rather than using impeller::Command, the impeller::RenderPass records most state directly into the Vulkan command buffer. This should remove allocation/free overhead of the intermediary structures and make further improvements to the backend even easier. This required a number of other changes to the renderer:

1. The render pass holds a strong ptr to the context. This helps avoid locking continually while encoding, which is quite slow.
2. barriers need to be encoded on the _producing_ side, and not the consuming side. This is because we'll actually run the consuming code before the producing code. i.e. we transition to shader read at the end of a render pass instead of when binding.
3. I've updated the binding code to also provide the descriptor type so that we don't need to look it up from the desc. set.
4. I added a test render pass class that records commands.
2024-01-16 21:52:54 +00:00

96 lines
2.3 KiB
C++

// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "impeller/renderer/command_buffer.h"
#include "flutter/fml/trace_event.h"
#include "impeller/renderer/compute_pass.h"
#include "impeller/renderer/render_pass.h"
#include "impeller/renderer/render_target.h"
namespace impeller {
CommandBuffer::CommandBuffer(std::weak_ptr<const Context> context)
: context_(std::move(context)) {}
CommandBuffer::~CommandBuffer() = default;
bool CommandBuffer::SubmitCommands(const CompletionCallback& callback) {
TRACE_EVENT0("impeller", "CommandBuffer::SubmitCommands");
if (!IsValid()) {
// Already committed or was never valid. Either way, this is caller error.
if (callback) {
callback(Status::kError);
}
return false;
}
return OnSubmitCommands(callback);
}
bool CommandBuffer::SubmitCommands() {
return SubmitCommands(nullptr);
}
void CommandBuffer::WaitUntilScheduled() {
return OnWaitUntilScheduled();
}
bool CommandBuffer::EncodeAndSubmit(
const std::shared_ptr<RenderPass>& render_pass) {
if (!render_pass->IsValid() || !IsValid()) {
return false;
}
if (!render_pass->EncodeCommands()) {
return false;
}
return SubmitCommands(nullptr);
}
bool CommandBuffer::EncodeAndSubmit(
const std::shared_ptr<BlitPass>& blit_pass,
const std::shared_ptr<Allocator>& allocator) {
if (!blit_pass->IsValid() || !IsValid()) {
return false;
}
if (!blit_pass->EncodeCommands(allocator)) {
return false;
}
return SubmitCommands(nullptr);
}
std::shared_ptr<RenderPass> CommandBuffer::CreateRenderPass(
const RenderTarget& render_target) {
auto pass = OnCreateRenderPass(render_target);
if (pass && pass->IsValid()) {
pass->SetLabel("RenderPass");
return pass;
}
return nullptr;
}
std::shared_ptr<BlitPass> CommandBuffer::CreateBlitPass() {
auto pass = OnCreateBlitPass();
if (pass && pass->IsValid()) {
pass->SetLabel("BlitPass");
return pass;
}
return nullptr;
}
std::shared_ptr<ComputePass> CommandBuffer::CreateComputePass() {
if (!IsValid()) {
return nullptr;
}
auto pass = OnCreateComputePass();
if (pass && pass->IsValid()) {
pass->SetLabel("ComputePass");
return pass;
}
return nullptr;
}
} // namespace impeller