diff --git a/engine/src/flutter/impeller/entity/BUILD.gn b/engine/src/flutter/impeller/entity/BUILD.gn index 48bcb2bc33..bfa91f4244 100644 --- a/engine/src/flutter/impeller/entity/BUILD.gn +++ b/engine/src/flutter/impeller/entity/BUILD.gn @@ -229,8 +229,6 @@ impeller_component("entity_test_helpers") { testonly = true 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", ] diff --git a/engine/src/flutter/impeller/entity/contents/runtime_effect_contents.cc b/engine/src/flutter/impeller/entity/contents/runtime_effect_contents.cc index dc2c2fea8b..d568567277 100644 --- a/engine/src/flutter/impeller/entity/contents/runtime_effect_contents.cc +++ b/engine/src/flutter/impeller/entity/contents/runtime_effect_contents.cc @@ -24,6 +24,38 @@ namespace impeller { +namespace { +constexpr char kPaddingType = 0; +constexpr char kFloatType = 1; +} // namespace + +// static +BufferView RuntimeEffectContents::EmplaceVulkanUniform( + const std::shared_ptr>& input_data, + HostBuffer& host_buffer, + const RuntimeUniformDescription& uniform) { + // TODO(jonahwilliams): rewrite this to emplace directly into + // HostBuffer. + std::vector uniform_buffer; + uniform_buffer.reserve(uniform.struct_layout.size()); + size_t uniform_byte_index = 0u; + for (char byte_type : uniform.struct_layout) { + if (byte_type == kPaddingType) { + uniform_buffer.push_back(0.f); + } else { + FML_DCHECK(byte_type == kFloatType); + uniform_buffer.push_back(reinterpret_cast( + input_data->data())[uniform_byte_index++]); + } + } + size_t alignment = std::max(sizeof(float) * uniform_buffer.size(), + DefaultUniformAlignment()); + + return host_buffer.Emplace( + reinterpret_cast(uniform_buffer.data()), + sizeof(float) * uniform_buffer.size(), alignment); +} + void RuntimeEffectContents::SetRuntimeStage( std::shared_ptr runtime_stage) { runtime_stage_ = std::move(runtime_stage); @@ -251,30 +283,11 @@ bool RuntimeEffectContents::Render(const ContentContext& renderer, uniform_slot.binding = uniform.location; uniform_slot.name = uniform.name.c_str(); - // TODO(jonahwilliams): rewrite this to emplace directly into - // HostBuffer. - std::vector uniform_buffer; - uniform_buffer.reserve(uniform.struct_layout.size()); - size_t uniform_byte_index = 0u; - for (const auto& byte_type : uniform.struct_layout) { - if (byte_type == 0) { - uniform_buffer.push_back(0.f); - } else if (byte_type == 1) { - uniform_buffer.push_back(reinterpret_cast( - uniform_data_->data())[uniform_byte_index++]); - } else { - FML_UNREACHABLE(); - } - } - size_t alignment = std::max(sizeof(float) * uniform_buffer.size(), - DefaultUniformAlignment()); - - BufferView buffer_view = renderer.GetTransientsBuffer().Emplace( - reinterpret_cast(uniform_buffer.data()), - sizeof(float) * uniform_buffer.size(), alignment); - pass.BindResource(ShaderStage::kFragment, - DescriptorType::kUniformBuffer, uniform_slot, - nullptr, std::move(buffer_view)); + pass.BindResource( + ShaderStage::kFragment, DescriptorType::kUniformBuffer, + uniform_slot, nullptr, + EmplaceVulkanUniform(uniform_data_, + renderer.GetTransientsBuffer(), uniform)); } } } diff --git a/engine/src/flutter/impeller/entity/contents/runtime_effect_contents.h b/engine/src/flutter/impeller/entity/contents/runtime_effect_contents.h index 151bb315f9..dd62059f22 100644 --- a/engine/src/flutter/impeller/entity/contents/runtime_effect_contents.h +++ b/engine/src/flutter/impeller/entity/contents/runtime_effect_contents.h @@ -8,6 +8,7 @@ #include #include +#include "impeller/core/host_buffer.h" #include "impeller/core/sampler_descriptor.h" #include "impeller/entity/contents/color_source_contents.h" #include "impeller/runtime_stage/runtime_stage.h" @@ -35,6 +36,12 @@ class RuntimeEffectContents final : public ColorSourceContents { /// Load the runtime effect and ensure a default PSO is initialized. bool BootstrapShader(const ContentContext& renderer) const; + // Visible for testing + static BufferView EmplaceVulkanUniform( + const std::shared_ptr>& input_data, + HostBuffer& host_buffer, + const RuntimeUniformDescription& uniform); + private: bool RegisterShader(const ContentContext& renderer) const; diff --git a/engine/src/flutter/impeller/entity/contents/test/contents_test_helpers.cc b/engine/src/flutter/impeller/entity/contents/test/contents_test_helpers.cc deleted file mode 100644 index fe06724eaa..0000000000 --- a/engine/src/flutter/impeller/entity/contents/test/contents_test_helpers.cc +++ /dev/null @@ -1,11 +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/contents_test_helpers.h" - -namespace impeller::testing { - -// - -} // namespace impeller::testing diff --git a/engine/src/flutter/impeller/entity/contents/test/contents_test_helpers.h b/engine/src/flutter/impeller/entity/contents/test/contents_test_helpers.h deleted file mode 100644 index 3783e86568..0000000000 --- a/engine/src/flutter/impeller/entity/contents/test/contents_test_helpers.h +++ /dev/null @@ -1,49 +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_CONTENTS_TEST_HELPERS_H_ -#define FLUTTER_IMPELLER_ENTITY_CONTENTS_TEST_CONTENTS_TEST_HELPERS_H_ - -#include "impeller/renderer/command.h" - -namespace impeller::testing { - -/// @brief Retrieve the [VertInfo] struct data from the provided [command]. -template -typename T::VertInfo* GetVertInfo(const Command& command) { - auto resource = std::find_if(command.vertex_bindings.buffers.begin(), - command.vertex_bindings.buffers.end(), - [](const BufferAndUniformSlot& data) { - return data.slot.ext_res_0 == 0u; - }); - if (resource == command.vertex_bindings.buffers.end()) { - return nullptr; - } - - auto data = (resource->view.resource.buffer->OnGetContents() + - resource->view.resource.range.offset); - return reinterpret_cast(data); -} - -/// @brief Retrieve the [FragInfo] struct data from the provided [command]. -template -typename T::FragInfo* GetFragInfo(const Command& command) { - auto resource = std::find_if(command.fragment_bindings.buffers.begin(), - command.fragment_bindings.buffers.end(), - [](const BufferAndUniformSlot& data) { - return data.slot.ext_res_0 == 0u || - data.slot.binding == 64; - }); - if (resource == command.fragment_bindings.buffers.end()) { - return nullptr; - } - - auto data = (resource->view.resource.buffer->OnGetContents() + - resource->view.resource.range.offset); - return reinterpret_cast(data); -} - -} // namespace impeller::testing - -#endif // FLUTTER_IMPELLER_ENTITY_CONTENTS_TEST_CONTENTS_TEST_HELPERS_H_ diff --git a/engine/src/flutter/impeller/entity/contents/test/recording_render_pass.cc b/engine/src/flutter/impeller/entity/contents/test/recording_render_pass.cc index 822ce71021..9d7877e1a1 100644 --- a/engine/src/flutter/impeller/entity/contents/test/recording_render_pass.cc +++ b/engine/src/flutter/impeller/entity/contents/test/recording_render_pass.cc @@ -110,7 +110,6 @@ bool RecordingRenderPass::BindResource(ShaderStage stage, const ShaderUniformSlot& slot, const ShaderMetadata* metadata, BufferView view) { - pending_.BindResource(stage, type, slot, metadata, view); if (delegate_) { return delegate_->BindResource(stage, type, slot, metadata, view); } @@ -124,7 +123,6 @@ bool RecordingRenderPass::BindDynamicResource( const ShaderUniformSlot& slot, std::unique_ptr metadata, BufferView view) { - pending_.BindResource(stage, type, slot, metadata.get(), view); if (delegate_) { return delegate_->BindDynamicResource(stage, type, slot, std::move(metadata), view); @@ -140,7 +138,6 @@ bool RecordingRenderPass::BindDynamicResource( std::unique_ptr metadata, std::shared_ptr texture, const std::unique_ptr& sampler) { - pending_.BindResource(stage, type, slot, metadata.get(), texture, sampler); if (delegate_) { return delegate_->BindDynamicResource( stage, type, slot, std::move(metadata), texture, sampler); @@ -155,7 +152,6 @@ bool RecordingRenderPass::BindResource( const ShaderMetadata* metadata, std::shared_ptr texture, const std::unique_ptr& sampler) { - pending_.BindResource(stage, type, slot, metadata, texture, sampler); if (delegate_) { return delegate_->BindResource(stage, type, slot, metadata, texture, sampler); diff --git a/engine/src/flutter/impeller/entity/entity_unittests.cc b/engine/src/flutter/impeller/entity/entity_unittests.cc index 756203ab2f..2d64dc4d48 100644 --- a/engine/src/flutter/impeller/entity/entity_unittests.cc +++ b/engine/src/flutter/impeller/entity/entity_unittests.cc @@ -1843,27 +1843,16 @@ TEST_P(EntityTest, RuntimeEffectSetsRightSizeWhenUniformIsStruct) { auto uniform_data = std::make_shared>(); uniform_data->resize(sizeof(FragUniforms)); memcpy(uniform_data->data(), &frag_uniforms, sizeof(FragUniforms)); - contents->SetUniformData(uniform_data); - Entity entity; - entity.SetContents(contents); + auto buffer_view = RuntimeEffectContents::EmplaceVulkanUniform( + uniform_data, GetContentContext()->GetTransientsBuffer(), + runtime_stage->GetUniforms()[0]); - auto context = GetContentContext(); - RenderTarget target = context->GetRenderTargetCache()->CreateOffscreen( - *context->GetContext(), {1, 1}, 1u); - - testing::MockRenderPass pass(GetContext(), target); - ASSERT_TRUE(contents->Render(*context, entity, pass)); - ASSERT_EQ(pass.GetCommands().size(), 1u); - const auto& command = pass.GetCommands()[0]; - ASSERT_EQ(command.fragment_bindings.buffers.size(), 1u); // 16 bytes: // 8 bytes for iResolution // 4 bytes for iTime // 4 bytes padding - EXPECT_EQ( - command.fragment_bindings.buffers[0].view.resource.GetRange().length, - 16u); + EXPECT_EQ(buffer_view.GetRange().length, 16u); } TEST_P(EntityTest, ColorFilterWithForegroundColorAdvancedBlend) { diff --git a/engine/src/flutter/impeller/renderer/backend/gles/buffer_bindings_gles.cc b/engine/src/flutter/impeller/renderer/backend/gles/buffer_bindings_gles.cc index 9ad2339572..491f9f24d7 100644 --- a/engine/src/flutter/impeller/renderer/backend/gles/buffer_bindings_gles.cc +++ b/engine/src/flutter/impeller/renderer/backend/gles/buffer_bindings_gles.cc @@ -13,6 +13,7 @@ #include "impeller/renderer/backend/gles/formats_gles.h" #include "impeller/renderer/backend/gles/sampler_gles.h" #include "impeller/renderer/backend/gles/texture_gles.h" +#include "impeller/renderer/command.h" namespace impeller { @@ -179,27 +180,23 @@ bool BufferBindingsGLES::BindVertexAttributes(const ProcTableGLES& gl, return true; } -bool BufferBindingsGLES::BindUniformData(const ProcTableGLES& gl, - const Bindings& vertex_bindings, - const Bindings& fragment_bindings) { - for (const auto& buffer : vertex_bindings.buffers) { - if (!BindUniformBuffer(gl, buffer.view)) { +bool BufferBindingsGLES::BindUniformData( + const ProcTableGLES& gl, + const std::vector& bound_textures, + const std::vector& bound_buffers, + Range texture_range, + Range buffer_range) { + for (auto i = 0u; i < buffer_range.length; i++) { + if (!BindUniformBuffer(gl, bound_buffers[buffer_range.offset + i])) { return false; } } - for (const auto& buffer : fragment_bindings.buffers) { - if (!BindUniformBuffer(gl, buffer.view)) { - return false; - } - } - std::optional next_unit_index = - BindTextures(gl, vertex_bindings, ShaderStage::kVertex); + BindTextures(gl, bound_textures, texture_range, ShaderStage::kVertex); if (!next_unit_index.has_value()) { return false; } - - if (!BindTextures(gl, fragment_bindings, ShaderStage::kFragment, + if (!BindTextures(gl, bound_textures, texture_range, ShaderStage::kFragment, *next_unit_index) .has_value()) { return false; @@ -389,11 +386,16 @@ bool BufferBindingsGLES::BindUniformBuffer(const ProcTableGLES& gl, std::optional BufferBindingsGLES::BindTextures( const ProcTableGLES& gl, - const Bindings& bindings, + const std::vector& bound_textures, + Range texture_range, ShaderStage stage, size_t unit_start_index) { size_t active_index = unit_start_index; - for (const auto& data : bindings.sampled_images) { + for (auto i = 0u; i < texture_range.length; i++) { + const TextureAndSampler& data = bound_textures[texture_range.offset + i]; + if (data.stage != stage) { + continue; + } const auto& texture_gles = TextureGLES::Cast(*data.texture.resource); if (data.texture.GetMetadata() == nullptr) { VALIDATION_LOG << "No metadata found for texture binding."; diff --git a/engine/src/flutter/impeller/renderer/backend/gles/buffer_bindings_gles.h b/engine/src/flutter/impeller/renderer/backend/gles/buffer_bindings_gles.h index 07bae42d49..eeaaf43fcd 100644 --- a/engine/src/flutter/impeller/renderer/backend/gles/buffer_bindings_gles.h +++ b/engine/src/flutter/impeller/renderer/backend/gles/buffer_bindings_gles.h @@ -42,8 +42,10 @@ class BufferBindingsGLES { size_t vertex_offset); bool BindUniformData(const ProcTableGLES& gl, - const Bindings& vertex_bindings, - const Bindings& fragment_bindings); + const std::vector& bound_textures, + const std::vector& bound_buffers, + Range texture_range, + Range buffer_range); bool UnbindVertexAttributes(const ProcTableGLES& gl); @@ -75,10 +77,12 @@ class BufferBindingsGLES { bool BindUniformBuffer(const ProcTableGLES& gl, const BufferResource& buffer); - std::optional BindTextures(const ProcTableGLES& gl, - const Bindings& bindings, - ShaderStage stage, - size_t unit_start_index = 0); + std::optional BindTextures( + const ProcTableGLES& gl, + const std::vector& bound_textures, + Range texture_range, + ShaderStage stage, + size_t unit_start_index = 0); BufferBindingsGLES(const BufferBindingsGLES&) = delete; diff --git a/engine/src/flutter/impeller/renderer/backend/gles/buffer_bindings_gles_unittests.cc b/engine/src/flutter/impeller/renderer/backend/gles/buffer_bindings_gles_unittests.cc index 1f7721c23f..9078447433 100644 --- a/engine/src/flutter/impeller/renderer/backend/gles/buffer_bindings_gles_unittests.cc +++ b/engine/src/flutter/impeller/renderer/backend/gles/buffer_bindings_gles_unittests.cc @@ -7,7 +7,7 @@ #include "impeller/renderer/backend/gles/buffer_bindings_gles.h" #include "impeller/renderer/backend/gles/device_buffer_gles.h" #include "impeller/renderer/backend/gles/test/mock_gles.h" -#include "impeller/renderer/testing/mocks.h" +#include "impeller/renderer/command.h" namespace impeller { namespace testing { @@ -18,7 +18,8 @@ TEST(BufferBindingsGLESTest, BindUniformData) { uniform_bindings["SHADERMETADATA.FOOBAR"] = 1; bindings.SetUniformBindings(std::move(uniform_bindings)); std::shared_ptr mock_gl = MockGLES::Init(); - Bindings vertex_bindings; + std::vector bound_buffers; + std::vector bound_textures; ShaderMetadata shader_metadata = { .name = "shader_metadata", @@ -33,14 +34,11 @@ TEST(BufferBindingsGLESTest, BindUniformData) { DeviceBufferGLES device_buffer(DeviceBufferDescriptor{.size = sizeof(float)}, reactor, backing_store); BufferView buffer_view(&device_buffer, Range(0, sizeof(float))); - vertex_bindings.buffers.push_back(BufferAndUniformSlot{ - .slot = - ShaderUniformSlot{ - .name = "foobar", .ext_res_0 = 0, .set = 0, .binding = 0}, - .view = BufferResource(&shader_metadata, buffer_view)}); - Bindings fragment_bindings; - EXPECT_TRUE(bindings.BindUniformData(mock_gl->GetProcTable(), vertex_bindings, - fragment_bindings)); + bound_buffers.push_back(BufferResource(&shader_metadata, buffer_view)); + + EXPECT_TRUE(bindings.BindUniformData(mock_gl->GetProcTable(), bound_textures, + bound_buffers, Range{0, 0}, + Range{0, 1})); std::vector captured_calls = mock_gl->GetCapturedCalls(); EXPECT_TRUE(std::find(captured_calls.begin(), captured_calls.end(), "glUniform1fv") != captured_calls.end()); diff --git a/engine/src/flutter/impeller/renderer/backend/gles/render_pass_gles.cc b/engine/src/flutter/impeller/renderer/backend/gles/render_pass_gles.cc index 7c273d74ed..c1308ee445 100644 --- a/engine/src/flutter/impeller/renderer/backend/gles/render_pass_gles.cc +++ b/engine/src/flutter/impeller/renderer/backend/gles/render_pass_gles.cc @@ -18,6 +18,7 @@ #include "impeller/renderer/backend/gles/gpu_tracer_gles.h" #include "impeller/renderer/backend/gles/pipeline_gles.h" #include "impeller/renderer/backend/gles/texture_gles.h" +#include "impeller/renderer/command.h" namespace impeller { @@ -188,9 +189,10 @@ void RenderPassGLES::ResetGLState(const ProcTableGLES& gl) { [[nodiscard]] bool EncodeCommandsInReactor( const RenderPassData& pass_data, - const std::shared_ptr& transients_allocator, const ReactorGLES& reactor, const std::vector& commands, + const std::vector& bound_textures, + const std::vector& bound_buffers, const std::shared_ptr& tracer) { TRACE_EVENT0("impeller", "RenderPassGLES::EncodeCommandsInReactor"); @@ -456,10 +458,13 @@ void RenderPassGLES::ResetGLState(const ProcTableGLES& gl) { //-------------------------------------------------------------------------- /// Bind uniform data. /// - if (!vertex_desc_gles->BindUniformData(gl, // - command.vertex_bindings, // - command.fragment_bindings // - )) { + if (!vertex_desc_gles->BindUniformData( + gl, // + bound_textures, // + bound_buffers, // + /*texture_range=*/command.bound_textures, // + /*buffer_range=*/command.bound_buffers // + )) { return false; } @@ -602,13 +607,18 @@ bool RenderPassGLES::OnEncodeCommands(const Context& context) const { CanDiscardAttachmentWhenDone(stencil0->store_action); } - std::shared_ptr shared_this = shared_from_this(); - auto tracer = ContextGLES::Cast(context).GetGPUTracer(); return reactor_->AddOperation( - [pass_data, allocator = context.GetResourceAllocator(), - render_pass = std::move(shared_this), tracer](const auto& reactor) { - auto result = EncodeCommandsInReactor(*pass_data, allocator, reactor, - render_pass->commands_, tracer); + [pass_data = std::move(pass_data), render_pass = shared_from_this(), + tracer = + ContextGLES::Cast(context).GetGPUTracer()](const auto& reactor) { + auto result = EncodeCommandsInReactor( + /*pass_data=*/*pass_data, // + /*reactor=*/reactor, // + /*commands=*/render_pass->commands_, // + /*bound_textures=*/render_pass->bound_textures_, // + /*bound_buffers=*/render_pass->bound_buffers_, // + /*tracer=*/tracer // + ); FML_CHECK(result) << "Must be able to encode GL commands without error."; }, diff --git a/engine/src/flutter/impeller/renderer/backend/metal/render_pass_mtl.h b/engine/src/flutter/impeller/renderer/backend/metal/render_pass_mtl.h index 476cde4b93..ee244ce1e9 100644 --- a/engine/src/flutter/impeller/renderer/backend/metal/render_pass_mtl.h +++ b/engine/src/flutter/impeller/renderer/backend/metal/render_pass_mtl.h @@ -48,9 +48,6 @@ class RenderPassMTL final : public RenderPass { const RenderTarget& target, id buffer); - // |RenderPass| - void ReserveCommands(size_t command_count) override {} - // |RenderPass| bool IsValid() const override; diff --git a/engine/src/flutter/impeller/renderer/backend/vulkan/render_pass_vk.h b/engine/src/flutter/impeller/renderer/backend/vulkan/render_pass_vk.h index d652f23f50..d442e08882 100644 --- a/engine/src/flutter/impeller/renderer/backend/vulkan/render_pass_vk.h +++ b/engine/src/flutter/impeller/renderer/backend/vulkan/render_pass_vk.h @@ -92,9 +92,6 @@ class RenderPassVK final : public RenderPass { // |RenderPass| fml::Status Draw() override; - // |RenderPass| - void ReserveCommands(size_t command_count) override {} - // |ResourceBinder| bool BindResource(ShaderStage stage, DescriptorType type, diff --git a/engine/src/flutter/impeller/renderer/command.cc b/engine/src/flutter/impeller/renderer/command.cc index 513f694ab4..bd17e02a50 100644 --- a/engine/src/flutter/impeller/renderer/command.cc +++ b/engine/src/flutter/impeller/renderer/command.cc @@ -4,11 +4,8 @@ #include "impeller/renderer/command.h" -#include - #include "impeller/base/validation.h" #include "impeller/core/formats.h" -#include "impeller/renderer/vertex_descriptor.h" namespace impeller { @@ -26,112 +23,4 @@ bool Command::BindVertices(const VertexBuffer& buffer) { return true; } -bool Command::BindResource(ShaderStage stage, - DescriptorType type, - const ShaderUniformSlot& slot, - const ShaderMetadata* metadata, - BufferView view) { - FML_DCHECK(slot.ext_res_0 != VertexDescriptor::kReservedVertexBufferIndex); - if (!view) { - return false; - } - BufferResource resouce = BufferResource(metadata, std::move(view)); - return BindBuffer(stage, slot, std::move(resouce)); -} - -bool Command::BindDynamicResource(ShaderStage stage, - DescriptorType type, - const ShaderUniformSlot& slot, - std::unique_ptr metadata, - BufferView view) { - FML_DCHECK(slot.ext_res_0 != VertexDescriptor::kReservedVertexBufferIndex); - if (!view) { - return false; - } - BufferResource resouce = - BufferResource::MakeDynamic(std::move(metadata), std::move(view)); - - return BindBuffer(stage, slot, std::move(resouce)); -} - -bool Command::BindResource(ShaderStage stage, - DescriptorType type, - const SampledImageSlot& slot, - const ShaderMetadata* metadata, - std::shared_ptr texture, - const std::unique_ptr& sampler) { - if (!sampler) { - return false; - } - if (!texture || !texture->IsValid()) { - return false; - } - TextureResource resource = TextureResource(metadata, std::move(texture)); - return BindTexture(stage, slot, std::move(resource), sampler); -} - -bool Command::BindDynamicResource( - ShaderStage stage, - DescriptorType type, - const SampledImageSlot& slot, - std::unique_ptr metadata, - std::shared_ptr texture, - const std::unique_ptr& sampler) { - if (!sampler) { - return false; - } - if (!texture || !texture->IsValid()) { - return false; - } - TextureResource resource = - TextureResource::MakeDynamic(std::move(metadata), std::move(texture)); - return BindTexture(stage, slot, std::move(resource), sampler); -} - -bool Command::BindBuffer(ShaderStage stage, - const ShaderUniformSlot& slot, - BufferResource resource) { - BufferAndUniformSlot data = - BufferAndUniformSlot{.slot = slot, .view = std::move(resource)}; - - switch (stage) { - case ShaderStage::kVertex: - vertex_bindings.buffers.push_back(std::move(data)); - return true; - case ShaderStage::kFragment: - fragment_bindings.buffers.push_back(std::move(data)); - return true; - case ShaderStage::kCompute: - VALIDATION_LOG << "Use ComputeCommands for compute shader stages."; - case ShaderStage::kUnknown: - return false; - } - - return false; -} - -bool Command::BindTexture(ShaderStage stage, - const SampledImageSlot& slot, - TextureResource resource, - const std::unique_ptr& sampler) { - TextureAndSampler data = TextureAndSampler{ - .slot = slot, - .texture = std::move(resource), - .sampler = &sampler, - }; - - switch (stage) { - case ShaderStage::kVertex: - vertex_bindings.sampled_images.push_back(std::move(data)); - return true; - case ShaderStage::kFragment: - fragment_bindings.sampled_images.push_back((std::move(data))); - return true; - case ShaderStage::kCompute: - VALIDATION_LOG << "Use ComputeCommands for compute shader stages."; - case ShaderStage::kUnknown: - return false; - } -} - } // namespace impeller diff --git a/engine/src/flutter/impeller/renderer/command.h b/engine/src/flutter/impeller/renderer/command.h index 29e41bb530..13ee566317 100644 --- a/engine/src/flutter/impeller/renderer/command.h +++ b/engine/src/flutter/impeller/renderer/command.h @@ -12,7 +12,6 @@ #include "impeller/core/buffer_view.h" #include "impeller/core/formats.h" -#include "impeller/core/resource_binder.h" #include "impeller/core/sampler.h" #include "impeller/core/shader_types.h" #include "impeller/core/texture.h" @@ -22,12 +21,6 @@ namespace impeller { -#ifdef IMPELLER_DEBUG -#define DEBUG_COMMAND_INFO(obj, arg) obj.label = arg; -#else -#define DEBUG_COMMAND_INFO(obj, arg) -#endif // IMPELLER_DEBUG - template class Resource { public: @@ -65,21 +58,11 @@ using TextureResource = Resource>; /// @brief combines the texture, sampler and sampler slot information. struct TextureAndSampler { SampledImageSlot slot; + ShaderStage stage; TextureResource texture; const std::unique_ptr* sampler; }; -/// @brief combines the buffer resource and its uniform slot information. -struct BufferAndUniformSlot { - ShaderUniformSlot slot; - BufferResource view; -}; - -struct Bindings { - std::vector sampled_images; - std::vector buffers; -}; - //------------------------------------------------------------------------------ /// @brief An object used to specify work to the GPU along with references /// to resources the GPU will used when doing said work. @@ -94,21 +77,16 @@ struct Bindings { /// referenced in commands views into buffers managed by other /// allocators and resource managers. /// -struct Command : public ResourceBinder { +struct Command { //---------------------------------------------------------------------------- /// The pipeline to use for this command. /// std::shared_ptr> pipeline; - //---------------------------------------------------------------------------- - /// The buffer, texture, and sampler bindings used by the vertex pipeline - /// stage. - /// - Bindings vertex_bindings; - //---------------------------------------------------------------------------- - /// The buffer, texture, and sampler bindings used by the fragment pipeline - /// stage. - /// - Bindings fragment_bindings; + + /// An offset into render pass storage where bound buffers/texture metadata is + /// stored. + Range bound_buffers = Range{0, 0}; + Range bound_textures = Range{0, 0}; #ifdef IMPELLER_DEBUG //---------------------------------------------------------------------------- @@ -184,45 +162,7 @@ struct Command : public ResourceBinder { /// bool BindVertices(const VertexBuffer& buffer); - // |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, - const std::unique_ptr& sampler) override; - - bool BindDynamicResource(ShaderStage stage, - DescriptorType type, - const ShaderUniformSlot& slot, - std::unique_ptr metadata, - BufferView view); - - bool BindDynamicResource(ShaderStage stage, - DescriptorType type, - const SampledImageSlot& slot, - std::unique_ptr metadata, - std::shared_ptr texture, - const std::unique_ptr& sampler); - bool IsValid() const { return pipeline && pipeline->IsValid(); } - - private: - bool BindBuffer(ShaderStage stage, - const ShaderUniformSlot& slot, - BufferResource resource); - - bool BindTexture(ShaderStage stage, - const SampledImageSlot& slot, - TextureResource resource, - const std::unique_ptr& sampler); }; } // namespace impeller diff --git a/engine/src/flutter/impeller/renderer/render_pass.cc b/engine/src/flutter/impeller/renderer/render_pass.cc index 028238ad97..e498589021 100644 --- a/engine/src/flutter/impeller/renderer/render_pass.cc +++ b/engine/src/flutter/impeller/renderer/render_pass.cc @@ -194,8 +194,12 @@ bool RenderPass::ValidateIndexBuffer(const BufferView& index_buffer, } fml::Status RenderPass::Draw() { + pending_.bound_buffers.offset = bound_buffers_start_.value_or(0u); + pending_.bound_textures.offset = bound_textures_start_.value_or(0u); auto result = AddCommand(std::move(pending_)); pending_ = Command{}; + bound_textures_start_ = std::nullopt; + bound_buffers_start_ = std::nullopt; if (result) { return fml::Status(); } @@ -209,7 +213,12 @@ bool RenderPass::BindResource(ShaderStage stage, const ShaderUniformSlot& slot, const ShaderMetadata* metadata, BufferView view) { - return pending_.BindResource(stage, type, slot, metadata, view); + FML_DCHECK(slot.ext_res_0 != VertexDescriptor::kReservedVertexBufferIndex); + if (!view) { + return false; + } + BufferResource resouce = BufferResource(metadata, std::move(view)); + return BindBuffer(stage, slot, std::move(resouce)); } // |ResourceBinder| @@ -219,8 +228,14 @@ bool RenderPass::BindResource(ShaderStage stage, const ShaderMetadata* metadata, std::shared_ptr texture, const std::unique_ptr& sampler) { - return pending_.BindResource(stage, type, slot, metadata, std::move(texture), - sampler); + if (!sampler) { + return false; + } + if (!texture || !texture->IsValid()) { + return false; + } + TextureResource resource = TextureResource(metadata, std::move(texture)); + return BindTexture(stage, slot, std::move(resource), sampler); } bool RenderPass::BindDynamicResource(ShaderStage stage, @@ -228,8 +243,14 @@ bool RenderPass::BindDynamicResource(ShaderStage stage, const ShaderUniformSlot& slot, std::unique_ptr metadata, BufferView view) { - return pending_.BindDynamicResource(stage, type, slot, std::move(metadata), - std::move(view)); + FML_DCHECK(slot.ext_res_0 != VertexDescriptor::kReservedVertexBufferIndex); + if (!view) { + return false; + } + BufferResource resouce = + BufferResource::MakeDynamic(std::move(metadata), std::move(view)); + + return BindBuffer(stage, slot, std::move(resouce)); } bool RenderPass::BindDynamicResource( @@ -239,8 +260,46 @@ bool RenderPass::BindDynamicResource( std::unique_ptr metadata, std::shared_ptr texture, const std::unique_ptr& sampler) { - return pending_.BindDynamicResource(stage, type, slot, std::move(metadata), - std::move(texture), sampler); + if (!sampler) { + return false; + } + if (!texture || !texture->IsValid()) { + return false; + } + TextureResource resource = + TextureResource::MakeDynamic(std::move(metadata), std::move(texture)); + return BindTexture(stage, slot, std::move(resource), sampler); +} + +bool RenderPass::BindBuffer(ShaderStage stage, + const ShaderUniformSlot& slot, + BufferResource resource) { + if (!bound_buffers_start_.has_value()) { + bound_buffers_start_ = bound_buffers_.size(); + } + + pending_.bound_buffers.length++; + bound_buffers_.push_back(std::move(resource)); + return true; +} + +bool RenderPass::BindTexture(ShaderStage stage, + const SampledImageSlot& slot, + TextureResource resource, + const std::unique_ptr& sampler) { + TextureAndSampler data = TextureAndSampler{ + .stage = stage, + .texture = std::move(resource), + .sampler = &sampler, + }; + + if (!bound_textures_start_.has_value()) { + bound_textures_start_ = bound_textures_.size(); + } + + pending_.bound_textures.length++; + bound_textures_.push_back(std::move(data)); + return true; } } // namespace impeller diff --git a/engine/src/flutter/impeller/renderer/render_pass.h b/engine/src/flutter/impeller/renderer/render_pass.h index dc590d307d..2ef60aecf1 100644 --- a/engine/src/flutter/impeller/renderer/render_pass.h +++ b/engine/src/flutter/impeller/renderer/render_pass.h @@ -18,9 +18,6 @@ namespace impeller { -class HostBuffer; -class Allocator; - //------------------------------------------------------------------------------ /// @brief Render passes encode render commands directed as one specific /// render target into an underlying command buffer. @@ -46,13 +43,6 @@ class RenderPass : public ResourceBinder { void SetLabel(std::string_view label); - /// @brief Reserve [command_count] commands in the HAL command buffer. - /// - /// Note: this is not the native command buffer. - virtual void ReserveCommands(size_t command_count) { - commands_.reserve(command_count); - } - //---------------------------------------------------------------------------- /// The pipeline to use for this command. virtual void SetPipeline( @@ -202,6 +192,7 @@ class RenderPass : public ResourceBinder { std::shared_ptr texture, const std::unique_ptr& sampler); + /// @brief Bind with dynamically generated shader metadata. virtual bool BindDynamicResource(ShaderStage stage, DescriptorType type, const ShaderUniformSlot& slot, @@ -253,6 +244,8 @@ class RenderPass : public ResourceBinder { const ISize render_target_size_; const RenderTarget render_target_; std::vector commands_; + std::vector bound_buffers_; + std::vector bound_textures_; const Matrix orthographic_; //---------------------------------------------------------------------------- @@ -284,7 +277,18 @@ class RenderPass : public ResourceBinder { RenderPass& operator=(const RenderPass&) = delete; + bool BindBuffer(ShaderStage stage, + const ShaderUniformSlot& slot, + BufferResource resource); + + bool BindTexture(ShaderStage stage, + const SampledImageSlot& slot, + TextureResource resource, + const std::unique_ptr& sampler); + Command pending_; + std::optional bound_buffers_start_ = std::nullopt; + std::optional bound_textures_start_ = std::nullopt; }; } // namespace impeller diff --git a/engine/src/flutter/lib/gpu/render_pass.cc b/engine/src/flutter/lib/gpu/render_pass.cc index 1d9ec46b2d..b2f43bc2db 100644 --- a/engine/src/flutter/lib/gpu/render_pass.cc +++ b/engine/src/flutter/lib/gpu/render_pass.cc @@ -417,7 +417,7 @@ static bool BindUniform( uniform_map->insert_or_assign( uniform_struct, - impeller::BufferAndUniformSlot{ + flutter::gpu::RenderPass::BufferAndUniformSlot{ .slot = uniform_struct->slot, .view = impeller::BufferResource{ &uniform_struct->metadata, diff --git a/engine/src/flutter/lib/gpu/render_pass.h b/engine/src/flutter/lib/gpu/render_pass.h index 08dd2ee902..5c540f7618 100644 --- a/engine/src/flutter/lib/gpu/render_pass.h +++ b/engine/src/flutter/lib/gpu/render_pass.h @@ -13,6 +13,7 @@ #include "flutter/lib/ui/dart_wrapper.h" #include "fml/memory/ref_ptr.h" #include "impeller/core/formats.h" +#include "impeller/core/shader_types.h" #include "impeller/renderer/command.h" #include "impeller/renderer/render_pass.h" #include "impeller/renderer/render_target.h" @@ -56,9 +57,14 @@ class RenderPass : public RefCountedDartWrappable { bool Draw(); + struct BufferAndUniformSlot { + impeller::ShaderUniformSlot slot; + impeller::BufferResource view; + }; + using BufferUniformMap = std::unordered_map; + BufferAndUniformSlot>; using TextureUniformMap = std::unordered_map;