From 73a2de5da53f8ab133e88b43d05189879c370cb3 Mon Sep 17 00:00:00 2001 From: "auto-submit[bot]" <98614782+auto-submit[bot]@users.noreply.github.com> Date: Wed, 17 Jan 2024 01:18:17 +0000 Subject: [PATCH] Reverts "[Impeller] Encode directly to command buffer for Vulkan." (#49818) Reverts flutter/engine#49780 Initiated by: jonahwilliams This change reverts the following previous change: Original Description: 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. --- impeller/aiks/BUILD.gn | 1 - impeller/aiks/testing/context_spy.cc | 21 +- impeller/aiks/testing/context_spy.h | 4 +- impeller/compiler/code_gen_template.h | 2 +- impeller/compiler/reflector.cc | 6 - impeller/compiler/reflector.h | 1 - impeller/core/resource_binder.h | 2 - impeller/entity/BUILD.gn | 2 - .../checkerboard_contents_unittests.cc | 10 +- .../contents/runtime_effect_contents.cc | 12 +- .../contents/test/recording_render_pass.cc | 116 ---- .../contents/test/recording_render_pass.h | 87 --- .../tiled_texture_contents_unittests.cc | 7 +- .../contents/vertices_contents_unittests.cc | 10 +- .../playground/imgui/imgui_impl_impeller.cc | 2 +- .../backend/gles/command_buffer_gles.cc | 6 +- .../renderer/backend/gles/render_pass_gles.cc | 2 +- .../renderer/backend/gles/render_pass_gles.h | 2 +- .../backend/metal/command_buffer_mtl.mm | 6 +- .../renderer/backend/metal/render_pass_mtl.h | 2 +- .../renderer/backend/metal/render_pass_mtl.mm | 2 +- .../backend/vulkan/binding_helpers_vk.cc | 66 ++ .../backend/vulkan/binding_helpers_vk.h | 11 + .../backend/vulkan/command_buffer_vk.cc | 9 +- .../backend/vulkan/command_buffer_vk.h | 1 + .../renderer/backend/vulkan/gpu_tracer_vk.cc | 15 +- .../renderer/backend/vulkan/render_pass_vk.cc | 584 +++++++----------- .../renderer/backend/vulkan/render_pass_vk.h | 90 +-- .../renderer/backend/vulkan/texture_vk.cc | 18 - impeller/renderer/command.cc | 3 - impeller/renderer/command.h | 3 - impeller/renderer/command_buffer.cc | 2 + impeller/renderer/compute_command.cc | 3 - impeller/renderer/compute_command.h | 2 - impeller/renderer/render_pass.cc | 20 +- impeller/renderer/render_pass.h | 64 +- impeller/renderer/renderer_unittests.cc | 15 + impeller/renderer/testing/mocks.h | 2 +- lib/gpu/render_pass.cc | 37 +- lib/gpu/render_pass.h | 2 +- 40 files changed, 445 insertions(+), 805 deletions(-) delete mode 100644 impeller/entity/contents/test/recording_render_pass.cc delete mode 100644 impeller/entity/contents/test/recording_render_pass.h diff --git a/impeller/aiks/BUILD.gn b/impeller/aiks/BUILD.gn index 06d643c7b9993..f1d7d8ef681ac 100644 --- a/impeller/aiks/BUILD.gn +++ b/impeller/aiks/BUILD.gn @@ -76,7 +76,6 @@ impeller_component("context_spy") { "testing/context_spy.h", ] deps = [ - "//flutter/impeller/entity:entity_test_helpers", "//flutter/impeller/renderer", "//flutter/testing:testing_lib", ] diff --git a/impeller/aiks/testing/context_spy.cc b/impeller/aiks/testing/context_spy.cc index 460013cc2808a..e831719cd3008 100644 --- a/impeller/aiks/testing/context_spy.cc +++ b/impeller/aiks/testing/context_spy.cc @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include - #include "impeller/aiks/testing/context_spy.h" namespace impeller { @@ -66,17 +64,14 @@ std::shared_ptr ContextSpy::MakeContext( }); ON_CALL(*spy, OnCreateRenderPass) - .WillByDefault([real_buffer, shared_this, - real_context](const RenderTarget& render_target) { - std::shared_ptr result = - CommandBufferMock::ForwardOnCreateRenderPass( - real_buffer.get(), render_target); - std::shared_ptr recorder = - std::make_shared(result, real_context, - render_target); - shared_this->render_passes_.push_back(recorder); - return recorder; - }); + .WillByDefault( + [real_buffer, shared_this](const RenderTarget& render_target) { + std::shared_ptr result = + CommandBufferMock::ForwardOnCreateRenderPass( + real_buffer.get(), render_target); + shared_this->render_passes_.push_back(result); + return result; + }); ON_CALL(*spy, OnCreateBlitPass).WillByDefault([real_buffer]() { return CommandBufferMock::ForwardOnCreateBlitPass(real_buffer.get()); diff --git a/impeller/aiks/testing/context_spy.h b/impeller/aiks/testing/context_spy.h index fe251b89e5999..28a5ec3907ae4 100644 --- a/impeller/aiks/testing/context_spy.h +++ b/impeller/aiks/testing/context_spy.h @@ -6,9 +6,7 @@ #define FLUTTER_IMPELLER_AIKS_TESTING_CONTEXT_SPY_H_ #include - #include "impeller/aiks/testing/context_mock.h" -#include "impeller/entity/contents/test/recording_render_pass.h" namespace impeller { namespace testing { @@ -22,7 +20,7 @@ class ContextSpy : public std::enable_shared_from_this { std::shared_ptr MakeContext( const std::shared_ptr& real_context); - std::vector> render_passes_; + std::vector> render_passes_; private: ContextSpy() = default; diff --git a/impeller/compiler/code_gen_template.h b/impeller/compiler/code_gen_template.h index dbef3017c0e41..7927c71d2952c 100644 --- a/impeller/compiler/code_gen_template.h +++ b/impeller/compiler/code_gen_template.h @@ -161,7 +161,7 @@ struct {{camel_case(shader_name)}}{{camel_case(shader_stage)}}Shader { {% endfor %}) { return {{ proto.args.0.argument_name }}.BindResource({% for arg in proto.args %} {% if loop.is_first %} -{{to_shader_stage(shader_stage)}}, {{ proto.descriptor_type }}, kResource{{ proto.name }}, kMetadata{{ proto.name }}, {% else %} +{{to_shader_stage(shader_stage)}}, kResource{{ proto.name }}, kMetadata{{ proto.name }}, {% else %} std::move({{ arg.argument_name }}){% if not loop.is_last %}, {% endif %} {% endif %} {% endfor %}); diff --git a/impeller/compiler/reflector.cc b/impeller/compiler/reflector.cc index cafa894256f4d..e01755bccc38f 100644 --- a/impeller/compiler/reflector.cc +++ b/impeller/compiler/reflector.cc @@ -1308,7 +1308,6 @@ std::vector Reflector::ReflectBindPrototypes( auto& proto = prototypes.emplace_back(BindPrototype{}); proto.return_type = "bool"; proto.name = ToCamelCase(uniform_buffer.name); - proto.descriptor_type = "DescriptorType::kUniformBuffer"; { std::stringstream stream; stream << "Bind uniform buffer for resource named " << uniform_buffer.name @@ -1328,7 +1327,6 @@ std::vector Reflector::ReflectBindPrototypes( auto& proto = prototypes.emplace_back(BindPrototype{}); proto.return_type = "bool"; proto.name = ToCamelCase(storage_buffer.name); - proto.descriptor_type = "DescriptorType::kStorageBuffer"; { std::stringstream stream; stream << "Bind storage buffer for resource named " << storage_buffer.name @@ -1348,7 +1346,6 @@ std::vector Reflector::ReflectBindPrototypes( auto& proto = prototypes.emplace_back(BindPrototype{}); proto.return_type = "bool"; proto.name = ToCamelCase(sampled_image.name); - proto.descriptor_type = "DescriptorType::kSampledImage"; { std::stringstream stream; stream << "Bind combined image sampler for resource named " @@ -1372,7 +1369,6 @@ std::vector Reflector::ReflectBindPrototypes( auto& proto = prototypes.emplace_back(BindPrototype{}); proto.return_type = "bool"; proto.name = ToCamelCase(separate_image.name); - proto.descriptor_type = "DescriptorType::kImage"; { std::stringstream stream; stream << "Bind separate image for resource named " << separate_image.name @@ -1392,7 +1388,6 @@ std::vector Reflector::ReflectBindPrototypes( auto& proto = prototypes.emplace_back(BindPrototype{}); proto.return_type = "bool"; proto.name = ToCamelCase(separate_sampler.name); - proto.descriptor_type = "DescriptorType::kSampler"; { std::stringstream stream; stream << "Bind separate sampler for resource named " @@ -1421,7 +1416,6 @@ nlohmann::json::array_t Reflector::EmitBindPrototypes( item["return_type"] = res.return_type; item["name"] = res.name; item["docstring"] = res.docstring; - item["descriptor_type"] = res.descriptor_type; auto& args = item["args"] = nlohmann::json::array_t{}; for (const auto& arg : res.args) { auto& json_arg = args.emplace_back(nlohmann::json::object_t{}); diff --git a/impeller/compiler/reflector.h b/impeller/compiler/reflector.h index 1448e412d4738..3de086c00a553 100644 --- a/impeller/compiler/reflector.h +++ b/impeller/compiler/reflector.h @@ -187,7 +187,6 @@ class Reflector { std::string name; std::string return_type; std::string docstring; - std::string descriptor_type = ""; std::vector args; }; diff --git a/impeller/core/resource_binder.h b/impeller/core/resource_binder.h index bd2dfea50508e..6a6172710d700 100644 --- a/impeller/core/resource_binder.h +++ b/impeller/core/resource_binder.h @@ -24,13 +24,11 @@ struct ResourceBinder { virtual ~ResourceBinder() = default; virtual bool BindResource(ShaderStage stage, - DescriptorType type, const ShaderUniformSlot& slot, const ShaderMetadata& metadata, BufferView view) = 0; virtual bool BindResource(ShaderStage stage, - DescriptorType type, const SampledImageSlot& slot, const ShaderMetadata& metadata, std::shared_ptr texture, diff --git a/impeller/entity/BUILD.gn b/impeller/entity/BUILD.gn index 0f900cf0345ab..31852bf1350df 100644 --- a/impeller/entity/BUILD.gn +++ b/impeller/entity/BUILD.gn @@ -257,8 +257,6 @@ impeller_component("entity_test_helpers") { sources = [ "contents/test/contents_test_helpers.cc", "contents/test/contents_test_helpers.h", - "contents/test/recording_render_pass.cc", - "contents/test/recording_render_pass.h", ] deps = [ ":entity" ] diff --git a/impeller/entity/contents/checkerboard_contents_unittests.cc b/impeller/entity/contents/checkerboard_contents_unittests.cc index 97e1dae4276d5..63a2cbdd3aa07 100644 --- a/impeller/entity/contents/checkerboard_contents_unittests.cc +++ b/impeller/entity/contents/checkerboard_contents_unittests.cc @@ -9,7 +9,6 @@ #include "impeller/entity/contents/checkerboard_contents.h" #include "impeller/entity/contents/contents.h" -#include "impeller/entity/contents/test/recording_render_pass.h" #include "impeller/entity/entity.h" #include "impeller/entity/entity_playground.h" #include "impeller/renderer/render_target.h" @@ -39,14 +38,11 @@ TEST_P(EntityTest, RendersWithoutError) { *GetContentContext()->GetRenderTargetCache(), {100, 100}, /*mip_count=*/1); auto render_pass = buffer->CreateRenderPass(render_target); - auto recording_pass = std::make_shared( - render_pass, GetContext(), render_target); - Entity entity; - ASSERT_TRUE(recording_pass->GetCommands().empty()); - ASSERT_TRUE(contents->Render(*content_context, entity, *recording_pass)); - ASSERT_FALSE(recording_pass->GetCommands().empty()); + ASSERT_TRUE(render_pass->GetCommands().empty()); + ASSERT_TRUE(contents->Render(*content_context, entity, *render_pass)); + ASSERT_FALSE(render_pass->GetCommands().empty()); } #endif // IMPELLER_DEBUG diff --git a/impeller/entity/contents/runtime_effect_contents.cc b/impeller/entity/contents/runtime_effect_contents.cc index 7da74e4a56b0b..54170ffff091f 100644 --- a/impeller/entity/contents/runtime_effect_contents.cc +++ b/impeller/entity/contents/runtime_effect_contents.cc @@ -199,9 +199,8 @@ bool RuntimeEffectContents::Render(const ContentContext& renderer, ShaderUniformSlot uniform_slot; uniform_slot.name = uniform.name.c_str(); uniform_slot.ext_res_0 = uniform.location; - pass.BindResource(ShaderStage::kFragment, - DescriptorType::kUniformBuffer, uniform_slot, - metadata, buffer_view); + pass.BindResource(ShaderStage::kFragment, uniform_slot, metadata, + buffer_view); buffer_index++; buffer_offset += uniform.GetSize(); break; @@ -238,8 +237,7 @@ bool RuntimeEffectContents::Render(const ContentContext& renderer, auto buffer_view = renderer.GetTransientsBuffer().Emplace( reinterpret_cast(uniform_buffer.data()), sizeof(float) * uniform_buffer.size(), alignment); - pass.BindResource(ShaderStage::kFragment, - DescriptorType::kUniformBuffer, uniform_slot, + pass.BindResource(ShaderStage::kFragment, uniform_slot, ShaderMetadata{}, buffer_view); } } @@ -273,8 +271,8 @@ bool RuntimeEffectContents::Render(const ContentContext& renderer, image_slot.binding = sampler_binding_location; image_slot.texture_index = uniform.location - minimum_sampler_index; - pass.BindResource(ShaderStage::kFragment, DescriptorType::kSampledImage, - image_slot, *metadata, input.texture, sampler); + pass.BindResource(ShaderStage::kFragment, image_slot, *metadata, + input.texture, sampler); sampler_index++; break; diff --git a/impeller/entity/contents/test/recording_render_pass.cc b/impeller/entity/contents/test/recording_render_pass.cc deleted file mode 100644 index ef22d86d69ed6..0000000000000 --- a/impeller/entity/contents/test/recording_render_pass.cc +++ /dev/null @@ -1,116 +0,0 @@ -// 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/entity/contents/test/recording_render_pass.h" - -#include - -namespace impeller { - -RecordingRenderPass::RecordingRenderPass( - std::shared_ptr delegate, - const std::shared_ptr& context, - const RenderTarget& render_target) - : RenderPass(context, render_target), delegate_(std::move(delegate)) {} - -// |RenderPass| -void RecordingRenderPass::SetPipeline( - const std::shared_ptr>& pipeline) { - pending_.pipeline = pipeline; - delegate_->SetPipeline(pipeline); -} - -void RecordingRenderPass::SetCommandLabel(std::string_view label) { -#ifdef IMPELLER_DEBUG - pending_.label = std::string(label); -#endif // IMPELLER_DEBUG - delegate_->SetCommandLabel(label); -} - -// |RenderPass| -void RecordingRenderPass::SetStencilReference(uint32_t value) { - pending_.stencil_reference = value; - delegate_->SetStencilReference(value); -} - -// |RenderPass| -void RecordingRenderPass::SetBaseVertex(uint64_t value) { - pending_.base_vertex = value; - delegate_->SetBaseVertex(value); -} - -// |RenderPass| -void RecordingRenderPass::SetViewport(Viewport viewport) { - pending_.viewport = viewport; - delegate_->SetViewport(viewport); -} - -// |RenderPass| -void RecordingRenderPass::SetScissor(IRect scissor) { - pending_.scissor = scissor; - delegate_->SetScissor(scissor); -} - -// |RenderPass| -void RecordingRenderPass::SetInstanceCount(size_t count) { - pending_.instance_count = count; - delegate_->SetInstanceCount(count); -} - -// |RenderPass| -bool RecordingRenderPass::SetVertexBuffer(VertexBuffer buffer) { - pending_.vertex_buffer = buffer; - return delegate_->SetVertexBuffer(buffer); -} - -// |RenderPass| -fml::Status RecordingRenderPass::Draw() { - commands_.emplace_back(std::move(pending_)); - pending_ = {}; - return delegate_->Draw(); -} - -// |RenderPass| -void RecordingRenderPass::OnSetLabel(std::string label) { - return; -} - -// |RenderPass| -bool RecordingRenderPass::OnEncodeCommands(const Context& context) const { - return true; -} - -// |RenderPass| -bool RecordingRenderPass::BindResource(ShaderStage stage, - DescriptorType type, - const ShaderUniformSlot& slot, - const ShaderMetadata& metadata, - BufferView view) { - pending_.BindResource(stage, type, slot, metadata, view); - return delegate_->BindResource(stage, type, slot, metadata, view); -} - -// |RenderPass| -bool RecordingRenderPass::BindResource( - ShaderStage stage, - DescriptorType type, - const ShaderUniformSlot& slot, - const std::shared_ptr& metadata, - BufferView view) { - pending_.BindResource(stage, type, slot, metadata, view); - return delegate_->BindResource(stage, type, slot, metadata, view); -} - -// |RenderPass| -bool RecordingRenderPass::BindResource(ShaderStage stage, - DescriptorType type, - const SampledImageSlot& slot, - const ShaderMetadata& metadata, - std::shared_ptr texture, - std::shared_ptr sampler) { - pending_.BindResource(stage, type, slot, metadata, texture, sampler); - return delegate_->BindResource(stage, type, slot, metadata, texture, sampler); -} - -} // namespace impeller diff --git a/impeller/entity/contents/test/recording_render_pass.h b/impeller/entity/contents/test/recording_render_pass.h deleted file mode 100644 index eb585c27767eb..0000000000000 --- a/impeller/entity/contents/test/recording_render_pass.h +++ /dev/null @@ -1,87 +0,0 @@ -// 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. - -#ifndef FLUTTER_IMPELLER_ENTITY_CONTENTS_TEST_RECORDING_RENDER_PASS_H_ -#define FLUTTER_IMPELLER_ENTITY_CONTENTS_TEST_RECORDING_RENDER_PASS_H_ - -#include "impeller/renderer/render_pass.h" - -namespace impeller { - -class RecordingRenderPass : public RenderPass { - public: - explicit RecordingRenderPass(std::shared_ptr delegate, - const std::shared_ptr& context, - const RenderTarget& render_target); - - ~RecordingRenderPass() = default; - - const std::vector& GetCommands() const override { return commands_; } - - // |RenderPass| - void SetPipeline( - const std::shared_ptr>& pipeline) override; - - void SetCommandLabel(std::string_view label) override; - - // |RenderPass| - void SetStencilReference(uint32_t value) override; - - // |RenderPass| - void SetBaseVertex(uint64_t value) override; - - // |RenderPass| - void SetViewport(Viewport viewport) override; - - // |RenderPass| - void SetScissor(IRect scissor) override; - - // |RenderPass| - void SetInstanceCount(size_t count) override; - - // |RenderPass| - bool SetVertexBuffer(VertexBuffer buffer) override; - - // |RenderPass| - fml::Status Draw() override; - - // |RenderPass| - bool BindResource(ShaderStage stage, - DescriptorType type, - const ShaderUniformSlot& slot, - const ShaderMetadata& metadata, - BufferView view) override; - - // |RenderPass| - bool BindResource(ShaderStage stage, - DescriptorType type, - const ShaderUniformSlot& slot, - const std::shared_ptr& metadata, - BufferView view) override; - - // |RenderPass| - bool BindResource(ShaderStage stage, - DescriptorType type, - const SampledImageSlot& slot, - const ShaderMetadata& metadata, - std::shared_ptr texture, - std::shared_ptr sampler) override; - - // |RenderPass| - void OnSetLabel(std::string label) override; - - // |RenderPass| - bool OnEncodeCommands(const Context& context) const override; - - bool IsValid() const override { return true; } - - private: - Command pending_; - std::shared_ptr delegate_; - std::vector commands_; -}; - -} // namespace impeller - -#endif // FLUTTER_IMPELLER_ENTITY_CONTENTS_TEST_RECORDING_RENDER_PASS_H_ diff --git a/impeller/entity/contents/tiled_texture_contents_unittests.cc b/impeller/entity/contents/tiled_texture_contents_unittests.cc index ddaedc3efc1f1..4715eaad79133 100644 --- a/impeller/entity/contents/tiled_texture_contents_unittests.cc +++ b/impeller/entity/contents/tiled_texture_contents_unittests.cc @@ -6,7 +6,6 @@ #include "impeller/core/formats.h" #include "impeller/core/texture_descriptor.h" -#include "impeller/entity/contents/test/recording_render_pass.h" #include "impeller/entity/contents/tiled_texture_contents.h" #include "impeller/entity/entity_playground.h" #include "impeller/playground/playground_test.h" @@ -37,11 +36,9 @@ TEST_P(EntityTest, TiledTextureContentsRendersWithCorrectPipeline) { *GetContentContext()->GetRenderTargetCache(), {100, 100}, /*mip_count=*/1); auto render_pass = buffer->CreateRenderPass(render_target); - auto recording_pass = std::make_shared( - render_pass, GetContext(), render_target); - ASSERT_TRUE(contents.Render(*GetContentContext(), {}, *recording_pass)); - const std::vector& commands = recording_pass->GetCommands(); + ASSERT_TRUE(contents.Render(*GetContentContext(), {}, *render_pass)); + const std::vector& commands = render_pass->GetCommands(); ASSERT_EQ(commands.size(), 1u); ASSERT_STREQ(commands[0].pipeline->GetDescriptor().GetLabel().c_str(), diff --git a/impeller/entity/contents/vertices_contents_unittests.cc b/impeller/entity/contents/vertices_contents_unittests.cc index 4f1e778986070..17fac72d722dc 100644 --- a/impeller/entity/contents/vertices_contents_unittests.cc +++ b/impeller/entity/contents/vertices_contents_unittests.cc @@ -10,7 +10,6 @@ #include "impeller/entity/contents/contents.h" #include "impeller/entity/contents/solid_color_contents.h" #include "impeller/entity/contents/test/contents_test_helpers.h" -#include "impeller/entity/contents/test/recording_render_pass.h" #include "impeller/entity/contents/vertices_contents.h" #include "impeller/entity/entity.h" #include "impeller/entity/entity_playground.h" @@ -65,15 +64,12 @@ TEST_P(EntityTest, RendersDstPerColorWithAlpha) { *GetContentContext()->GetRenderTargetCache(), {100, 100}, /*mip_count=*/1); auto render_pass = buffer->CreateRenderPass(render_target); - auto recording_pass = std::make_shared( - render_pass, GetContext(), render_target); Entity entity; - ASSERT_TRUE(recording_pass->GetCommands().empty()); - ASSERT_TRUE(contents->Render(*content_context, entity, *recording_pass)); + ASSERT_TRUE(render_pass->GetCommands().empty()); + ASSERT_TRUE(contents->Render(*content_context, entity, *render_pass)); - ASSERT_TRUE(recording_pass->GetCommands().size() > 0); - const auto& cmd = recording_pass->GetCommands()[0]; + const auto& cmd = render_pass->GetCommands()[0]; auto* frag_uniforms = GetFragInfo(cmd); ASSERT_TRUE(frag_uniforms); diff --git a/impeller/playground/imgui/imgui_impl_impeller.cc b/impeller/playground/imgui/imgui_impl_impeller.cc index 279c94e51189c..ada717b742ea8 100644 --- a/impeller/playground/imgui/imgui_impl_impeller.cc +++ b/impeller/playground/imgui/imgui_impl_impeller.cc @@ -126,7 +126,7 @@ void ImGui_ImplImpeller_RenderDrawData(ImDrawData* draw_data, return; // Nothing to render. } auto host_buffer = impeller::HostBuffer::Create( - render_pass.GetContext()->GetResourceAllocator()); + render_pass.GetContext().lock()->GetResourceAllocator()); using VS = impeller::ImguiRasterVertexShader; using FS = impeller::ImguiRasterFragmentShader; diff --git a/impeller/renderer/backend/gles/command_buffer_gles.cc b/impeller/renderer/backend/gles/command_buffer_gles.cc index ea6a651d0189a..737984d3ae1a8 100644 --- a/impeller/renderer/backend/gles/command_buffer_gles.cc +++ b/impeller/renderer/backend/gles/command_buffer_gles.cc @@ -49,12 +49,8 @@ std::shared_ptr CommandBufferGLES::OnCreateRenderPass( if (!IsValid()) { return nullptr; } - auto context = context_.lock(); - if (!context) { - return nullptr; - } auto pass = std::shared_ptr( - new RenderPassGLES(context, target, reactor_)); + new RenderPassGLES(context_, target, reactor_)); if (!pass->IsValid()) { return nullptr; } diff --git a/impeller/renderer/backend/gles/render_pass_gles.cc b/impeller/renderer/backend/gles/render_pass_gles.cc index 6cff519a41270..20b6fd4bea71b 100644 --- a/impeller/renderer/backend/gles/render_pass_gles.cc +++ b/impeller/renderer/backend/gles/render_pass_gles.cc @@ -20,7 +20,7 @@ namespace impeller { -RenderPassGLES::RenderPassGLES(std::shared_ptr context, +RenderPassGLES::RenderPassGLES(std::weak_ptr context, const RenderTarget& target, ReactorGLES::Ref reactor) : RenderPass(std::move(context), target), diff --git a/impeller/renderer/backend/gles/render_pass_gles.h b/impeller/renderer/backend/gles/render_pass_gles.h index 9d4f986108d57..e7e408306336c 100644 --- a/impeller/renderer/backend/gles/render_pass_gles.h +++ b/impeller/renderer/backend/gles/render_pass_gles.h @@ -26,7 +26,7 @@ class RenderPassGLES final std::string label_; bool is_valid_ = false; - RenderPassGLES(std::shared_ptr context, + RenderPassGLES(std::weak_ptr context, const RenderTarget& target, ReactorGLES::Ref reactor); diff --git a/impeller/renderer/backend/metal/command_buffer_mtl.mm b/impeller/renderer/backend/metal/command_buffer_mtl.mm index c7899d48982f3..7adb44a189225 100644 --- a/impeller/renderer/backend/metal/command_buffer_mtl.mm +++ b/impeller/renderer/backend/metal/command_buffer_mtl.mm @@ -275,12 +275,8 @@ static bool LogMTLCommandBufferErrorIfPresent(id buffer) { return nullptr; } - auto context = context_.lock(); - if (!context) { - return nullptr; - } auto pass = std::shared_ptr( - new RenderPassMTL(context, target, buffer_)); + new RenderPassMTL(context_, target, buffer_)); if (!pass->IsValid()) { return nullptr; } diff --git a/impeller/renderer/backend/metal/render_pass_mtl.h b/impeller/renderer/backend/metal/render_pass_mtl.h index 00240d45249d3..69c78573e8add 100644 --- a/impeller/renderer/backend/metal/render_pass_mtl.h +++ b/impeller/renderer/backend/metal/render_pass_mtl.h @@ -26,7 +26,7 @@ class RenderPassMTL final : public RenderPass { std::string label_; bool is_valid_ = false; - RenderPassMTL(std::shared_ptr context, + RenderPassMTL(std::weak_ptr context, const RenderTarget& target, id buffer); diff --git a/impeller/renderer/backend/metal/render_pass_mtl.mm b/impeller/renderer/backend/metal/render_pass_mtl.mm index 396127d598733..83918f71fce84 100644 --- a/impeller/renderer/backend/metal/render_pass_mtl.mm +++ b/impeller/renderer/backend/metal/render_pass_mtl.mm @@ -134,7 +134,7 @@ static bool ConfigureStencilAttachment( return result; } -RenderPassMTL::RenderPassMTL(std::shared_ptr context, +RenderPassMTL::RenderPassMTL(std::weak_ptr context, const RenderTarget& target, id buffer) : RenderPass(std::move(context), target), diff --git a/impeller/renderer/backend/vulkan/binding_helpers_vk.cc b/impeller/renderer/backend/vulkan/binding_helpers_vk.cc index 92b30313f5f3a..3bc11ba252784 100644 --- a/impeller/renderer/backend/vulkan/binding_helpers_vk.cc +++ b/impeller/renderer/backend/vulkan/binding_helpers_vk.cc @@ -20,6 +20,11 @@ namespace impeller { +// Warning: if any of the constant values or layouts are changed in the +// framebuffer fetch shader, then this input binding may need to be +// manually changed. +static constexpr size_t kMagicSubpassInputBinding = 64; + static bool BindImages( const Bindings& bindings, Allocator& allocator, @@ -120,6 +125,67 @@ static bool BindBuffers( return true; } +fml::StatusOr AllocateAndBindDescriptorSets( + const ContextVK& context, + const std::shared_ptr& encoder, + Allocator& allocator, + const Command& command, + const TextureVK& input_attachment, + std::array& image_workspace, + std::array& buffer_workspace, + std::array& + write_workspace) { + auto descriptor_result = encoder->AllocateDescriptorSets( + PipelineVK::Cast(*command.pipeline).GetDescriptorSetLayout(), context); + if (!descriptor_result.ok()) { + return descriptor_result.status(); + } + vk::DescriptorSet descriptor_set = descriptor_result.value(); + + size_t buffer_offset = 0u; + size_t image_offset = 0u; + size_t write_offset = 0u; + + auto& pipeline_descriptor = command.pipeline->GetDescriptor(); + auto& desc_set = + pipeline_descriptor.GetVertexDescriptor()->GetDescriptorSetLayouts(); + + if (!BindBuffers(command.vertex_bindings, allocator, encoder, descriptor_set, + desc_set, buffer_workspace, buffer_offset, write_workspace, + write_offset) || + !BindBuffers(command.fragment_bindings, allocator, encoder, + descriptor_set, desc_set, buffer_workspace, buffer_offset, + write_workspace, write_offset) || + !BindImages(command.fragment_bindings, allocator, encoder, descriptor_set, + image_workspace, image_offset, write_workspace, + write_offset)) { + return fml::Status(fml::StatusCode::kUnknown, + "Failed to bind texture or buffer."); + } + + if (pipeline_descriptor.UsesSubpassInput()) { + vk::DescriptorImageInfo image_info; + image_info.imageLayout = vk::ImageLayout::eGeneral; + image_info.sampler = VK_NULL_HANDLE; + image_info.imageView = input_attachment.GetImageView(); + image_workspace[image_offset++] = image_info; + + vk::WriteDescriptorSet write_set; + write_set.dstSet = descriptor_set; + write_set.dstBinding = kMagicSubpassInputBinding; + write_set.descriptorCount = 1u; + write_set.descriptorType = vk::DescriptorType::eInputAttachment; + write_set.pImageInfo = &image_workspace[image_offset - 1]; + + write_workspace[write_offset++] = write_set; + } + + context.GetDevice().updateDescriptorSets(write_offset, write_workspace.data(), + 0u, {}); + + return descriptor_set; +} + fml::StatusOr AllocateAndBindDescriptorSets( const ContextVK& context, const std::shared_ptr& encoder, diff --git a/impeller/renderer/backend/vulkan/binding_helpers_vk.h b/impeller/renderer/backend/vulkan/binding_helpers_vk.h index be35567a77e3b..1dc7f32d2a4b6 100644 --- a/impeller/renderer/backend/vulkan/binding_helpers_vk.h +++ b/impeller/renderer/backend/vulkan/binding_helpers_vk.h @@ -17,6 +17,17 @@ namespace impeller { // backend to avoid dynamic heap allocations. static constexpr size_t kMaxBindings = 32; +fml::StatusOr AllocateAndBindDescriptorSets( + const ContextVK& context, + const std::shared_ptr& encoder, + Allocator& allocator, + const Command& command, + const TextureVK& input_attachment, + std::array& image_workspace, + std::array& buffer_workspace, + std::array& + write_workspace); + fml::StatusOr AllocateAndBindDescriptorSets( const ContextVK& context, const std::shared_ptr& encoder, diff --git a/impeller/renderer/backend/vulkan/command_buffer_vk.cc b/impeller/renderer/backend/vulkan/command_buffer_vk.cc index 6b7b14f243fdb..78eb547847082 100644 --- a/impeller/renderer/backend/vulkan/command_buffer_vk.cc +++ b/impeller/renderer/backend/vulkan/command_buffer_vk.cc @@ -7,10 +7,13 @@ #include #include +#include "flutter/fml/logging.h" +#include "impeller/base/validation.h" #include "impeller/renderer/backend/vulkan/blit_pass_vk.h" #include "impeller/renderer/backend/vulkan/command_encoder_vk.h" #include "impeller/renderer/backend/vulkan/compute_pass_vk.h" #include "impeller/renderer/backend/vulkan/context_vk.h" +#include "impeller/renderer/backend/vulkan/formats_vk.h" #include "impeller/renderer/backend/vulkan/render_pass_vk.h" #include "impeller/renderer/command_buffer.h" #include "impeller/renderer/render_target.h" @@ -70,9 +73,9 @@ std::shared_ptr CommandBufferVK::OnCreateRenderPass( return nullptr; } auto pass = - std::shared_ptr(new RenderPassVK(context, // - target, // - shared_from_this() // + std::shared_ptr(new RenderPassVK(context, // + target, // + weak_from_this() // )); if (!pass->IsValid()) { return nullptr; diff --git a/impeller/renderer/backend/vulkan/command_buffer_vk.h b/impeller/renderer/backend/vulkan/command_buffer_vk.h index d85ce290082a8..b1ede05b724f0 100644 --- a/impeller/renderer/backend/vulkan/command_buffer_vk.h +++ b/impeller/renderer/backend/vulkan/command_buffer_vk.h @@ -5,6 +5,7 @@ #ifndef FLUTTER_IMPELLER_RENDERER_BACKEND_VULKAN_COMMAND_BUFFER_VK_H_ #define FLUTTER_IMPELLER_RENDERER_BACKEND_VULKAN_COMMAND_BUFFER_VK_H_ +#include "flutter/fml/macros.h" #include "impeller/base/backend_cast.h" #include "impeller/renderer/backend/vulkan/vk.h" #include "impeller/renderer/command_buffer.h" diff --git a/impeller/renderer/backend/vulkan/gpu_tracer_vk.cc b/impeller/renderer/backend/vulkan/gpu_tracer_vk.cc index 4867c9626c941..921677408697c 100644 --- a/impeller/renderer/backend/vulkan/gpu_tracer_vk.cc +++ b/impeller/renderer/backend/vulkan/gpu_tracer_vk.cc @@ -8,7 +8,6 @@ #include #include #include - #include "fml/logging.h" #include "fml/trace_event.h" #include "impeller/base/validation.h" @@ -31,7 +30,7 @@ GPUTracerVK::GPUTracerVK(const std::shared_ptr& device_holder) // Disable tracing in release mode. #ifdef IMPELLER_DEBUG enabled_ = true; -#endif // IMPELLER_DEBUG +#endif } bool GPUTracerVK::IsEnabled() const { @@ -106,14 +105,16 @@ void GPUTracerVK::RecordCmdBufferStart(const vk::CommandBuffer& buffer, trace_states_[current_state_].query_pool.get(), state.current_index); state.current_index += 1; - probe.index_ = current_state_; - state.pending_buffers += 1; + if (!probe.index_.has_value()) { + state.pending_buffers += 1; + probe.index_ = current_state_; + } } void GPUTracerVK::RecordCmdBufferEnd(const vk::CommandBuffer& buffer, GPUProbe& probe) { if (!enabled_ || std::this_thread::get_id() != raster_thread_id_ || - !in_frame_ || !probe.index_.has_value()) { + !in_frame_) { return; } Lock lock(trace_state_mutex_); @@ -127,6 +128,10 @@ void GPUTracerVK::RecordCmdBufferEnd(const vk::CommandBuffer& buffer, state.query_pool.get(), state.current_index); state.current_index += 1; + if (!probe.index_.has_value()) { + state.pending_buffers += 1; + probe.index_ = current_state_; + } } void GPUTracerVK::OnFenceComplete(size_t frame_index) { diff --git a/impeller/renderer/backend/vulkan/render_pass_vk.cc b/impeller/renderer/backend/vulkan/render_pass_vk.cc index dc40fc6b70b67..ef2fbff69ecfc 100644 --- a/impeller/renderer/backend/vulkan/render_pass_vk.cc +++ b/impeller/renderer/backend/vulkan/render_pass_vk.cc @@ -8,11 +8,10 @@ #include #include -#include "fml/status.h" +#include "flutter/fml/trace_event.h" #include "impeller/base/validation.h" #include "impeller/core/device_buffer.h" #include "impeller/core/formats.h" -#include "impeller/core/texture.h" #include "impeller/renderer/backend/vulkan/barrier_vk.h" #include "impeller/renderer/backend/vulkan/binding_helpers_vk.h" #include "impeller/renderer/backend/vulkan/command_buffer_vk.h" @@ -21,63 +20,15 @@ #include "impeller/renderer/backend/vulkan/device_buffer_vk.h" #include "impeller/renderer/backend/vulkan/formats_vk.h" #include "impeller/renderer/backend/vulkan/pipeline_vk.h" -#include "impeller/renderer/backend/vulkan/sampler_vk.h" #include "impeller/renderer/backend/vulkan/shared_object_vk.h" #include "impeller/renderer/backend/vulkan/texture_vk.h" - +#include "impeller/renderer/command.h" #include "vulkan/vulkan_enums.hpp" #include "vulkan/vulkan_handles.hpp" #include "vulkan/vulkan_to_string.hpp" namespace impeller { -// Warning: if any of the constant values or layouts are changed in the -// framebuffer fetch shader, then this input binding may need to be -// manually changed. -static constexpr size_t kMagicSubpassInputBinding = 64; - -static vk::ClearColorValue VKClearValueFromColor(Color color) { - vk::ClearColorValue value; - value.setFloat32( - std::array{color.red, color.green, color.blue, color.alpha}); - return value; -} - -static vk::ClearDepthStencilValue VKClearValueFromDepthStencil(uint32_t stencil, - Scalar depth) { - vk::ClearDepthStencilValue value; - value.depth = depth; - value.stencil = stencil; - return value; -} - -static std::vector GetVKClearValues( - const RenderTarget& target) { - std::vector clears; - - for (const auto& [_, color] : target.GetColorAttachments()) { - clears.emplace_back(VKClearValueFromColor(color.clear_color)); - if (color.resolve_texture) { - clears.emplace_back(VKClearValueFromColor(color.clear_color)); - } - } - - const auto& depth = target.GetDepthAttachment(); - const auto& stencil = target.GetStencilAttachment(); - - if (depth.has_value()) { - clears.emplace_back(VKClearValueFromDepthStencil( - stencil ? stencil->clear_stencil : 0u, depth->clear_depth)); - } - - if (stencil.has_value()) { - clears.emplace_back(VKClearValueFromDepthStencil( - stencil->clear_stencil, depth ? depth->clear_depth : 0.0f)); - } - - return clears; -} - static vk::AttachmentDescription CreateAttachmentDescription( const Attachment& attachment, const std::shared_ptr Attachment::*texture_ptr, @@ -248,76 +199,8 @@ SharedHandleVK RenderPassVK::CreateVKRenderPass( RenderPassVK::RenderPassVK(const std::shared_ptr& context, const RenderTarget& target, - std::shared_ptr command_buffer) + std::weak_ptr command_buffer) : RenderPass(context, target), command_buffer_(std::move(command_buffer)) { - const auto& vk_context = ContextVK::Cast(*context); - const std::shared_ptr& encoder = - command_buffer_->GetEncoder(); - command_buffer_vk_ = encoder->GetCommandBuffer(); - render_target_.IterateAllAttachments( - [&encoder](const auto& attachment) -> bool { - encoder->Track(attachment.texture); - encoder->Track(attachment.resolve_texture); - return true; - }); - - const auto& target_size = render_target_.GetRenderTargetSize(); - - SharedHandleVK render_pass = CreateVKRenderPass( - vk_context, command_buffer_, - vk_context.GetCapabilities()->SupportsFramebufferFetch()); - if (!render_pass) { - VALIDATION_LOG << "Could not create renderpass."; - is_valid_ = false; - return; - } - - auto framebuffer = CreateVKFramebuffer(vk_context, *render_pass); - if (!framebuffer) { - VALIDATION_LOG << "Could not create framebuffer."; - is_valid_ = false; - return; - } - - if (!encoder->Track(framebuffer) || !encoder->Track(render_pass)) { - is_valid_ = false; - return; - } - - auto clear_values = GetVKClearValues(render_target_); - - vk::RenderPassBeginInfo pass_info; - pass_info.renderPass = *render_pass; - pass_info.framebuffer = *framebuffer; - pass_info.renderArea.extent.width = static_cast(target_size.width); - pass_info.renderArea.extent.height = - static_cast(target_size.height); - pass_info.setClearValues(clear_values); - - command_buffer_vk_.beginRenderPass(pass_info, vk::SubpassContents::eInline); - - // Set the initial viewport and scissors. - const auto vp = Viewport{.rect = Rect::MakeSize(target_size)}; - vk::Viewport viewport = vk::Viewport() - .setWidth(vp.rect.GetWidth()) - .setHeight(-vp.rect.GetHeight()) - .setY(vp.rect.GetHeight()) - .setMinDepth(0.0f) - .setMaxDepth(1.0f); - command_buffer_vk_.setViewport(0, 1, &viewport); - - // Set the initial scissor rect. - const auto sc = IRect::MakeSize(target_size); - vk::Rect2D scissor = - vk::Rect2D() - .setOffset(vk::Offset2D(sc.GetX(), sc.GetY())) - .setExtent(vk::Extent2D(sc.GetWidth(), sc.GetHeight())); - command_buffer_vk_.setScissor(0, 1, &scissor); - - color_image_vk_ = - render_target_.GetColorAttachments().find(0u)->second.texture; - resolve_image_vk_ = - render_target_.GetColorAttachments().find(0u)->second.resolve_texture; is_valid_ = true; } @@ -331,6 +214,48 @@ void RenderPassVK::OnSetLabel(std::string label) { debug_label_ = std::move(label); } +static vk::ClearColorValue VKClearValueFromColor(Color color) { + vk::ClearColorValue value; + value.setFloat32( + std::array{color.red, color.green, color.blue, color.alpha}); + return value; +} + +static vk::ClearDepthStencilValue VKClearValueFromDepthStencil(uint32_t stencil, + Scalar depth) { + vk::ClearDepthStencilValue value; + value.depth = depth; + value.stencil = stencil; + return value; +} + +static std::vector GetVKClearValues( + const RenderTarget& target) { + std::vector clears; + + for (const auto& [_, color] : target.GetColorAttachments()) { + clears.emplace_back(VKClearValueFromColor(color.clear_color)); + if (color.resolve_texture) { + clears.emplace_back(VKClearValueFromColor(color.clear_color)); + } + } + + const auto& depth = target.GetDepthAttachment(); + const auto& stencil = target.GetStencilAttachment(); + + if (depth.has_value()) { + clears.emplace_back(VKClearValueFromDepthStencil( + stencil ? stencil->clear_stencil : 0u, depth->clear_depth)); + } + + if (stencil.has_value()) { + clears.emplace_back(VKClearValueFromDepthStencil( + stencil->clear_stencil, depth ? depth->clear_depth : 0.0f)); + } + + return clears; +} + SharedHandleVK RenderPassVK::CreateVKFramebuffer( const ContextVK& context, const vk::RenderPass& pass) const { @@ -377,114 +302,134 @@ SharedHandleVK RenderPassVK::CreateVKFramebuffer( return MakeSharedVK(std::move(framebuffer)); } -// |RenderPass| -void RenderPassVK::SetPipeline( - const std::shared_ptr>& pipeline) { - PipelineVK& pipeline_vk = PipelineVK::Cast(*pipeline); - - auto descriptor_result = - command_buffer_->GetEncoder()->AllocateDescriptorSets( - pipeline_vk.GetDescriptorSetLayout(), ContextVK::Cast(*context_)); - if (!descriptor_result.ok()) { - return; +static bool UpdateBindingLayouts(const Bindings& bindings, + const vk::CommandBuffer& buffer) { + // All previous writes via a render or blit pass must be done before another + // shader attempts to read the resource. + BarrierVK barrier; + barrier.cmd_buffer = buffer; + barrier.src_access = vk::AccessFlagBits::eColorAttachmentWrite | + vk::AccessFlagBits::eTransferWrite; + barrier.src_stage = vk::PipelineStageFlagBits::eColorAttachmentOutput | + vk::PipelineStageFlagBits::eTransfer; + barrier.dst_access = vk::AccessFlagBits::eShaderRead; + barrier.dst_stage = vk::PipelineStageFlagBits::eFragmentShader; + + barrier.new_layout = vk::ImageLayout::eShaderReadOnlyOptimal; + + for (const TextureAndSampler& data : bindings.sampled_images) { + if (!TextureVK::Cast(*data.texture.resource).SetLayout(barrier)) { + return false; + } } - pipeline_valid_ = true; - descriptor_set_ = descriptor_result.value(); - pipeline_layout_ = pipeline_vk.GetPipelineLayout(); - command_buffer_vk_.bindPipeline(vk::PipelineBindPoint::eGraphics, - pipeline_vk.GetPipeline()); + return true; +} - if (pipeline->GetDescriptor().UsesSubpassInput()) { - if (bound_image_offset_ >= kMaxBindings) { - pipeline_valid_ = false; - return; - } +static bool UpdateBindingLayouts(const Command& command, + const vk::CommandBuffer& buffer) { + return UpdateBindingLayouts(command.vertex_bindings, buffer) && + UpdateBindingLayouts(command.fragment_bindings, buffer); +} - vk::DescriptorImageInfo image_info; - image_info.imageLayout = vk::ImageLayout::eGeneral; - image_info.sampler = VK_NULL_HANDLE; - image_info.imageView = TextureVK::Cast(*color_image_vk_).GetImageView(); - image_workspace_[bound_image_offset_++] = image_info; +static bool UpdateBindingLayouts(const std::vector& commands, + const vk::CommandBuffer& buffer) { + for (const Command& command : commands) { + if (!UpdateBindingLayouts(command, buffer)) { + return false; + } + } + return true; +} - vk::WriteDescriptorSet write_set; - write_set.dstBinding = kMagicSubpassInputBinding; - write_set.descriptorCount = 1u; - write_set.descriptorType = vk::DescriptorType::eInputAttachment; - write_set.pImageInfo = &image_workspace_[bound_image_offset_ - 1]; +static void SetViewportAndScissor(const Command& command, + const vk::CommandBuffer& cmd_buffer, + PassBindingsCache& cmd_buffer_cache, + const ISize& target_size) { + // Set the viewport. + const auto& vp = command.viewport.value_or( + {.rect = Rect::MakeSize(target_size)}); + vk::Viewport viewport = vk::Viewport() + .setWidth(vp.rect.GetWidth()) + .setHeight(-vp.rect.GetHeight()) + .setY(vp.rect.GetHeight()) + .setMinDepth(0.0f) + .setMaxDepth(1.0f); + cmd_buffer_cache.SetViewport(cmd_buffer, 0, 1, &viewport); - write_workspace_[descriptor_write_offset_++] = write_set; - } + // Set the scissor rect. + const auto& sc = command.scissor.value_or(IRect::MakeSize(target_size)); + vk::Rect2D scissor = + vk::Rect2D() + .setOffset(vk::Offset2D(sc.GetX(), sc.GetY())) + .setExtent(vk::Extent2D(sc.GetWidth(), sc.GetHeight())); + cmd_buffer_cache.SetScissor(cmd_buffer, 0, 1, &scissor); } -// |RenderPass| -void RenderPassVK::SetCommandLabel(std::string_view label) { +static bool EncodeCommand(const Context& context, + const Command& command, + CommandEncoderVK& encoder, + PassBindingsCache& command_buffer_cache, + const ISize& target_size, + const vk::DescriptorSet vk_desc_set, + const vk::CommandBuffer& cmd_buffer) { #ifdef IMPELLER_DEBUG - std::string label_copy(label); - command_buffer_->GetEncoder()->PushDebugGroup(label_copy.c_str()); - has_label_ = true; + fml::ScopedCleanupClosure pop_marker( + [&encoder]() { encoder.PopDebugGroup(); }); + if (!command.label.empty()) { + encoder.PushDebugGroup(command.label.c_str()); + } else { + pop_marker.Release(); + } #endif // IMPELLER_DEBUG -} -// |RenderPass| -void RenderPassVK::SetStencilReference(uint32_t value) { - command_buffer_vk_.setStencilReference( - vk::StencilFaceFlagBits::eVkStencilFrontAndBack, value); -} + const PipelineVK& pipeline_vk = PipelineVK::Cast(*command.pipeline); -// |RenderPass| -void RenderPassVK::SetBaseVertex(uint64_t value) { - base_vertex_ = value; -} + cmd_buffer.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, // bind point + pipeline_vk.GetPipelineLayout(), // layout + 0, // first set + 1, // set count + &vk_desc_set, // sets + 0, // offset count + nullptr // offsets + ); -// |RenderPass| -void RenderPassVK::SetViewport(Viewport viewport) { - vk::Viewport viewport_vk = vk::Viewport() - .setWidth(viewport.rect.GetWidth()) - .setHeight(-viewport.rect.GetHeight()) - .setY(viewport.rect.GetHeight()) - .setMinDepth(0.0f) - .setMaxDepth(1.0f); - command_buffer_vk_.setViewport(0, 1, &viewport_vk); -} + command_buffer_cache.BindPipeline( + cmd_buffer, vk::PipelineBindPoint::eGraphics, pipeline_vk.GetPipeline()); -// |RenderPass| -void RenderPassVK::SetScissor(IRect scissor) { - vk::Rect2D scissor_vk = - vk::Rect2D() - .setOffset(vk::Offset2D(scissor.GetX(), scissor.GetY())) - .setExtent(vk::Extent2D(scissor.GetWidth(), scissor.GetHeight())); - command_buffer_vk_.setScissor(0, 1, &scissor_vk); -} + // Set the viewport and scissors. + SetViewportAndScissor(command, cmd_buffer, command_buffer_cache, target_size); -// |RenderPass| -void RenderPassVK::SetInstanceCount(size_t count) { - instance_count_ = count; -} + // Set the stencil reference. + command_buffer_cache.SetStencilReference( + cmd_buffer, vk::StencilFaceFlagBits::eVkStencilFrontAndBack, + command.stencil_reference); -// |RenderPass| -bool RenderPassVK::SetVertexBuffer(VertexBuffer buffer) { - vertex_count_ = buffer.vertex_count; - if (buffer.index_type == IndexType::kUnknown) { + // Configure vertex and index and buffers for binding. + if (!command.vertex_buffer.vertex_buffer) { + VALIDATION_LOG << "Failed to acquire device buffer" + << " for vertex buffer view"; return false; } - if (!command_buffer_->GetEncoder()->Track(buffer.vertex_buffer.buffer)) { + auto& allocator = *context.GetResourceAllocator(); + const std::shared_ptr& vertex_buffer = + command.vertex_buffer.vertex_buffer.buffer; + + if (!encoder.Track(vertex_buffer)) { return false; } // Bind the vertex buffer. vk::Buffer vertex_buffer_handle = - DeviceBufferVK::Cast(*buffer.vertex_buffer.buffer).GetBuffer(); + DeviceBufferVK::Cast(*vertex_buffer).GetBuffer(); vk::Buffer vertex_buffers[] = {vertex_buffer_handle}; - vk::DeviceSize vertex_buffer_offsets[] = {buffer.vertex_buffer.range.offset}; + vk::DeviceSize vertex_buffer_offsets[] = { + command.vertex_buffer.vertex_buffer.range.offset}; + cmd_buffer.bindVertexBuffers(0u, 1u, vertex_buffers, vertex_buffer_offsets); - command_buffer_vk_.bindVertexBuffers(0u, 1u, vertex_buffers, - vertex_buffer_offsets); - - // Bind the index buffer. - if (buffer.index_type != IndexType::kNone) { - has_index_buffer_ = true; - const BufferView& index_buffer_view = buffer.index_buffer; + if (command.vertex_buffer.index_type != IndexType::kNone) { + // Bind the index buffer. + const BufferView& index_buffer_view = command.vertex_buffer.index_buffer; if (!index_buffer_view) { return false; } @@ -497,187 +442,128 @@ bool RenderPassVK::SetVertexBuffer(VertexBuffer buffer) { return false; } - if (!command_buffer_->GetEncoder()->Track(index_buffer)) { + if (!encoder.Track(index_buffer)) { return false; } vk::Buffer index_buffer_handle = DeviceBufferVK::Cast(*index_buffer).GetBuffer(); - command_buffer_vk_.bindIndexBuffer(index_buffer_handle, - index_buffer_view.range.offset, - ToVKIndexType(buffer.index_type)); + cmd_buffer.bindIndexBuffer(index_buffer_handle, + index_buffer_view.range.offset, + ToVKIndexType(command.vertex_buffer.index_type)); + + // Engage! + cmd_buffer.drawIndexed(command.vertex_buffer.vertex_count, // index count + command.instance_count, // instance count + 0u, // first index + command.base_vertex, // vertex offset + 0u // first instance + ); } else { - has_index_buffer_ = false; + cmd_buffer.draw(command.vertex_buffer.vertex_count, // vertex count + command.instance_count, // instance count + command.base_vertex, // vertex offset + 0u // first instance + ); } return true; } -// |RenderPass| -fml::Status RenderPassVK::Draw() { - if (!pipeline_valid_) { - return fml::Status(fml::StatusCode::kCancelled, - "No valid pipeline is bound to the RenderPass."); - } - - const ContextVK& context_vk = ContextVK::Cast(*context_); - for (auto i = 0u; i < descriptor_write_offset_; i++) { - write_workspace_[i].dstSet = descriptor_set_; +bool RenderPassVK::OnEncodeCommands(const Context& context) const { + TRACE_EVENT0("impeller", "RenderPassVK::OnEncodeCommands"); + if (!IsValid()) { + return false; } - context_vk.GetDevice().updateDescriptorSets(descriptor_write_offset_, - write_workspace_.data(), 0u, {}); - - command_buffer_vk_.bindDescriptorSets( - vk::PipelineBindPoint::eGraphics, // bind point - pipeline_layout_, // layout - 0, // first set - 1, // set count - &descriptor_set_, // sets - 0, // offset count - nullptr // offsets - ); + const auto& vk_context = ContextVK::Cast(context); - if (has_index_buffer_) { - command_buffer_vk_.drawIndexed(vertex_count_, // index count - instance_count_, // instance count - 0u, // first index - base_vertex_, // vertex offset - 0u // first instance - ); - } else { - command_buffer_vk_.draw(vertex_count_, // vertex count - instance_count_, // instance count - base_vertex_, // vertex offset - 0u // first instance - ); + std::shared_ptr command_buffer = command_buffer_.lock(); + if (!command_buffer) { + VALIDATION_LOG << "Command buffer died before commands could be encoded."; + return false; + } + const std::shared_ptr& encoder = + command_buffer->GetEncoder(); + if (!encoder) { + return false; } #ifdef IMPELLER_DEBUG - if (has_label_) { - command_buffer_->GetEncoder()->PopDebugGroup(); + fml::ScopedCleanupClosure pop_marker( + [&encoder]() { encoder->PopDebugGroup(); }); + if (!debug_label_.empty()) { + encoder->PushDebugGroup(debug_label_.c_str()); + } else { + pop_marker.Release(); } #endif // IMPELLER_DEBUG - has_label_ = false; - has_index_buffer_ = false; - bound_image_offset_ = 0u; - bound_buffer_offset_ = 0u; - descriptor_write_offset_ = 0u; - instance_count_ = 1u; - base_vertex_ = 0u; - vertex_count_ = 0u; - pipeline_valid_ = false; - return fml::Status(); -} -// The RenderPassVK binding methods only need the binding, set, and buffer type -// information. -bool RenderPassVK::BindResource(ShaderStage stage, - DescriptorType type, - const ShaderUniformSlot& slot, - const ShaderMetadata& metadata, - BufferView view) { - return BindResource(slot.binding, type, view); -} + vk::CommandBuffer cmd_buffer = encoder->GetCommandBuffer(); -bool RenderPassVK::BindResource( - ShaderStage stage, - DescriptorType type, - const ShaderUniformSlot& slot, - const std::shared_ptr& metadata, - BufferView view) { - return BindResource(slot.binding, type, view); -} - -bool RenderPassVK::BindResource(size_t binding, - DescriptorType type, - const BufferView& view) { - if (bound_buffer_offset_ >= kMaxBindings) { + if (!UpdateBindingLayouts(commands_, cmd_buffer)) { return false; } - const std::shared_ptr& device_buffer = view.buffer; - auto buffer = DeviceBufferVK::Cast(*device_buffer).GetBuffer(); - if (!buffer) { - return false; - } + render_target_.IterateAllAttachments( + [&encoder](const auto& attachment) -> bool { + encoder->Track(attachment.texture); + encoder->Track(attachment.resolve_texture); + return true; + }); + + const auto& target_size = render_target_.GetRenderTargetSize(); - if (!command_buffer_->GetEncoder()->Track(device_buffer)) { + SharedHandleVK render_pass = CreateVKRenderPass( + vk_context, command_buffer, + vk_context.GetCapabilities()->SupportsFramebufferFetch()); + if (!render_pass) { + VALIDATION_LOG << "Could not create renderpass."; return false; } - uint32_t offset = view.range.offset; - - vk::DescriptorBufferInfo buffer_info; - buffer_info.buffer = buffer; - buffer_info.offset = offset; - buffer_info.range = view.range.length; - buffer_workspace_[bound_buffer_offset_++] = buffer_info; - - vk::WriteDescriptorSet write_set; - write_set.dstBinding = binding; - write_set.descriptorCount = 1u; - write_set.descriptorType = ToVKDescriptorType(type); - write_set.pBufferInfo = &buffer_workspace_[bound_buffer_offset_ - 1]; - - write_workspace_[descriptor_write_offset_++] = write_set; - return true; -} - -bool RenderPassVK::BindResource(ShaderStage stage, - DescriptorType type, - const SampledImageSlot& slot, - const ShaderMetadata& metadata, - std::shared_ptr texture, - std::shared_ptr sampler) { - if (bound_buffer_offset_ >= kMaxBindings) { + auto framebuffer = CreateVKFramebuffer(vk_context, *render_pass); + if (!framebuffer) { + VALIDATION_LOG << "Could not create framebuffer."; return false; } - const TextureVK& texture_vk = TextureVK::Cast(*texture); - const SamplerVK& sampler_vk = SamplerVK::Cast(*sampler); - if (!command_buffer_->GetEncoder()->Track(texture) || - !command_buffer_->GetEncoder()->Track(sampler_vk.GetSharedSampler())) { + if (!encoder->Track(framebuffer) || !encoder->Track(render_pass)) { return false; } - vk::DescriptorImageInfo image_info; - image_info.imageLayout = vk::ImageLayout::eShaderReadOnlyOptimal; - image_info.sampler = sampler_vk.GetSampler(); - image_info.imageView = texture_vk.GetImageView(); - image_workspace_[bound_image_offset_++] = image_info; - - vk::WriteDescriptorSet write_set; - write_set.dstBinding = slot.binding; - write_set.descriptorCount = 1u; - write_set.descriptorType = vk::DescriptorType::eCombinedImageSampler; - write_set.pImageInfo = &image_workspace_[bound_image_offset_ - 1]; - - write_workspace_[descriptor_write_offset_++] = write_set; - return true; -} - -bool RenderPassVK::OnEncodeCommands(const Context& context) const { - command_buffer_->GetEncoder()->GetCommandBuffer().endRenderPass(); - - // If this render target will be consumed by a subsequent render pass, - // perform a layout transition to a shader read state. - const std::shared_ptr& result_texture = - resolve_image_vk_ ? resolve_image_vk_ : color_image_vk_; - if (result_texture->GetTextureDescriptor().usage & - static_cast(TextureUsage::kShaderRead)) { - BarrierVK barrier; - barrier.cmd_buffer = command_buffer_vk_; - barrier.src_access = vk::AccessFlagBits::eColorAttachmentWrite | - vk::AccessFlagBits::eTransferWrite; - barrier.src_stage = vk::PipelineStageFlagBits::eColorAttachmentOutput | - vk::PipelineStageFlagBits::eTransfer; - barrier.dst_access = vk::AccessFlagBits::eShaderRead; - barrier.dst_stage = vk::PipelineStageFlagBits::eFragmentShader; + auto clear_values = GetVKClearValues(render_target_); - barrier.new_layout = vk::ImageLayout::eShaderReadOnlyOptimal; + vk::RenderPassBeginInfo pass_info; + pass_info.renderPass = *render_pass; + pass_info.framebuffer = *framebuffer; + pass_info.renderArea.extent.width = static_cast(target_size.width); + pass_info.renderArea.extent.height = + static_cast(target_size.height); + pass_info.setClearValues(clear_values); - if (!TextureVK::Cast(*result_texture).SetLayout(barrier)) { - return false; + const TextureVK& color_image_vk = TextureVK::Cast( + *render_target_.GetColorAttachments().find(0u)->second.texture); + Allocator& allocator = *context.GetResourceAllocator(); + + { + TRACE_EVENT0("impeller", "EncodeRenderPassCommands"); + cmd_buffer.beginRenderPass(pass_info, vk::SubpassContents::eInline); + + fml::ScopedCleanupClosure end_render_pass( + [cmd_buffer]() { cmd_buffer.endRenderPass(); }); + + for (const auto& command : commands_) { + fml::StatusOr desc_set_result = + AllocateAndBindDescriptorSets(vk_context, encoder, allocator, command, + color_image_vk, image_workspace_, + buffer_workspace_, write_workspace_); + if (!desc_set_result.ok()) { + return false; + } + if (!EncodeCommand(context, command, *encoder, pass_bindings_cache_, + target_size, desc_set_result.value(), cmd_buffer)) { + return false; + } } } diff --git a/impeller/renderer/backend/vulkan/render_pass_vk.h b/impeller/renderer/backend/vulkan/render_pass_vk.h index 26c635c41c6fe..2d31abd4019f6 100644 --- a/impeller/renderer/backend/vulkan/render_pass_vk.h +++ b/impeller/renderer/backend/vulkan/render_pass_vk.h @@ -5,10 +5,10 @@ #ifndef FLUTTER_IMPELLER_RENDERER_BACKEND_VULKAN_RENDER_PASS_VK_H_ #define FLUTTER_IMPELLER_RENDERER_BACKEND_VULKAN_RENDER_PASS_VK_H_ -#include "impeller/core/buffer_view.h" +#include "flutter/fml/macros.h" #include "impeller/renderer/backend/vulkan/binding_helpers_vk.h" #include "impeller/renderer/backend/vulkan/context_vk.h" -#include "impeller/renderer/backend/vulkan/pipeline_vk.h" +#include "impeller/renderer/backend/vulkan/pass_bindings_cache.h" #include "impeller/renderer/backend/vulkan/shared_object_vk.h" #include "impeller/renderer/render_pass.h" #include "impeller/renderer/render_target.h" @@ -25,92 +25,20 @@ class RenderPassVK final : public RenderPass { private: friend class CommandBufferVK; - std::shared_ptr command_buffer_; + std::weak_ptr command_buffer_; std::string debug_label_; bool is_valid_ = false; - vk::CommandBuffer command_buffer_vk_; - std::shared_ptr color_image_vk_; - std::shared_ptr resolve_image_vk_; - - // Per-command state. - std::array image_workspace_; - std::array buffer_workspace_; - std::array + mutable std::array image_workspace_; + mutable std::array buffer_workspace_; + mutable std::array write_workspace_; - size_t bound_image_offset_ = 0u; - size_t bound_buffer_offset_ = 0u; - size_t descriptor_write_offset_ = 0u; - size_t instance_count_ = 1u; - size_t base_vertex_ = 0u; - size_t vertex_count_ = 0u; - bool has_index_buffer_ = false; - bool has_label_ = false; - bool pipeline_valid_ = false; - vk::Pipeline last_pipeline_; - vk::DescriptorSet descriptor_set_ = {}; - vk::PipelineLayout pipeline_layout_ = {}; + + mutable PassBindingsCache pass_bindings_cache_; RenderPassVK(const std::shared_ptr& context, const RenderTarget& target, - std::shared_ptr command_buffer); - - // |RenderPass| - void SetPipeline( - const std::shared_ptr>& pipeline) override; - - // |RenderPass| - void SetCommandLabel(std::string_view label) override; - - // |RenderPass| - void SetStencilReference(uint32_t value) override; - - // |RenderPass| - void SetBaseVertex(uint64_t value) override; - - // |RenderPass| - void SetViewport(Viewport viewport) override; - - // |RenderPass| - void SetScissor(IRect scissor) override; - - // |RenderPass| - void SetInstanceCount(size_t count) override; - - // |RenderPass| - bool SetVertexBuffer(VertexBuffer buffer) override; - - // |RenderPass| - fml::Status Draw() override; - - // |RenderPass| - void ReserveCommands(size_t command_count) override {} - - // |ResourceBinder| - bool BindResource(ShaderStage stage, - DescriptorType type, - const ShaderUniformSlot& slot, - const ShaderMetadata& metadata, - BufferView view) override; - - // |RenderPass| - bool BindResource(ShaderStage stage, - DescriptorType type, - const ShaderUniformSlot& slot, - const std::shared_ptr& metadata, - BufferView view) override; - - // |ResourceBinder| - bool BindResource(ShaderStage stage, - DescriptorType type, - const SampledImageSlot& slot, - const ShaderMetadata& metadata, - std::shared_ptr texture, - std::shared_ptr sampler) override; - - bool BindResource(size_t binding, - DescriptorType type, - const BufferView& view); + std::weak_ptr command_buffer); // |RenderPass| bool IsValid() const override; diff --git a/impeller/renderer/backend/vulkan/texture_vk.cc b/impeller/renderer/backend/vulkan/texture_vk.cc index 36f5d3878fe91..cbe525400c303 100644 --- a/impeller/renderer/backend/vulkan/texture_vk.cc +++ b/impeller/renderer/backend/vulkan/texture_vk.cc @@ -107,24 +107,6 @@ bool TextureVK::OnSetContents(const uint8_t* contents, © // regions ); - // Transition to shader-read. - { - BarrierVK barrier; - barrier.cmd_buffer = vk_cmd_buffer; - barrier.src_access = vk::AccessFlagBits::eColorAttachmentWrite | - vk::AccessFlagBits::eTransferWrite; - barrier.src_stage = vk::PipelineStageFlagBits::eColorAttachmentOutput | - vk::PipelineStageFlagBits::eTransfer; - barrier.dst_access = vk::AccessFlagBits::eShaderRead; - barrier.dst_stage = vk::PipelineStageFlagBits::eFragmentShader; - - barrier.new_layout = vk::ImageLayout::eShaderReadOnlyOptimal; - - if (!SetLayout(barrier)) { - return false; - } - } - return cmd_buffer->SubmitCommands(); } diff --git a/impeller/renderer/command.cc b/impeller/renderer/command.cc index 6507c81d565c0..40dfd8c09d518 100644 --- a/impeller/renderer/command.cc +++ b/impeller/renderer/command.cc @@ -23,7 +23,6 @@ bool Command::BindVertices(VertexBuffer buffer) { } bool Command::BindResource(ShaderStage stage, - DescriptorType type, const ShaderUniformSlot& slot, const ShaderMetadata& metadata, BufferView view) { @@ -32,7 +31,6 @@ bool Command::BindResource(ShaderStage stage, bool Command::BindResource( ShaderStage stage, - DescriptorType type, const ShaderUniformSlot& slot, const std::shared_ptr& metadata, BufferView view) { @@ -68,7 +66,6 @@ bool Command::DoBindResource(ShaderStage stage, } bool Command::BindResource(ShaderStage stage, - DescriptorType type, const SampledImageSlot& slot, const ShaderMetadata& metadata, std::shared_ptr texture, diff --git a/impeller/renderer/command.h b/impeller/renderer/command.h index 0df30895b7959..0e27d74750a71 100644 --- a/impeller/renderer/command.h +++ b/impeller/renderer/command.h @@ -162,20 +162,17 @@ struct Command : public ResourceBinder { // |ResourceBinder| bool BindResource(ShaderStage stage, - DescriptorType type, const ShaderUniformSlot& slot, const ShaderMetadata& metadata, BufferView view) override; bool BindResource(ShaderStage stage, - DescriptorType type, const ShaderUniformSlot& slot, const std::shared_ptr& metadata, BufferView view); // |ResourceBinder| bool BindResource(ShaderStage stage, - DescriptorType type, const SampledImageSlot& slot, const ShaderMetadata& metadata, std::shared_ptr texture, diff --git a/impeller/renderer/command_buffer.cc b/impeller/renderer/command_buffer.cc index b25ab3af000ff..98b23204604b1 100644 --- a/impeller/renderer/command_buffer.cc +++ b/impeller/renderer/command_buffer.cc @@ -38,6 +38,7 @@ void CommandBuffer::WaitUntilScheduled() { bool CommandBuffer::EncodeAndSubmit( const std::shared_ptr& render_pass) { + TRACE_EVENT0("impeller", "CommandBuffer::EncodeAndSubmit"); if (!render_pass->IsValid() || !IsValid()) { return false; } @@ -51,6 +52,7 @@ bool CommandBuffer::EncodeAndSubmit( bool CommandBuffer::EncodeAndSubmit( const std::shared_ptr& blit_pass, const std::shared_ptr& allocator) { + TRACE_EVENT0("impeller", "CommandBuffer::EncodeAndSubmit"); if (!blit_pass->IsValid() || !IsValid()) { return false; } diff --git a/impeller/renderer/compute_command.cc b/impeller/renderer/compute_command.cc index e1a06015fa611..fbbfe3b58666f 100644 --- a/impeller/renderer/compute_command.cc +++ b/impeller/renderer/compute_command.cc @@ -8,12 +8,10 @@ #include "impeller/base/validation.h" #include "impeller/core/formats.h" -#include "impeller/core/shader_types.h" namespace impeller { bool ComputeCommand::BindResource(ShaderStage stage, - DescriptorType type, const ShaderUniformSlot& slot, const ShaderMetadata& metadata, BufferView view) { @@ -31,7 +29,6 @@ bool ComputeCommand::BindResource(ShaderStage stage, } bool ComputeCommand::BindResource(ShaderStage stage, - DescriptorType type, const SampledImageSlot& slot, const ShaderMetadata& metadata, std::shared_ptr texture, diff --git a/impeller/renderer/compute_command.h b/impeller/renderer/compute_command.h index c0c56e9f698f6..fb2639df664e8 100644 --- a/impeller/renderer/compute_command.h +++ b/impeller/renderer/compute_command.h @@ -53,14 +53,12 @@ struct ComputeCommand : public ResourceBinder { // |ResourceBinder| bool BindResource(ShaderStage stage, - DescriptorType type, const ShaderUniformSlot& slot, const ShaderMetadata& metadata, BufferView view) override; // |ResourceBinder| bool BindResource(ShaderStage stage, - DescriptorType type, const SampledImageSlot& slot, const ShaderMetadata& metadata, std::shared_ptr texture, diff --git a/impeller/renderer/render_pass.cc b/impeller/renderer/render_pass.cc index 8c3998d8720af..10c5a16556117 100644 --- a/impeller/renderer/render_pass.cc +++ b/impeller/renderer/render_pass.cc @@ -7,7 +7,7 @@ namespace impeller { -RenderPass::RenderPass(std::shared_ptr context, +RenderPass::RenderPass(std::weak_ptr context, const RenderTarget& target) : context_(std::move(context)), sample_count_(target.GetSampleCount()), @@ -77,10 +77,15 @@ bool RenderPass::AddCommand(Command&& command) { } bool RenderPass::EncodeCommands() const { - return OnEncodeCommands(*context_); + auto context = context_.lock(); + // The context could have been collected in the meantime. + if (!context) { + return false; + } + return OnEncodeCommands(*context); } -const std::shared_ptr& RenderPass::GetContext() const { +const std::weak_ptr& RenderPass::GetContext() const { return context_; } @@ -131,30 +136,27 @@ fml::Status RenderPass::Draw() { // |ResourceBinder| bool RenderPass::BindResource(ShaderStage stage, - DescriptorType type, const ShaderUniformSlot& slot, const ShaderMetadata& metadata, BufferView view) { - return pending_.BindResource(stage, type, slot, metadata, view); + return pending_.BindResource(stage, slot, metadata, view); } bool RenderPass::BindResource( ShaderStage stage, - DescriptorType type, const ShaderUniformSlot& slot, const std::shared_ptr& metadata, BufferView view) { - return pending_.BindResource(stage, type, slot, metadata, std::move(view)); + return pending_.BindResource(stage, slot, metadata, std::move(view)); } // |ResourceBinder| bool RenderPass::BindResource(ShaderStage stage, - DescriptorType type, const SampledImageSlot& slot, const ShaderMetadata& metadata, std::shared_ptr texture, std::shared_ptr sampler) { - return pending_.BindResource(stage, type, slot, metadata, std::move(texture), + return pending_.BindResource(stage, slot, metadata, std::move(texture), std::move(sampler)); } diff --git a/impeller/renderer/render_pass.h b/impeller/renderer/render_pass.h index cae0fe3046f7d..c2bd755c58f9b 100644 --- a/impeller/renderer/render_pass.h +++ b/impeller/renderer/render_pass.h @@ -34,7 +34,7 @@ class RenderPass : public ResourceBinder { public: virtual ~RenderPass(); - const std::shared_ptr& GetContext() const; + const std::weak_ptr& GetContext() const; const RenderTarget& GetRenderTarget() const; @@ -46,18 +46,21 @@ class RenderPass : public ResourceBinder { void SetLabel(std::string label); - virtual void ReserveCommands(size_t command_count) { + /// @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); } //---------------------------------------------------------------------------- /// The pipeline to use for this command. - virtual void SetPipeline( + void SetPipeline( const std::shared_ptr>& pipeline); //---------------------------------------------------------------------------- /// The debugging label to use for the command. - virtual void SetCommandLabel(std::string_view label); + void SetCommandLabel(std::string_view label); //---------------------------------------------------------------------------- /// The reference value to use in stenciling operations. Stencil configuration @@ -66,9 +69,9 @@ class RenderPass : public ResourceBinder { /// @see `Pipeline` /// @see `PipelineDescriptor` /// - virtual void SetStencilReference(uint32_t value); + void SetStencilReference(uint32_t value); - virtual void SetBaseVertex(uint64_t value); + void SetBaseVertex(uint64_t value); //---------------------------------------------------------------------------- /// The viewport coordinates that the rasterizer linearly maps normalized @@ -76,14 +79,14 @@ class RenderPass : public ResourceBinder { /// If unset, the viewport is the size of the render target with a zero /// origin, znear=0, and zfar=1. /// - virtual void SetViewport(Viewport viewport); + void SetViewport(Viewport viewport); //---------------------------------------------------------------------------- /// The scissor rect to use for clipping writes to the render target. The /// scissor rect must lie entirely within the render target. /// If unset, no scissor is applied. /// - virtual void SetScissor(IRect scissor); + void SetScissor(IRect scissor); //---------------------------------------------------------------------------- /// The number of instances of the given set of vertices to render. Not all @@ -92,7 +95,7 @@ class RenderPass : public ResourceBinder { /// @warning Setting this to more than one will limit the availability of /// backends to use with this command. /// - virtual void SetInstanceCount(size_t count); + void SetInstanceCount(size_t count); //---------------------------------------------------------------------------- /// @brief Specify the vertex and index buffer to use for this command. @@ -102,32 +105,28 @@ class RenderPass : public ResourceBinder { /// /// @return returns if the binding was updated. /// - virtual bool SetVertexBuffer(VertexBuffer buffer); + bool SetVertexBuffer(VertexBuffer buffer); /// Record the currently pending command. - virtual fml::Status Draw(); + fml::Status Draw(); // |ResourceBinder| - virtual bool BindResource(ShaderStage stage, - DescriptorType type, - const ShaderUniformSlot& slot, - const ShaderMetadata& metadata, - BufferView view) override; - - virtual bool BindResource( - ShaderStage stage, - DescriptorType type, - const ShaderUniformSlot& slot, - const std::shared_ptr& metadata, - BufferView view); + bool BindResource(ShaderStage stage, + const ShaderUniformSlot& slot, + const ShaderMetadata& metadata, + BufferView view) override; + + bool BindResource(ShaderStage stage, + const ShaderUniformSlot& slot, + const std::shared_ptr& metadata, + BufferView view); // |ResourceBinder| - virtual bool BindResource(ShaderStage stage, - DescriptorType type, - const SampledImageSlot& slot, - const ShaderMetadata& metadata, - std::shared_ptr texture, - std::shared_ptr sampler) override; + bool BindResource(ShaderStage stage, + const SampledImageSlot& slot, + const ShaderMetadata& metadata, + std::shared_ptr texture, + std::shared_ptr sampler) override; //---------------------------------------------------------------------------- /// @brief Encode the recorded commands to the underlying command buffer. @@ -142,7 +141,7 @@ class RenderPass : public ResourceBinder { /// /// @details Visible for testing. /// - virtual const std::vector& GetCommands() const { return commands_; } + const std::vector& GetCommands() const { return commands_; } //---------------------------------------------------------------------------- /// @brief The sample count of the attached render target. @@ -157,7 +156,7 @@ class RenderPass : public ResourceBinder { bool HasStencilAttachment() const; protected: - const std::shared_ptr context_; + 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 @@ -182,8 +181,7 @@ class RenderPass : public ResourceBinder { /// bool AddCommand(Command&& command); - RenderPass(std::shared_ptr context, - const RenderTarget& target); + RenderPass(std::weak_ptr context, const RenderTarget& target); virtual void OnSetLabel(std::string label) = 0; diff --git a/impeller/renderer/renderer_unittests.cc b/impeller/renderer/renderer_unittests.cc index b01f8ed328c2d..0881fd6c4bd15 100644 --- a/impeller/renderer/renderer_unittests.cc +++ b/impeller/renderer/renderer_unittests.cc @@ -1255,6 +1255,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( + GetContext()->GetResourceAllocator()); + + auto render_target = RenderTarget::CreateOffscreen( + *context, *render_target_cache, {100, 100}, /*mip_count=*/1); + auto render_pass = cmd_buffer->CreateRenderPass(render_target); + + render_pass->ReserveCommands(100u); + + EXPECT_EQ(render_pass->GetCommands().capacity(), 100u); +} + TEST_P(RendererTest, CanLookupRenderTargetProperties) { auto context = GetContext(); auto cmd_buffer = context->CreateCommandBuffer(); diff --git a/impeller/renderer/testing/mocks.h b/impeller/renderer/testing/mocks.h index 2c3b096bda6f7..4960a57ef78fd 100644 --- a/impeller/renderer/testing/mocks.h +++ b/impeller/renderer/testing/mocks.h @@ -92,7 +92,7 @@ class MockBlitPass : public BlitPass { class MockRenderPass : public RenderPass { public: - MockRenderPass(std::shared_ptr context, + MockRenderPass(std::weak_ptr context, const RenderTarget& target) : RenderPass(std::move(context), target) {} MOCK_METHOD(bool, IsValid, (), (const, override)); diff --git a/lib/gpu/render_pass.cc b/lib/gpu/render_pass.cc index 206da54bde4ac..35a43793fb637 100644 --- a/lib/gpu/render_pass.cc +++ b/lib/gpu/render_pass.cc @@ -28,7 +28,7 @@ RenderPass::RenderPass() RenderPass::~RenderPass() = default; -const std::shared_ptr& RenderPass::GetContext() const { +const std::weak_ptr& RenderPass::GetContext() const { return render_pass_->GetContext(); } @@ -115,7 +115,7 @@ RenderPass::GetOrCreatePipeline() { } } - auto& context = *GetContext(); + auto& context = *GetContext().lock(); render_pipeline_->BindToPipelineDescriptor(*context.GetShaderLibrary(), pipeline_desc); @@ -151,27 +151,23 @@ bool RenderPass::Draw() { } render_pass_->SetVertexBuffer(result.vertex_buffer); for (const auto& buffer : result.vertex_bindings.buffers) { - render_pass_->BindResource(impeller::ShaderStage::kVertex, - impeller::DescriptorType::kUniformBuffer, - buffer.slot, *buffer.view.GetMetadata(), + render_pass_->BindResource(impeller::ShaderStage::kVertex, buffer.slot, + *buffer.view.GetMetadata(), buffer.view.resource); } for (const auto& texture : result.vertex_bindings.sampled_images) { - render_pass_->BindResource(impeller::ShaderStage::kVertex, - impeller::DescriptorType::kSampledImage, - texture.slot, *texture.texture.GetMetadata(), + render_pass_->BindResource(impeller::ShaderStage::kVertex, texture.slot, + *texture.texture.GetMetadata(), texture.texture.resource, texture.sampler); } for (const auto& buffer : result.fragment_bindings.buffers) { - render_pass_->BindResource(impeller::ShaderStage::kFragment, - impeller::DescriptorType::kUniformBuffer, - buffer.slot, *buffer.view.GetMetadata(), + render_pass_->BindResource(impeller::ShaderStage::kFragment, buffer.slot, + *buffer.view.GetMetadata(), buffer.view.resource); } for (const auto& texture : result.fragment_bindings.sampled_images) { - render_pass_->BindResource(impeller::ShaderStage::kFragment, - impeller::DescriptorType::kSampledImage, - texture.slot, *texture.texture.GetMetadata(), + render_pass_->BindResource(impeller::ShaderStage::kFragment, texture.slot, + *texture.texture.GetMetadata(), texture.texture.resource, texture.sampler); } return render_pass_->Draw().ok(); @@ -381,8 +377,7 @@ static bool BindUniform(flutter::gpu::RenderPass* wrapper, } return command.BindResource( - shader->GetShaderStage(), impeller::DescriptorType::kUniformBuffer, - uniform_struct->slot, uniform_struct->metadata, + shader->GetShaderStage(), uniform_struct->slot, uniform_struct->metadata, impeller::BufferView{ .buffer = buffer, .range = impeller::Range(offset_in_bytes, length_in_bytes), @@ -448,12 +443,12 @@ bool InternalFlutterGpu_RenderPass_BindTexture( flutter::gpu::ToImpellerSamplerAddressMode(width_address_mode); sampler_desc.height_address_mode = flutter::gpu::ToImpellerSamplerAddressMode(height_address_mode); - auto sampler = - wrapper->GetContext()->GetSamplerLibrary()->GetSampler(sampler_desc); + auto sampler = wrapper->GetContext().lock()->GetSamplerLibrary()->GetSampler( + sampler_desc); - return command.BindResource( - shader->GetShaderStage(), impeller::DescriptorType::kSampledImage, - *image_slot, impeller::ShaderMetadata{}, texture->GetTexture(), sampler); + return command.BindResource(shader->GetShaderStage(), *image_slot, + impeller::ShaderMetadata{}, texture->GetTexture(), + sampler); } void InternalFlutterGpu_RenderPass_ClearBindings( diff --git a/lib/gpu/render_pass.h b/lib/gpu/render_pass.h index 94b7d5faebcca..1581ac1597ead 100644 --- a/lib/gpu/render_pass.h +++ b/lib/gpu/render_pass.h @@ -33,7 +33,7 @@ class RenderPass : public RefCountedDartWrappable { ~RenderPass() override; - const std::shared_ptr& GetContext() const; + const std::weak_ptr& GetContext() const; impeller::Command& GetCommand(); const impeller::Command& GetCommand() const;