[Impeller] Passes and command buffers hold weak handles to the context. (flutter/engine#35352)

This makes the submission simpler as the allocators can be acquired from the
pass itself.

Also makes command buffer submission go through a common method that performs
error checking before dispatch to the backend.
This commit is contained in:
Chinmay Garde 2022-08-11 14:50:10 -07:00 committed by GitHub
parent fea6e19d60
commit a48523baec
24 changed files with 102 additions and 74 deletions

View File

@ -263,7 +263,7 @@ std::shared_ptr<Texture> ContentContext::MakeSubpass(
return nullptr;
}
if (!sub_renderpass->EncodeCommands(context->GetResourceAllocator())) {
if (!sub_renderpass->EncodeCommands()) {
return nullptr;
}

View File

@ -173,8 +173,7 @@ bool EntityPass::Render(ContentContext& renderer,
entity.Render(renderer, *render_pass);
}
if (!render_pass->EncodeCommands(
renderer.GetContext()->GetResourceAllocator())) {
if (!render_pass->EncodeCommands()) {
return false;
}
if (!command_buffer->SubmitCommands()) {

View File

@ -37,7 +37,7 @@ bool InlinePassContext::EndPass() {
return true;
}
if (!pass_->EncodeCommands(context_->GetResourceAllocator())) {
if (!pass_->EncodeCommands()) {
return false;
}

View File

@ -244,7 +244,7 @@ bool Playground::OpenPlaygroundHere(Renderer::RenderCallback render_callback) {
ImGui_ImplImpeller_RenderDrawData(ImGui::GetDrawData(), *pass);
pass->EncodeCommands(renderer->GetContext()->GetResourceAllocator());
pass->EncodeCommands();
if (!buffer->SubmitCommands()) {
return false;
}
@ -284,7 +284,7 @@ bool Playground::OpenPlaygroundHere(SinglePassCallback pass_callback) {
return false;
}
pass->EncodeCommands(context->GetResourceAllocator());
pass->EncodeCommands();
if (!buffer->SubmitCommands()) {
return false;
}

View File

@ -10,8 +10,10 @@
namespace impeller {
CommandBufferGLES::CommandBufferGLES(ReactorGLES::Ref reactor)
: reactor_(std::move(reactor)),
CommandBufferGLES::CommandBufferGLES(std::weak_ptr<const Context> context,
ReactorGLES::Ref reactor)
: CommandBuffer(std::move(context)),
reactor_(std::move(reactor)),
is_valid_(reactor_ && reactor_->IsValid()) {}
CommandBufferGLES::~CommandBufferGLES() = default;
@ -27,13 +29,8 @@ bool CommandBufferGLES::IsValid() const {
}
// |CommandBuffer|
bool CommandBufferGLES::SubmitCommands(CompletionCallback callback) {
if (!IsValid()) {
return false;
}
bool CommandBufferGLES::OnSubmitCommands(CompletionCallback callback) {
const auto result = reactor_->React();
if (callback) {
callback(result ? CommandBuffer::Status::kCompleted
: CommandBuffer::Status::kError);
@ -48,7 +45,7 @@ std::shared_ptr<RenderPass> CommandBufferGLES::OnCreateRenderPass(
return nullptr;
}
auto pass = std::shared_ptr<RenderPassGLES>(
new RenderPassGLES(std::move(target), reactor_));
new RenderPassGLES(context_, std::move(target), reactor_));
if (!pass->IsValid()) {
return nullptr;
}

View File

@ -22,7 +22,8 @@ class CommandBufferGLES final : public CommandBuffer {
ReactorGLES::Ref reactor_;
bool is_valid_ = false;
CommandBufferGLES(ReactorGLES::Ref reactor);
CommandBufferGLES(std::weak_ptr<const Context> context,
ReactorGLES::Ref reactor);
// |CommandBuffer|
void SetLabel(const std::string& label) const override;
@ -31,7 +32,7 @@ class CommandBufferGLES final : public CommandBuffer {
bool IsValid() const override;
// |CommandBuffer|
bool SubmitCommands(CompletionCallback callback) override;
bool OnSubmitCommands(CompletionCallback callback) override;
// |CommandBuffer|
std::shared_ptr<RenderPass> OnCreateRenderPass(

View File

@ -103,7 +103,8 @@ std::shared_ptr<PipelineLibrary> ContextGLES::GetPipelineLibrary() const {
}
std::shared_ptr<CommandBuffer> ContextGLES::CreateCommandBuffer() const {
return std::shared_ptr<CommandBufferGLES>(new CommandBufferGLES(reactor_));
return std::shared_ptr<CommandBufferGLES>(
new CommandBufferGLES(weak_from_this(), reactor_));
}
// |Context|

View File

@ -16,8 +16,10 @@
namespace impeller {
RenderPassGLES::RenderPassGLES(RenderTarget target, ReactorGLES::Ref reactor)
: RenderPass(std::move(target)),
RenderPassGLES::RenderPassGLES(std::weak_ptr<const Context> context,
RenderTarget target,
ReactorGLES::Ref reactor)
: RenderPass(std::move(context), std::move(target)),
reactor_(std::move(reactor)),
is_valid_(reactor_ && reactor_->IsValid()) {}
@ -455,8 +457,7 @@ struct RenderPassData {
}
// |RenderPass|
bool RenderPassGLES::EncodeCommands(
const std::shared_ptr<Allocator>& transients_allocator) const {
bool RenderPassGLES::OnEncodeCommands(const Context& context) const {
if (!IsValid()) {
return false;
}
@ -507,10 +508,11 @@ bool RenderPassGLES::EncodeCommands(
CanDiscardAttachmentWhenDone(stencil0->store_action);
}
return reactor_->AddOperation([pass_data, transients_allocator,
return reactor_->AddOperation([pass_data,
allocator = context.GetResourceAllocator(),
commands = commands_](const auto& reactor) {
auto result = EncodeCommandsInReactor(*pass_data, transients_allocator,
reactor, commands);
auto result =
EncodeCommandsInReactor(*pass_data, allocator, reactor, commands);
FML_CHECK(result) << "Must be able to encode GL commands without error.";
});
}

View File

@ -22,7 +22,9 @@ class RenderPassGLES final : public RenderPass {
std::string label_;
bool is_valid_ = false;
RenderPassGLES(RenderTarget target, ReactorGLES::Ref reactor);
RenderPassGLES(std::weak_ptr<const Context> context,
RenderTarget target,
ReactorGLES::Ref reactor);
// |RenderPass|
bool IsValid() const override;
@ -31,8 +33,7 @@ class RenderPassGLES final : public RenderPass {
void OnSetLabel(std::string label) override;
// |RenderPass|
bool EncodeCommands(
const std::shared_ptr<Allocator>& transients_allocator) const override;
bool OnEncodeCommands(const Context& context) const override;
FML_DISALLOW_COPY_AND_ASSIGN(RenderPassGLES);
};

View File

@ -13,8 +13,6 @@ namespace impeller {
class CommandBufferMTL final : public CommandBuffer {
public:
CommandBufferMTL();
// |CommandBuffer|
~CommandBufferMTL() override;
@ -23,7 +21,8 @@ class CommandBufferMTL final : public CommandBuffer {
id<MTLCommandBuffer> buffer_ = nullptr;
CommandBufferMTL(id<MTLCommandQueue> queue);
CommandBufferMTL(const std::weak_ptr<const Context> context,
id<MTLCommandQueue> queue);
// |CommandBuffer|
void SetLabel(const std::string& label) const override;
@ -32,7 +31,7 @@ class CommandBufferMTL final : public CommandBuffer {
bool IsValid() const override;
// |CommandBuffer|
bool SubmitCommands(CompletionCallback callback) override;
bool OnSubmitCommands(CompletionCallback callback) override;
// |CommandBuffer|
std::shared_ptr<RenderPass> OnCreateRenderPass(

View File

@ -137,8 +137,9 @@ id<MTLCommandBuffer> CreateCommandBuffer(id<MTLCommandQueue> queue) {
return [queue commandBuffer];
}
CommandBufferMTL::CommandBufferMTL(id<MTLCommandQueue> queue)
: buffer_(CreateCommandBuffer(queue)) {}
CommandBufferMTL::CommandBufferMTL(const std::weak_ptr<const Context> context,
id<MTLCommandQueue> queue)
: CommandBuffer(std::move(context)), buffer_(CreateCommandBuffer(queue)) {}
CommandBufferMTL::~CommandBufferMTL() = default;
@ -166,15 +167,7 @@ static CommandBuffer::Status ToCommitResult(MTLCommandBufferStatus status) {
return CommandBufferMTL::Status::kError;
}
bool CommandBufferMTL::SubmitCommands(CompletionCallback callback) {
if (!IsValid()) {
// Already committed or was never valid. Either way, this is caller error.
if (callback) {
callback(Status::kError);
}
return false;
}
bool CommandBufferMTL::OnSubmitCommands(CompletionCallback callback) {
if (callback) {
[buffer_ addCompletedHandler:^(id<MTLCommandBuffer> buffer) {
LogMTLCommandBufferErrorIfPresent(buffer);
@ -195,7 +188,7 @@ std::shared_ptr<RenderPass> CommandBufferMTL::OnCreateRenderPass(
}
auto pass = std::shared_ptr<RenderPassMTL>(
new RenderPassMTL(buffer_, std::move(target)));
new RenderPassMTL(context_, std::move(target), buffer_));
if (!pass->IsValid()) {
return nullptr;
}

View File

@ -193,7 +193,8 @@ std::shared_ptr<CommandBuffer> ContextMTL::CreateCommandBufferInQueue(
return nullptr;
}
auto buffer = std::shared_ptr<CommandBufferMTL>(new CommandBufferMTL(queue));
auto buffer = std::shared_ptr<CommandBufferMTL>(
new CommandBufferMTL(weak_from_this(), queue));
if (!buffer->IsValid()) {
return nullptr;
}

View File

@ -25,7 +25,9 @@ class RenderPassMTL final : public RenderPass {
std::string label_;
bool is_valid_ = false;
RenderPassMTL(id<MTLCommandBuffer> buffer, RenderTarget target);
RenderPassMTL(std::weak_ptr<const Context> context,
RenderTarget target,
id<MTLCommandBuffer> buffer);
// |RenderPass|
bool IsValid() const override;
@ -34,8 +36,7 @@ class RenderPassMTL final : public RenderPass {
void OnSetLabel(std::string label) override;
// |RenderPass|
bool EncodeCommands(
const std::shared_ptr<Allocator>& transients_allocator) const override;
bool OnEncodeCommands(const Context& context) const override;
bool EncodeCommands(const std::shared_ptr<Allocator>& transients_allocator,
id<MTLRenderCommandEncoder> pass) const;

View File

@ -128,8 +128,10 @@ static MTLRenderPassDescriptor* ToMTLRenderPassDescriptor(
return result;
}
RenderPassMTL::RenderPassMTL(id<MTLCommandBuffer> buffer, RenderTarget target)
: RenderPass(std::move(target)),
RenderPassMTL::RenderPassMTL(std::weak_ptr<const Context> context,
RenderTarget target,
id<MTLCommandBuffer> buffer)
: RenderPass(std::move(context), std::move(target)),
buffer_(buffer),
desc_(ToMTLRenderPassDescriptor(GetRenderTarget())) {
if (!buffer_ || !desc_ || !render_target_.IsValid()) {
@ -151,8 +153,7 @@ void RenderPassMTL::OnSetLabel(std::string label) {
label_ = std::move(label);
}
bool RenderPassMTL::EncodeCommands(
const std::shared_ptr<Allocator>& transients_allocator) const {
bool RenderPassMTL::OnEncodeCommands(const Context& context) const {
TRACE_EVENT0("impeller", "RenderPassMTL::EncodeCommands");
if (!IsValid()) {
return false;
@ -173,7 +174,7 @@ bool RenderPassMTL::EncodeCommands(
fml::ScopedCleanupClosure auto_end(
[render_command_encoder]() { [render_command_encoder endEncoding]; });
return EncodeCommands(transients_allocator, render_command_encoder);
return EncodeCommands(context.GetResourceAllocator(), render_command_encoder);
}
//-----------------------------------------------------------------------------

View File

@ -9,7 +9,8 @@
namespace impeller {
CommandBufferVK::CommandBufferVK() = default;
CommandBufferVK::CommandBufferVK(std::weak_ptr<const Context> context)
: CommandBuffer(std::move(context)) {}
CommandBufferVK::~CommandBufferVK() = default;
@ -21,7 +22,7 @@ bool CommandBufferVK::IsValid() const {
FML_UNREACHABLE();
}
bool CommandBufferVK::SubmitCommands(CompletionCallback callback) {
bool CommandBufferVK::OnSubmitCommands(CompletionCallback callback) {
FML_UNREACHABLE();
}

View File

@ -17,7 +17,7 @@ class CommandBufferVK final : public CommandBuffer {
private:
friend class ContextMTL;
CommandBufferVK();
explicit CommandBufferVK(std::weak_ptr<const Context> context);
// |CommandBuffer|
void SetLabel(const std::string& label) const override;
@ -26,7 +26,7 @@ class CommandBufferVK final : public CommandBuffer {
bool IsValid() const override;
// |CommandBuffer|
bool SubmitCommands(CompletionCallback callback) override;
bool OnSubmitCommands(CompletionCallback callback) override;
// |CommandBuffer|
std::shared_ptr<RenderPass> OnCreateRenderPass(

View File

@ -27,8 +27,7 @@ class RenderPassVK final : public RenderPass {
void OnSetLabel(std::string label) override;
// |RenderPass|
bool EncodeCommands(
const std::shared_ptr<Allocator>& transients_allocator) const override;
bool OnEncodeCommands(const Context& context) const override;
FML_DISALLOW_COPY_AND_ASSIGN(RenderPassVK);
};

View File

@ -4,15 +4,29 @@
#include "impeller/renderer/command_buffer.h"
#include "flutter/fml/trace_event.h"
#include "impeller/renderer/render_pass.h"
#include "impeller/renderer/render_target.h"
namespace impeller {
CommandBuffer::CommandBuffer() = default;
CommandBuffer::CommandBuffer(std::weak_ptr<const Context> context)
: context_(std::move(context)) {}
CommandBuffer::~CommandBuffer() = default;
bool CommandBuffer::SubmitCommands(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);
}

View File

@ -59,7 +59,7 @@ class CommandBuffer {
///
/// @param[in] callback The completion callback.
///
[[nodiscard]] virtual bool SubmitCommands(CompletionCallback callback) = 0;
[[nodiscard]] bool SubmitCommands(CompletionCallback callback);
[[nodiscard]] bool SubmitCommands();
@ -82,13 +82,17 @@ class CommandBuffer {
std::shared_ptr<BlitPass> CreateBlitPass() const;
protected:
CommandBuffer();
std::weak_ptr<const Context> context_;
explicit CommandBuffer(std::weak_ptr<const Context> context);
virtual std::shared_ptr<RenderPass> OnCreateRenderPass(
RenderTarget render_target) const = 0;
virtual std::shared_ptr<BlitPass> OnCreateBlitPass() const = 0;
[[nodiscard]] virtual bool OnSubmitCommands(CompletionCallback callback) = 0;
private:
FML_DISALLOW_COPY_AND_ASSIGN(CommandBuffer);
};

View File

@ -17,7 +17,7 @@ class CommandBuffer;
class PipelineLibrary;
class Allocator;
class Context {
class Context : public std::enable_shared_from_this<Context> {
public:
virtual ~Context();

View File

@ -6,8 +6,10 @@
namespace impeller {
RenderPass::RenderPass(RenderTarget target)
: render_target_(std::move(target)),
RenderPass::RenderPass(std::weak_ptr<const Context> context,
RenderTarget target)
: context_(std::move(context)),
render_target_(std::move(target)),
transients_buffer_(HostBuffer::Create()) {}
RenderPass::~RenderPass() = default;
@ -63,4 +65,13 @@ bool RenderPass::AddCommand(Command command) {
return true;
}
bool RenderPass::EncodeCommands() const {
auto context = context_.lock();
// The context could have been collected in the meantime.
if (!context) {
return false;
}
return OnEncodeCommands(*context);
}
} // namespace impeller

View File

@ -51,23 +51,23 @@ class RenderPass {
//----------------------------------------------------------------------------
/// @brief Encode the recorded commands to the underlying command buffer.
///
/// @param transients_allocator The transients allocator.
///
/// @return If the commands were encoded to the underlying command
/// buffer.
///
virtual bool EncodeCommands(
const std::shared_ptr<Allocator>& transients_allocator) const = 0;
bool EncodeCommands() const;
protected:
const std::weak_ptr<const Context> context_;
const RenderTarget render_target_;
std::shared_ptr<HostBuffer> transients_buffer_;
std::vector<Command> commands_;
RenderPass(RenderTarget target);
RenderPass(std::weak_ptr<const Context> context, RenderTarget target);
virtual void OnSetLabel(std::string label) = 0;
virtual bool OnEncodeCommands(const Context& context) const = 0;
private:
FML_DISALLOW_COPY_AND_ASSIGN(RenderPass);
};

View File

@ -53,8 +53,11 @@ bool Renderer::Render(std::unique_ptr<Surface> surface,
return false;
}
const auto present_result = surface->Present();
frames_in_flight_sema_->Signal();
return surface->Present();
return present_result;
}
std::shared_ptr<Context> Renderer::GetContext() const {

View File

@ -378,7 +378,7 @@ TEST_P(RendererTest, CanRenderToTexture) {
VS::BindUniformBuffer(
cmd, r2t_pass->GetTransientsBuffer().EmplaceUniform(uniforms));
ASSERT_TRUE(r2t_pass->AddCommand(std::move(cmd)));
ASSERT_TRUE(r2t_pass->EncodeCommands(context->GetResourceAllocator()));
ASSERT_TRUE(r2t_pass->EncodeCommands());
}
#if IMPELLER_ENABLE_METAL
@ -543,7 +543,7 @@ TEST_P(RendererTest, CanBlitTextureToTexture) {
pass->AddCommand(std::move(cmd));
}
pass->EncodeCommands(context->GetResourceAllocator());
pass->EncodeCommands();
}
if (!buffer->SubmitCommands()) {
@ -664,7 +664,7 @@ TEST_P(RendererTest, CanGenerateMipmaps) {
pass->AddCommand(std::move(cmd));
}
pass->EncodeCommands(context->GetResourceAllocator());
pass->EncodeCommands();
}
if (!buffer->SubmitCommands()) {