diff --git a/impeller/aiks/BUILD.gn b/impeller/aiks/BUILD.gn index f1d7d8ef681ac..06d643c7b9993 100644 --- a/impeller/aiks/BUILD.gn +++ b/impeller/aiks/BUILD.gn @@ -76,6 +76,7 @@ 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 e831719cd3008..460013cc2808a 100644 --- a/impeller/aiks/testing/context_spy.cc +++ b/impeller/aiks/testing/context_spy.cc @@ -2,6 +2,8 @@ // 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 { @@ -64,14 +66,17 @@ std::shared_ptr ContextSpy::MakeContext( }); ON_CALL(*spy, OnCreateRenderPass) - .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; - }); + .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; + }); 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 28a5ec3907ae4..fe251b89e5999 100644 --- a/impeller/aiks/testing/context_spy.h +++ b/impeller/aiks/testing/context_spy.h @@ -6,7 +6,9 @@ #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 { @@ -20,7 +22,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 7927c71d2952c..dbef3017c0e41 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)}}, kResource{{ proto.name }}, kMetadata{{ proto.name }}, {% else %} +{{to_shader_stage(shader_stage)}}, {{ proto.descriptor_type }}, 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 e01755bccc38f..cafa894256f4d 100644 --- a/impeller/compiler/reflector.cc +++ b/impeller/compiler/reflector.cc @@ -1308,6 +1308,7 @@ 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 @@ -1327,6 +1328,7 @@ 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 @@ -1346,6 +1348,7 @@ 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 " @@ -1369,6 +1372,7 @@ 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 @@ -1388,6 +1392,7 @@ 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 " @@ -1416,6 +1421,7 @@ 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 3de086c00a553..1448e412d4738 100644 --- a/impeller/compiler/reflector.h +++ b/impeller/compiler/reflector.h @@ -187,6 +187,7 @@ 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 6a6172710d700..bd2dfea50508e 100644 --- a/impeller/core/resource_binder.h +++ b/impeller/core/resource_binder.h @@ -24,11 +24,13 @@ 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 c3fc2a8dca355..79ac4a76a5ee7 100644 --- a/impeller/entity/BUILD.gn +++ b/impeller/entity/BUILD.gn @@ -256,6 +256,8 @@ 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 63a2cbdd3aa07..97e1dae4276d5 100644 --- a/impeller/entity/contents/checkerboard_contents_unittests.cc +++ b/impeller/entity/contents/checkerboard_contents_unittests.cc @@ -9,6 +9,7 @@ #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" @@ -38,11 +39,14 @@ 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(render_pass->GetCommands().empty()); - ASSERT_TRUE(contents->Render(*content_context, entity, *render_pass)); - ASSERT_FALSE(render_pass->GetCommands().empty()); + ASSERT_TRUE(recording_pass->GetCommands().empty()); + ASSERT_TRUE(contents->Render(*content_context, entity, *recording_pass)); + ASSERT_FALSE(recording_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 454ff2a5f25fc..0a0ca655aa86f 100644 --- a/impeller/entity/contents/runtime_effect_contents.cc +++ b/impeller/entity/contents/runtime_effect_contents.cc @@ -191,8 +191,9 @@ 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, uniform_slot, metadata, - buffer_view); + pass.BindResource(ShaderStage::kFragment, + DescriptorType::kUniformBuffer, uniform_slot, + metadata, buffer_view); buffer_index++; buffer_offset += uniform.GetSize(); break; @@ -229,7 +230,8 @@ 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, uniform_slot, + pass.BindResource(ShaderStage::kFragment, + DescriptorType::kUniformBuffer, uniform_slot, ShaderMetadata{}, buffer_view); } } @@ -263,8 +265,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, image_slot, *metadata, - input.texture, sampler); + pass.BindResource(ShaderStage::kFragment, DescriptorType::kSampledImage, + 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 new file mode 100644 index 0000000000000..ef22d86d69ed6 --- /dev/null +++ b/impeller/entity/contents/test/recording_render_pass.cc @@ -0,0 +1,116 @@ +// 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 new file mode 100644 index 0000000000000..eb585c27767eb --- /dev/null +++ b/impeller/entity/contents/test/recording_render_pass.h @@ -0,0 +1,87 @@ +// 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 4715eaad79133..ddaedc3efc1f1 100644 --- a/impeller/entity/contents/tiled_texture_contents_unittests.cc +++ b/impeller/entity/contents/tiled_texture_contents_unittests.cc @@ -6,6 +6,7 @@ #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" @@ -36,9 +37,11 @@ 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(), {}, *render_pass)); - const std::vector& commands = render_pass->GetCommands(); + ASSERT_TRUE(contents.Render(*GetContentContext(), {}, *recording_pass)); + const std::vector& commands = recording_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 17fac72d722dc..4f1e778986070 100644 --- a/impeller/entity/contents/vertices_contents_unittests.cc +++ b/impeller/entity/contents/vertices_contents_unittests.cc @@ -10,6 +10,7 @@ #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" @@ -64,12 +65,15 @@ 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(render_pass->GetCommands().empty()); - ASSERT_TRUE(contents->Render(*content_context, entity, *render_pass)); + ASSERT_TRUE(recording_pass->GetCommands().empty()); + ASSERT_TRUE(contents->Render(*content_context, entity, *recording_pass)); - const auto& cmd = render_pass->GetCommands()[0]; + ASSERT_TRUE(recording_pass->GetCommands().size() > 0); + const auto& cmd = recording_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 ada717b742ea8..279c94e51189c 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().lock()->GetResourceAllocator()); + render_pass.GetContext()->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 737984d3ae1a8..ea6a651d0189a 100644 --- a/impeller/renderer/backend/gles/command_buffer_gles.cc +++ b/impeller/renderer/backend/gles/command_buffer_gles.cc @@ -49,8 +49,12 @@ 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 20b6fd4bea71b..6cff519a41270 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::weak_ptr context, +RenderPassGLES::RenderPassGLES(std::shared_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 e7e408306336c..9d4f986108d57 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::weak_ptr context, + RenderPassGLES(std::shared_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 7adb44a189225..c7899d48982f3 100644 --- a/impeller/renderer/backend/metal/command_buffer_mtl.mm +++ b/impeller/renderer/backend/metal/command_buffer_mtl.mm @@ -275,8 +275,12 @@ 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 69c78573e8add..00240d45249d3 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::weak_ptr context, + RenderPassMTL(std::shared_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 83918f71fce84..396127d598733 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::weak_ptr context, +RenderPassMTL::RenderPassMTL(std::shared_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 3bc11ba252784..92b30313f5f3a 100644 --- a/impeller/renderer/backend/vulkan/binding_helpers_vk.cc +++ b/impeller/renderer/backend/vulkan/binding_helpers_vk.cc @@ -20,11 +20,6 @@ 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, @@ -125,67 +120,6 @@ 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 1dc7f32d2a4b6..be35567a77e3b 100644 --- a/impeller/renderer/backend/vulkan/binding_helpers_vk.h +++ b/impeller/renderer/backend/vulkan/binding_helpers_vk.h @@ -17,17 +17,6 @@ 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 78eb547847082..6b7b14f243fdb 100644 --- a/impeller/renderer/backend/vulkan/command_buffer_vk.cc +++ b/impeller/renderer/backend/vulkan/command_buffer_vk.cc @@ -7,13 +7,10 @@ #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" @@ -73,9 +70,9 @@ std::shared_ptr CommandBufferVK::OnCreateRenderPass( return nullptr; } auto pass = - std::shared_ptr(new RenderPassVK(context, // - target, // - weak_from_this() // + std::shared_ptr(new RenderPassVK(context, // + target, // + shared_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 b1ede05b724f0..d85ce290082a8 100644 --- a/impeller/renderer/backend/vulkan/command_buffer_vk.h +++ b/impeller/renderer/backend/vulkan/command_buffer_vk.h @@ -5,7 +5,6 @@ #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 921677408697c..4867c9626c941 100644 --- a/impeller/renderer/backend/vulkan/gpu_tracer_vk.cc +++ b/impeller/renderer/backend/vulkan/gpu_tracer_vk.cc @@ -8,6 +8,7 @@ #include #include #include + #include "fml/logging.h" #include "fml/trace_event.h" #include "impeller/base/validation.h" @@ -30,7 +31,7 @@ GPUTracerVK::GPUTracerVK(const std::shared_ptr& device_holder) // Disable tracing in release mode. #ifdef IMPELLER_DEBUG enabled_ = true; -#endif +#endif // IMPELLER_DEBUG } bool GPUTracerVK::IsEnabled() const { @@ -105,16 +106,14 @@ void GPUTracerVK::RecordCmdBufferStart(const vk::CommandBuffer& buffer, trace_states_[current_state_].query_pool.get(), state.current_index); state.current_index += 1; - if (!probe.index_.has_value()) { - state.pending_buffers += 1; - probe.index_ = current_state_; - } + probe.index_ = current_state_; + state.pending_buffers += 1; } void GPUTracerVK::RecordCmdBufferEnd(const vk::CommandBuffer& buffer, GPUProbe& probe) { if (!enabled_ || std::this_thread::get_id() != raster_thread_id_ || - !in_frame_) { + !in_frame_ || !probe.index_.has_value()) { return; } Lock lock(trace_state_mutex_); @@ -128,10 +127,6 @@ 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 ef2fbff69ecfc..dc40fc6b70b67 100644 --- a/impeller/renderer/backend/vulkan/render_pass_vk.cc +++ b/impeller/renderer/backend/vulkan/render_pass_vk.cc @@ -8,10 +8,11 @@ #include #include -#include "flutter/fml/trace_event.h" +#include "fml/status.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" @@ -20,15 +21,63 @@ #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, @@ -199,61 +248,87 @@ SharedHandleVK RenderPassVK::CreateVKRenderPass( RenderPassVK::RenderPassVK(const std::shared_ptr& context, const RenderTarget& target, - std::weak_ptr command_buffer) + std::shared_ptr command_buffer) : RenderPass(context, target), command_buffer_(std::move(command_buffer)) { - is_valid_ = true; -} + 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; + }); -RenderPassVK::~RenderPassVK() = default; + const auto& target_size = render_target_.GetRenderTargetSize(); -bool RenderPassVK::IsValid() const { - return is_valid_; -} + 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; + } -void RenderPassVK::OnSetLabel(std::string label) { - debug_label_ = std::move(label); -} + auto framebuffer = CreateVKFramebuffer(vk_context, *render_pass); + if (!framebuffer) { + VALIDATION_LOG << "Could not create framebuffer."; + is_valid_ = false; + return; + } -static vk::ClearColorValue VKClearValueFromColor(Color color) { - vk::ClearColorValue value; - value.setFloat32( - std::array{color.red, color.green, color.blue, color.alpha}); - return value; -} + if (!encoder->Track(framebuffer) || !encoder->Track(render_pass)) { + is_valid_ = false; + return; + } -static vk::ClearDepthStencilValue VKClearValueFromDepthStencil(uint32_t stencil, - Scalar depth) { - vk::ClearDepthStencilValue value; - value.depth = depth; - value.stencil = stencil; - return value; -} + auto clear_values = GetVKClearValues(render_target_); -static std::vector GetVKClearValues( - const RenderTarget& target) { - std::vector clears; + 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); - for (const auto& [_, color] : target.GetColorAttachments()) { - clears.emplace_back(VKClearValueFromColor(color.clear_color)); - if (color.resolve_texture) { - clears.emplace_back(VKClearValueFromColor(color.clear_color)); - } - } + command_buffer_vk_.beginRenderPass(pass_info, vk::SubpassContents::eInline); - const auto& depth = target.GetDepthAttachment(); - const auto& stencil = target.GetStencilAttachment(); + // 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); - if (depth.has_value()) { - clears.emplace_back(VKClearValueFromDepthStencil( - stencil ? stencil->clear_stencil : 0u, depth->clear_depth)); - } + // 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); - if (stencil.has_value()) { - clears.emplace_back(VKClearValueFromDepthStencil( - stencil->clear_stencil, depth ? depth->clear_depth : 0.0f)); - } + color_image_vk_ = + render_target_.GetColorAttachments().find(0u)->second.texture; + resolve_image_vk_ = + render_target_.GetColorAttachments().find(0u)->second.resolve_texture; + is_valid_ = true; +} - return clears; +RenderPassVK::~RenderPassVK() = default; + +bool RenderPassVK::IsValid() const { + return is_valid_; +} + +void RenderPassVK::OnSetLabel(std::string label) { + debug_label_ = std::move(label); } SharedHandleVK RenderPassVK::CreateVKFramebuffer( @@ -302,134 +377,114 @@ SharedHandleVK RenderPassVK::CreateVKFramebuffer( return MakeSharedVK(std::move(framebuffer)); } -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; - } - } - return true; -} +// |RenderPass| +void RenderPassVK::SetPipeline( + const std::shared_ptr>& pipeline) { + PipelineVK& pipeline_vk = PipelineVK::Cast(*pipeline); -static bool UpdateBindingLayouts(const Command& command, - const vk::CommandBuffer& buffer) { - return UpdateBindingLayouts(command.vertex_bindings, buffer) && - UpdateBindingLayouts(command.fragment_bindings, buffer); -} + auto descriptor_result = + command_buffer_->GetEncoder()->AllocateDescriptorSets( + pipeline_vk.GetDescriptorSetLayout(), ContextVK::Cast(*context_)); + if (!descriptor_result.ok()) { + return; + } + pipeline_valid_ = true; + descriptor_set_ = descriptor_result.value(); + pipeline_layout_ = pipeline_vk.GetPipelineLayout(); + command_buffer_vk_.bindPipeline(vk::PipelineBindPoint::eGraphics, + pipeline_vk.GetPipeline()); -static bool UpdateBindingLayouts(const std::vector& commands, - const vk::CommandBuffer& buffer) { - for (const Command& command : commands) { - if (!UpdateBindingLayouts(command, buffer)) { - return false; + if (pipeline->GetDescriptor().UsesSubpassInput()) { + if (bound_image_offset_ >= kMaxBindings) { + pipeline_valid_ = false; + return; } - } - return true; -} -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); + 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; - // 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); + 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]; + + write_workspace_[descriptor_write_offset_++] = write_set; + } } -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) { +// |RenderPass| +void RenderPassVK::SetCommandLabel(std::string_view label) { #ifdef IMPELLER_DEBUG - fml::ScopedCleanupClosure pop_marker( - [&encoder]() { encoder.PopDebugGroup(); }); - if (!command.label.empty()) { - encoder.PushDebugGroup(command.label.c_str()); - } else { - pop_marker.Release(); - } + std::string label_copy(label); + command_buffer_->GetEncoder()->PushDebugGroup(label_copy.c_str()); + has_label_ = true; #endif // IMPELLER_DEBUG +} - const PipelineVK& pipeline_vk = PipelineVK::Cast(*command.pipeline); +// |RenderPass| +void RenderPassVK::SetStencilReference(uint32_t value) { + command_buffer_vk_.setStencilReference( + vk::StencilFaceFlagBits::eVkStencilFrontAndBack, 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::SetBaseVertex(uint64_t value) { + base_vertex_ = value; +} - command_buffer_cache.BindPipeline( - cmd_buffer, vk::PipelineBindPoint::eGraphics, pipeline_vk.GetPipeline()); +// |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); +} - // Set the viewport and scissors. - SetViewportAndScissor(command, cmd_buffer, command_buffer_cache, target_size); +// |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 stencil reference. - command_buffer_cache.SetStencilReference( - cmd_buffer, vk::StencilFaceFlagBits::eVkStencilFrontAndBack, - command.stencil_reference); +// |RenderPass| +void RenderPassVK::SetInstanceCount(size_t count) { + instance_count_ = count; +} - // 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"; +// |RenderPass| +bool RenderPassVK::SetVertexBuffer(VertexBuffer buffer) { + vertex_count_ = buffer.vertex_count; + if (buffer.index_type == IndexType::kUnknown) { return false; } - auto& allocator = *context.GetResourceAllocator(); - const std::shared_ptr& vertex_buffer = - command.vertex_buffer.vertex_buffer.buffer; - - if (!encoder.Track(vertex_buffer)) { + if (!command_buffer_->GetEncoder()->Track(buffer.vertex_buffer.buffer)) { return false; } // Bind the vertex buffer. vk::Buffer vertex_buffer_handle = - DeviceBufferVK::Cast(*vertex_buffer).GetBuffer(); + DeviceBufferVK::Cast(*buffer.vertex_buffer.buffer).GetBuffer(); vk::Buffer vertex_buffers[] = {vertex_buffer_handle}; - vk::DeviceSize vertex_buffer_offsets[] = { - command.vertex_buffer.vertex_buffer.range.offset}; - cmd_buffer.bindVertexBuffers(0u, 1u, vertex_buffers, vertex_buffer_offsets); + vk::DeviceSize vertex_buffer_offsets[] = {buffer.vertex_buffer.range.offset}; - if (command.vertex_buffer.index_type != IndexType::kNone) { - // Bind the index buffer. - const BufferView& index_buffer_view = command.vertex_buffer.index_buffer; + 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 (!index_buffer_view) { return false; } @@ -442,128 +497,187 @@ static bool EncodeCommand(const Context& context, return false; } - if (!encoder.Track(index_buffer)) { + if (!command_buffer_->GetEncoder()->Track(index_buffer)) { return false; } vk::Buffer index_buffer_handle = DeviceBufferVK::Cast(*index_buffer).GetBuffer(); - 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 - ); + command_buffer_vk_.bindIndexBuffer(index_buffer_handle, + index_buffer_view.range.offset, + ToVKIndexType(buffer.index_type)); } else { - cmd_buffer.draw(command.vertex_buffer.vertex_count, // vertex count - command.instance_count, // instance count - command.base_vertex, // vertex offset - 0u // first instance - ); + has_index_buffer_ = false; } return true; } -bool RenderPassVK::OnEncodeCommands(const Context& context) const { - TRACE_EVENT0("impeller", "RenderPassVK::OnEncodeCommands"); - if (!IsValid()) { - return false; +// |RenderPass| +fml::Status RenderPassVK::Draw() { + if (!pipeline_valid_) { + return fml::Status(fml::StatusCode::kCancelled, + "No valid pipeline is bound to the RenderPass."); } - const auto& vk_context = ContextVK::Cast(context); - - std::shared_ptr command_buffer = command_buffer_.lock(); - if (!command_buffer) { - VALIDATION_LOG << "Command buffer died before commands could be encoded."; - return false; + const ContextVK& context_vk = ContextVK::Cast(*context_); + for (auto i = 0u; i < descriptor_write_offset_; i++) { + write_workspace_[i].dstSet = descriptor_set_; } - const std::shared_ptr& encoder = - command_buffer->GetEncoder(); - if (!encoder) { - 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 + ); + + 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 + ); } #ifdef IMPELLER_DEBUG - fml::ScopedCleanupClosure pop_marker( - [&encoder]() { encoder->PopDebugGroup(); }); - if (!debug_label_.empty()) { - encoder->PushDebugGroup(debug_label_.c_str()); - } else { - pop_marker.Release(); + if (has_label_) { + command_buffer_->GetEncoder()->PopDebugGroup(); } #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(); +} - vk::CommandBuffer cmd_buffer = encoder->GetCommandBuffer(); +// 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); +} - if (!UpdateBindingLayouts(commands_, cmd_buffer)) { +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) { 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(); + const std::shared_ptr& device_buffer = view.buffer; + auto buffer = DeviceBufferVK::Cast(*device_buffer).GetBuffer(); + if (!buffer) { + return false; + } - SharedHandleVK render_pass = CreateVKRenderPass( - vk_context, command_buffer, - vk_context.GetCapabilities()->SupportsFramebufferFetch()); - if (!render_pass) { - VALIDATION_LOG << "Could not create renderpass."; + if (!command_buffer_->GetEncoder()->Track(device_buffer)) { return false; } - auto framebuffer = CreateVKFramebuffer(vk_context, *render_pass); - if (!framebuffer) { - VALIDATION_LOG << "Could not create framebuffer."; + 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) { return false; } + const TextureVK& texture_vk = TextureVK::Cast(*texture); + const SamplerVK& sampler_vk = SamplerVK::Cast(*sampler); - if (!encoder->Track(framebuffer) || !encoder->Track(render_pass)) { + if (!command_buffer_->GetEncoder()->Track(texture) || + !command_buffer_->GetEncoder()->Track(sampler_vk.GetSharedSampler())) { return false; } - auto clear_values = GetVKClearValues(render_target_); + 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::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); + 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; +} - 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; - } +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; + + barrier.new_layout = vk::ImageLayout::eShaderReadOnlyOptimal; + + if (!TextureVK::Cast(*result_texture).SetLayout(barrier)) { + return false; } } diff --git a/impeller/renderer/backend/vulkan/render_pass_vk.h b/impeller/renderer/backend/vulkan/render_pass_vk.h index 2d31abd4019f6..26c635c41c6fe 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 "flutter/fml/macros.h" +#include "impeller/core/buffer_view.h" #include "impeller/renderer/backend/vulkan/binding_helpers_vk.h" #include "impeller/renderer/backend/vulkan/context_vk.h" -#include "impeller/renderer/backend/vulkan/pass_bindings_cache.h" +#include "impeller/renderer/backend/vulkan/pipeline_vk.h" #include "impeller/renderer/backend/vulkan/shared_object_vk.h" #include "impeller/renderer/render_pass.h" #include "impeller/renderer/render_target.h" @@ -25,20 +25,92 @@ class RenderPassVK final : public RenderPass { private: friend class CommandBufferVK; - std::weak_ptr command_buffer_; + std::shared_ptr command_buffer_; std::string debug_label_; bool is_valid_ = false; - mutable std::array image_workspace_; - mutable std::array buffer_workspace_; - mutable std::array - write_workspace_; + vk::CommandBuffer command_buffer_vk_; + std::shared_ptr color_image_vk_; + std::shared_ptr resolve_image_vk_; - mutable PassBindingsCache pass_bindings_cache_; + // Per-command state. + std::array image_workspace_; + std::array buffer_workspace_; + 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_ = {}; RenderPassVK(const std::shared_ptr& context, const RenderTarget& target, - std::weak_ptr command_buffer); + 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); // |RenderPass| bool IsValid() const override; diff --git a/impeller/renderer/backend/vulkan/texture_vk.cc b/impeller/renderer/backend/vulkan/texture_vk.cc index cbe525400c303..36f5d3878fe91 100644 --- a/impeller/renderer/backend/vulkan/texture_vk.cc +++ b/impeller/renderer/backend/vulkan/texture_vk.cc @@ -107,6 +107,24 @@ 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 40dfd8c09d518..6507c81d565c0 100644 --- a/impeller/renderer/command.cc +++ b/impeller/renderer/command.cc @@ -23,6 +23,7 @@ bool Command::BindVertices(VertexBuffer buffer) { } bool Command::BindResource(ShaderStage stage, + DescriptorType type, const ShaderUniformSlot& slot, const ShaderMetadata& metadata, BufferView view) { @@ -31,6 +32,7 @@ bool Command::BindResource(ShaderStage stage, bool Command::BindResource( ShaderStage stage, + DescriptorType type, const ShaderUniformSlot& slot, const std::shared_ptr& metadata, BufferView view) { @@ -66,6 +68,7 @@ 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 0e27d74750a71..0df30895b7959 100644 --- a/impeller/renderer/command.h +++ b/impeller/renderer/command.h @@ -162,17 +162,20 @@ 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 98b23204604b1..b25ab3af000ff 100644 --- a/impeller/renderer/command_buffer.cc +++ b/impeller/renderer/command_buffer.cc @@ -38,7 +38,6 @@ void CommandBuffer::WaitUntilScheduled() { bool CommandBuffer::EncodeAndSubmit( const std::shared_ptr& render_pass) { - TRACE_EVENT0("impeller", "CommandBuffer::EncodeAndSubmit"); if (!render_pass->IsValid() || !IsValid()) { return false; } @@ -52,7 +51,6 @@ 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 fbbfe3b58666f..e1a06015fa611 100644 --- a/impeller/renderer/compute_command.cc +++ b/impeller/renderer/compute_command.cc @@ -8,10 +8,12 @@ #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) { @@ -29,6 +31,7 @@ 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 fb2639df664e8..c0c56e9f698f6 100644 --- a/impeller/renderer/compute_command.h +++ b/impeller/renderer/compute_command.h @@ -53,12 +53,14 @@ 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 10c5a16556117..8c3998d8720af 100644 --- a/impeller/renderer/render_pass.cc +++ b/impeller/renderer/render_pass.cc @@ -7,7 +7,7 @@ namespace impeller { -RenderPass::RenderPass(std::weak_ptr context, +RenderPass::RenderPass(std::shared_ptr context, const RenderTarget& target) : context_(std::move(context)), sample_count_(target.GetSampleCount()), @@ -77,15 +77,10 @@ bool RenderPass::AddCommand(Command&& command) { } bool RenderPass::EncodeCommands() const { - auto context = context_.lock(); - // The context could have been collected in the meantime. - if (!context) { - return false; - } - return OnEncodeCommands(*context); + return OnEncodeCommands(*context_); } -const std::weak_ptr& RenderPass::GetContext() const { +const std::shared_ptr& RenderPass::GetContext() const { return context_; } @@ -136,27 +131,30 @@ fml::Status RenderPass::Draw() { // |ResourceBinder| bool RenderPass::BindResource(ShaderStage stage, + DescriptorType type, const ShaderUniformSlot& slot, const ShaderMetadata& metadata, BufferView view) { - return pending_.BindResource(stage, slot, metadata, view); + return pending_.BindResource(stage, type, slot, metadata, view); } bool RenderPass::BindResource( ShaderStage stage, + DescriptorType type, const ShaderUniformSlot& slot, const std::shared_ptr& metadata, BufferView view) { - return pending_.BindResource(stage, slot, metadata, std::move(view)); + return pending_.BindResource(stage, type, 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, slot, metadata, std::move(texture), + return pending_.BindResource(stage, type, slot, metadata, std::move(texture), std::move(sampler)); } diff --git a/impeller/renderer/render_pass.h b/impeller/renderer/render_pass.h index c2bd755c58f9b..cae0fe3046f7d 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::weak_ptr& GetContext() const; + const std::shared_ptr& GetContext() const; const RenderTarget& GetRenderTarget() const; @@ -46,21 +46,18 @@ class RenderPass : public ResourceBinder { void SetLabel(std::string label); - /// @brief Reserve [command_count] commands in the HAL command buffer. - /// - /// Note: this is not the native command buffer. - void ReserveCommands(size_t command_count) { + virtual void ReserveCommands(size_t command_count) { commands_.reserve(command_count); } //---------------------------------------------------------------------------- /// The pipeline to use for this command. - void SetPipeline( + virtual void SetPipeline( const std::shared_ptr>& pipeline); //---------------------------------------------------------------------------- /// The debugging label to use for the command. - void SetCommandLabel(std::string_view label); + virtual void SetCommandLabel(std::string_view label); //---------------------------------------------------------------------------- /// The reference value to use in stenciling operations. Stencil configuration @@ -69,9 +66,9 @@ class RenderPass : public ResourceBinder { /// @see `Pipeline` /// @see `PipelineDescriptor` /// - void SetStencilReference(uint32_t value); + virtual void SetStencilReference(uint32_t value); - void SetBaseVertex(uint64_t value); + virtual void SetBaseVertex(uint64_t value); //---------------------------------------------------------------------------- /// The viewport coordinates that the rasterizer linearly maps normalized @@ -79,14 +76,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. /// - void SetViewport(Viewport viewport); + virtual 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. /// - void SetScissor(IRect scissor); + virtual void SetScissor(IRect scissor); //---------------------------------------------------------------------------- /// The number of instances of the given set of vertices to render. Not all @@ -95,7 +92,7 @@ class RenderPass : public ResourceBinder { /// @warning Setting this to more than one will limit the availability of /// backends to use with this command. /// - void SetInstanceCount(size_t count); + virtual void SetInstanceCount(size_t count); //---------------------------------------------------------------------------- /// @brief Specify the vertex and index buffer to use for this command. @@ -105,28 +102,32 @@ class RenderPass : public ResourceBinder { /// /// @return returns if the binding was updated. /// - bool SetVertexBuffer(VertexBuffer buffer); + virtual bool SetVertexBuffer(VertexBuffer buffer); /// Record the currently pending command. - fml::Status Draw(); + virtual fml::Status Draw(); // |ResourceBinder| - 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); + 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); // |ResourceBinder| - bool BindResource(ShaderStage stage, - const SampledImageSlot& slot, - const ShaderMetadata& metadata, - std::shared_ptr texture, - std::shared_ptr sampler) override; + virtual bool BindResource(ShaderStage stage, + DescriptorType type, + 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. @@ -141,7 +142,7 @@ class RenderPass : public ResourceBinder { /// /// @details Visible for testing. /// - const std::vector& GetCommands() const { return commands_; } + virtual const std::vector& GetCommands() const { return commands_; } //---------------------------------------------------------------------------- /// @brief The sample count of the attached render target. @@ -156,7 +157,7 @@ class RenderPass : public ResourceBinder { bool HasStencilAttachment() const; protected: - const std::weak_ptr context_; + const std::shared_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 @@ -181,7 +182,8 @@ class RenderPass : public ResourceBinder { /// bool AddCommand(Command&& command); - RenderPass(std::weak_ptr context, const RenderTarget& target); + RenderPass(std::shared_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 0881fd6c4bd15..b01f8ed328c2d 100644 --- a/impeller/renderer/renderer_unittests.cc +++ b/impeller/renderer/renderer_unittests.cc @@ -1255,21 +1255,6 @@ 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 4960a57ef78fd..2c3b096bda6f7 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::weak_ptr context, + MockRenderPass(std::shared_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 35a43793fb637..206da54bde4ac 100644 --- a/lib/gpu/render_pass.cc +++ b/lib/gpu/render_pass.cc @@ -28,7 +28,7 @@ RenderPass::RenderPass() RenderPass::~RenderPass() = default; -const std::weak_ptr& RenderPass::GetContext() const { +const std::shared_ptr& RenderPass::GetContext() const { return render_pass_->GetContext(); } @@ -115,7 +115,7 @@ RenderPass::GetOrCreatePipeline() { } } - auto& context = *GetContext().lock(); + auto& context = *GetContext(); render_pipeline_->BindToPipelineDescriptor(*context.GetShaderLibrary(), pipeline_desc); @@ -151,23 +151,27 @@ bool RenderPass::Draw() { } render_pass_->SetVertexBuffer(result.vertex_buffer); for (const auto& buffer : result.vertex_bindings.buffers) { - render_pass_->BindResource(impeller::ShaderStage::kVertex, buffer.slot, - *buffer.view.GetMetadata(), + render_pass_->BindResource(impeller::ShaderStage::kVertex, + impeller::DescriptorType::kUniformBuffer, + buffer.slot, *buffer.view.GetMetadata(), buffer.view.resource); } for (const auto& texture : result.vertex_bindings.sampled_images) { - render_pass_->BindResource(impeller::ShaderStage::kVertex, texture.slot, - *texture.texture.GetMetadata(), + render_pass_->BindResource(impeller::ShaderStage::kVertex, + impeller::DescriptorType::kSampledImage, + texture.slot, *texture.texture.GetMetadata(), texture.texture.resource, texture.sampler); } for (const auto& buffer : result.fragment_bindings.buffers) { - render_pass_->BindResource(impeller::ShaderStage::kFragment, buffer.slot, - *buffer.view.GetMetadata(), + render_pass_->BindResource(impeller::ShaderStage::kFragment, + impeller::DescriptorType::kUniformBuffer, + buffer.slot, *buffer.view.GetMetadata(), buffer.view.resource); } for (const auto& texture : result.fragment_bindings.sampled_images) { - render_pass_->BindResource(impeller::ShaderStage::kFragment, texture.slot, - *texture.texture.GetMetadata(), + render_pass_->BindResource(impeller::ShaderStage::kFragment, + impeller::DescriptorType::kSampledImage, + texture.slot, *texture.texture.GetMetadata(), texture.texture.resource, texture.sampler); } return render_pass_->Draw().ok(); @@ -377,7 +381,8 @@ static bool BindUniform(flutter::gpu::RenderPass* wrapper, } return command.BindResource( - shader->GetShaderStage(), uniform_struct->slot, uniform_struct->metadata, + shader->GetShaderStage(), impeller::DescriptorType::kUniformBuffer, + uniform_struct->slot, uniform_struct->metadata, impeller::BufferView{ .buffer = buffer, .range = impeller::Range(offset_in_bytes, length_in_bytes), @@ -443,12 +448,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().lock()->GetSamplerLibrary()->GetSampler( - sampler_desc); + auto sampler = + wrapper->GetContext()->GetSamplerLibrary()->GetSampler(sampler_desc); - return command.BindResource(shader->GetShaderStage(), *image_slot, - impeller::ShaderMetadata{}, texture->GetTexture(), - sampler); + return command.BindResource( + shader->GetShaderStage(), impeller::DescriptorType::kSampledImage, + *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 1581ac1597ead..94b7d5faebcca 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::weak_ptr& GetContext() const; + const std::shared_ptr& GetContext() const; impeller::Command& GetCommand(); const impeller::Command& GetCommand() const;