diff --git a/engine/src/flutter/impeller/impeller/compositor/BUILD.gn b/engine/src/flutter/impeller/impeller/compositor/BUILD.gn index 9c946b391f7..1765dfbe643 100644 --- a/engine/src/flutter/impeller/impeller/compositor/BUILD.gn +++ b/engine/src/flutter/impeller/impeller/compositor/BUILD.gn @@ -8,8 +8,8 @@ impeller_component("compositor") { sources = [ "context.h", "context.mm", - "pipeline_builder.h", - "pipeline_builder.mm", + "pipeline.h", + "pipeline.mm", "pipeline_descriptor.h", "pipeline_descriptor.mm", "pipeline_library.h", diff --git a/engine/src/flutter/impeller/impeller/compositor/context.h b/engine/src/flutter/impeller/impeller/compositor/context.h index dc007ba4d7e..6dee81f7b48 100644 --- a/engine/src/flutter/impeller/impeller/compositor/context.h +++ b/engine/src/flutter/impeller/impeller/compositor/context.h @@ -9,6 +9,7 @@ #include #include "flutter/fml/macros.h" +#include "impeller/compositor/pipeline_library.h" namespace impeller { @@ -28,11 +29,14 @@ class Context { std::shared_ptr GetShaderLibrary() const; + std::shared_ptr GetPipelineLibrary() const; + private: id device_ = nullptr; id render_queue_ = nullptr; id transfer_queue_ = nullptr; std::shared_ptr shader_library_; + std::shared_ptr pipeline_library_; bool is_valid_ = false; FML_DISALLOW_COPY_AND_ASSIGN(Context); diff --git a/engine/src/flutter/impeller/impeller/compositor/pipeline.h b/engine/src/flutter/impeller/impeller/compositor/pipeline.h new file mode 100644 index 00000000000..e3f75d7b4e8 --- /dev/null +++ b/engine/src/flutter/impeller/impeller/compositor/pipeline.h @@ -0,0 +1,35 @@ +// 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. + +#pragma once + +#include "flutter/fml/macros.h" + +#include + +namespace impeller { + +class PipelineLibrary; + +class Pipeline { + public: + enum class Type { + kUnknown, + kRender, + }; + + ~Pipeline(); + + private: + friend class PipelineLibrary; + + Type type_ = Type::kUnknown; + id state_; + + Pipeline(id state); + + FML_DISALLOW_COPY_AND_ASSIGN(Pipeline); +}; + +} // namespace impeller diff --git a/engine/src/flutter/impeller/impeller/compositor/pipeline.mm b/engine/src/flutter/impeller/impeller/compositor/pipeline.mm new file mode 100644 index 00000000000..a682a77d0c0 --- /dev/null +++ b/engine/src/flutter/impeller/impeller/compositor/pipeline.mm @@ -0,0 +1,17 @@ +// 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 "flutter/impeller/impeller/compositor/pipeline.h" + +namespace impeller { + +Pipeline::Pipeline(id state) : state_(state) { + if (state_ != nil) { + type_ = Type::kRender; + } +} + +Pipeline::~Pipeline() = default; + +} // namespace impeller diff --git a/engine/src/flutter/impeller/impeller/compositor/pipeline_builder.h b/engine/src/flutter/impeller/impeller/compositor/pipeline_builder.h deleted file mode 100644 index 5db78f14642..00000000000 --- a/engine/src/flutter/impeller/impeller/compositor/pipeline_builder.h +++ /dev/null @@ -1,43 +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. - -#pragma once - -#include -#include -#include -#include - -#include "flutter/fml/macros.h" -#include "impeller/compositor/pipeline_descriptor.h" -#include "impeller/compositor/shader_library.h" -#include "impeller/compositor/vertex_descriptor.h" - -namespace impeller { - -class PipelineBuilder { - public: - PipelineBuilder(); - - ~PipelineBuilder(); - - PipelineBuilder& SetLabel(const std::string_view& label); - - PipelineBuilder& SetSampleCount(size_t samples); - - PipelineBuilder& AddStageEntrypoint(std::shared_ptr function); - - PipelineBuilder& SetVertexDescriptor( - std::shared_ptr vertex_descriptor); - - private: - std::string label_; - size_t sample_count_ = 1; - std::unordered_map> entrypoints_; - std::shared_ptr vertex_descriptor_; - - FML_DISALLOW_COPY_AND_ASSIGN(PipelineBuilder); -}; - -} // namespace impeller diff --git a/engine/src/flutter/impeller/impeller/compositor/pipeline_builder.mm b/engine/src/flutter/impeller/impeller/compositor/pipeline_builder.mm deleted file mode 100644 index cc603842852..00000000000 --- a/engine/src/flutter/impeller/impeller/compositor/pipeline_builder.mm +++ /dev/null @@ -1,44 +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/compositor/pipeline_builder.h" - -namespace impeller { - -PipelineBuilder::PipelineBuilder() = default; - -PipelineBuilder::~PipelineBuilder() = default; - -PipelineBuilder& PipelineBuilder::SetLabel(const std::string_view& label) { - label_ = {label.data(), label.size()}; - return *this; -} - -PipelineBuilder& PipelineBuilder::SetSampleCount(size_t samples) { - sample_count_ = samples; - return *this; -} - -PipelineBuilder& PipelineBuilder::AddStageEntrypoint( - std::shared_ptr function) { - if (!function) { - return *this; - } - - if (function->GetStage() == ShaderStage::kUnknown) { - return *this; - } - - entrypoints_[function->GetStage()] = std::move(function); - - return *this; -} - -PipelineBuilder& PipelineBuilder::SetVertexDescriptor( - std::shared_ptr vertex_descriptor) { - vertex_descriptor_ = std::move(vertex_descriptor); - return *this; -} - -} // namespace impeller diff --git a/engine/src/flutter/impeller/impeller/compositor/pipeline_descriptor.h b/engine/src/flutter/impeller/impeller/compositor/pipeline_descriptor.h index 093536dae56..0b5869e756f 100644 --- a/engine/src/flutter/impeller/impeller/compositor/pipeline_descriptor.h +++ b/engine/src/flutter/impeller/impeller/compositor/pipeline_descriptor.h @@ -4,17 +4,53 @@ #pragma once +#include + +#include +#include +#include +#include +#include +#include + #include "flutter/fml/macros.h" +#include "impeller/shader_glue/shader_types.h" namespace impeller { +class ShaderFunction; +class VertexDescriptor; + class PipelineDescriptor { public: + struct HashEqual { + std::size_t operator()(const PipelineDescriptor& des) const; + bool operator()(const PipelineDescriptor& d1, + const PipelineDescriptor& d2) const; + }; + PipelineDescriptor(); ~PipelineDescriptor(); + PipelineDescriptor& SetLabel(const std::string_view& label); + + PipelineDescriptor& SetSampleCount(size_t samples); + + PipelineDescriptor& AddStageEntrypoint( + std::shared_ptr function); + + PipelineDescriptor& SetVertexDescriptor( + std::shared_ptr vertex_descriptor); + + MTLRenderPipelineDescriptor* GetMTLRenderPipelineDescriptor() const; + private: + std::string label_; + size_t sample_count_ = 1; + std::map> entrypoints_; + std::shared_ptr vertex_descriptor_; + FML_DISALLOW_COPY_AND_ASSIGN(PipelineDescriptor); }; diff --git a/engine/src/flutter/impeller/impeller/compositor/pipeline_descriptor.mm b/engine/src/flutter/impeller/impeller/compositor/pipeline_descriptor.mm index ab8c8281e56..a9d199763cb 100644 --- a/engine/src/flutter/impeller/impeller/compositor/pipeline_descriptor.mm +++ b/engine/src/flutter/impeller/impeller/compositor/pipeline_descriptor.mm @@ -4,10 +4,75 @@ #include "impeller/compositor/pipeline_descriptor.h" +#include "flutter/fml/hash_combine.h" +#include "impeller/compositor/shader_library.h" + namespace impeller { PipelineDescriptor::PipelineDescriptor() = default; PipelineDescriptor::~PipelineDescriptor() = default; +std::size_t PipelineDescriptor::HashEqual::operator()( + const PipelineDescriptor& des) const { + auto seed = fml::HashCombine(); + fml::HashCombineSeed(seed, des.label_); + for (const auto& entry : des.entrypoints_) { + fml::HashCombineSeed(seed, entry) + } +} + +bool PipelineDescriptor::HashEqual::operator()( + const PipelineDescriptor& d1, + const PipelineDescriptor& d2) const {} + +PipelineDescriptor& PipelineDescriptor::SetLabel( + const std::string_view& label) { + label_ = {label.data(), label.size()}; + return *this; +} + +PipelineDescriptor& PipelineDescriptor::SetSampleCount(size_t samples) { + sample_count_ = samples; + return *this; +} + +PipelineDescriptor& PipelineDescriptor::AddStageEntrypoint( + std::shared_ptr function) { + if (!function) { + return *this; + } + + if (function->GetStage() == ShaderStage::kUnknown) { + return *this; + } + + entrypoints_[function->GetStage()] = std::move(function); + + return *this; +} + +PipelineDescriptor& PipelineDescriptor::SetVertexDescriptor( + std::shared_ptr vertex_descriptor) { + vertex_descriptor_ = std::move(vertex_descriptor); + return *this; +} + +MTLRenderPipelineDescriptor* +PipelineDescriptor::GetMTLRenderPipelineDescriptor() const { + auto descriptor = [[MTLRenderPipelineDescriptor alloc] init]; + descriptor.label = @(label_.c_str()); + descriptor.sampleCount = sample_count_; + + for (const auto& entry : entrypoints_) { + if (entry.first == ShaderStage::kVertex) { + descriptor.vertexFunction = entry.second->GetMTLFunction(); + } + if (entry.first == ShaderStage::kFragment) { + descriptor.fragmentFunction = entry.second->GetMTLFunction(); + } + } + return descriptor; +} + } // namespace impeller diff --git a/engine/src/flutter/impeller/impeller/compositor/pipeline_library.h b/engine/src/flutter/impeller/impeller/compositor/pipeline_library.h index a20ff2a08cd..1740df363ef 100644 --- a/engine/src/flutter/impeller/impeller/compositor/pipeline_library.h +++ b/engine/src/flutter/impeller/impeller/compositor/pipeline_library.h @@ -4,17 +4,34 @@ #pragma once +#include + +#include +#include + #include "flutter/fml/macros.h" +#include "impeller/compositor/pipeline.h" +#include "impeller/compositor/pipeline_descriptor.h" namespace impeller { class PipelineLibrary { public: - PipelineLibrary(); + PipelineLibrary(id device); ~PipelineLibrary(); + std::future> GetRenderPipeline( + PipelineDescriptor descriptor); + private: + using Pipelines = std::unordered_map, + PipelineDescriptor::HashEqual, + PipelineDescriptor::HashEqual>; + id device_; + Pipelines pipelines_; + FML_DISALLOW_COPY_AND_ASSIGN(PipelineLibrary); }; diff --git a/engine/src/flutter/impeller/impeller/compositor/pipeline_library.mm b/engine/src/flutter/impeller/impeller/compositor/pipeline_library.mm index e69de29bb2d..26abd1b3035 100644 --- a/engine/src/flutter/impeller/impeller/compositor/pipeline_library.mm +++ b/engine/src/flutter/impeller/impeller/compositor/pipeline_library.mm @@ -0,0 +1,45 @@ +// 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/compositor/pipeline_library.h" + +#include + +#include "flutter/fml/logging.h" + +namespace impeller { + +PipelineLibrary::PipelineLibrary(id device) : device_(device) {} + +PipelineLibrary::~PipelineLibrary() = default; + +std::future> PipelineLibrary::GetRenderPipeline( + PipelineDescriptor descriptor) { + auto promise = std::make_shared>>(); + auto future = promise->get_future(); + if (auto found = pipelines_.find(descriptor); found != pipelines_.end()) { + promise->set_value(nullptr); + return future; + } + + auto completion_handler = + ^(id _Nullable render_pipeline_state, + NSError* _Nullable error) { + if (error != nil) { + FML_LOG(ERROR) << "Could not create render pipeline: " + << error.localizedDescription.UTF8String; + promise->set_value(nullptr); + } else { + promise->set_value( + std::shared_ptr(new Pipeline(render_pipeline_state))); + } + }; + [device_ + newRenderPipelineStateWithDescriptor:descriptor + .GetMTLRenderPipelineDescriptor() + completionHandler:completion_handler]; + return future; +} + +} // namespace impeller diff --git a/engine/src/flutter/impeller/impeller/compositor/shader_library.h b/engine/src/flutter/impeller/impeller/compositor/shader_library.h index 3a7daed01c4..76c280f5d9d 100644 --- a/engine/src/flutter/impeller/impeller/compositor/shader_library.h +++ b/engine/src/flutter/impeller/impeller/compositor/shader_library.h @@ -9,7 +9,9 @@ #include #include #include +#include +#include "flutter/fml/hash_combine.h" #include "flutter/fml/macros.h" #include "impeller/shader_glue/shader_types.h" @@ -23,6 +25,8 @@ class ShaderFunction { ShaderStage GetStage() const; + id GetMTLFunction() const; + private: friend class ShaderLibrary; @@ -38,13 +42,40 @@ class ShaderLibrary { public: ~ShaderLibrary(); - std::shared_ptr GetFunction(const std::string_view& name, - ShaderStage stage); + std::shared_ptr GetFunction( + const std::string_view& name, + ShaderStage stage); private: friend class Context; + struct ShaderKey { + std::string name; + ShaderStage stage = ShaderStage::kUnknown; + + ShaderKey(const std::string_view& p_name, ShaderStage p_stage) + : name({p_name.data(), p_name.size()}), stage(p_stage) {} + + struct Hash { + size_t operator()(const ShaderKey& key) const { + return fml::HashCombine(key.name, key.stage); + } + }; + + struct Equal { + constexpr bool operator()(const ShaderKey& k1, + const ShaderKey& k2) const { + return k1.stage == k2.stage && k1.name == k2.name; + } + }; + }; + id library_ = nullptr; + using Functions = std::unordered_map, + ShaderKey::Hash, + ShaderKey::Equal>; + Functions functions_; ShaderLibrary(id library); diff --git a/engine/src/flutter/impeller/impeller/compositor/shader_library.mm b/engine/src/flutter/impeller/impeller/compositor/shader_library.mm index 70d90d8e7c0..20b6f881ba3 100644 --- a/engine/src/flutter/impeller/impeller/compositor/shader_library.mm +++ b/engine/src/flutter/impeller/impeller/compositor/shader_library.mm @@ -11,6 +11,10 @@ ShaderFunction::ShaderFunction(id function, ShaderStage stage) ShaderFunction::~ShaderFunction() = default; +id ShaderFunction::GetMTLFunction() const { + return function_; +} + ShaderStage ShaderFunction::GetStage() const { return stage_; } @@ -19,14 +23,24 @@ ShaderLibrary::ShaderLibrary(id library) : library_(library) {} ShaderLibrary::~ShaderLibrary() = default; -std::shared_ptr ShaderLibrary::GetFunction( +std::shared_ptr ShaderLibrary::GetFunction( const std::string_view& name, ShaderStage stage) { + ShaderKey key(name, stage); + + if (auto found = functions_.find(key); found != functions_.end()) { + return found->second; + } + auto function = [library_ newFunctionWithName:@(name.data())]; if (!function) { return nullptr; } - return std::shared_ptr(new ShaderFunction(function, stage)); + + auto func = + std::shared_ptr(new ShaderFunction(function, stage)); + functions_[key] = func; + return func; } } // namespace impeller diff --git a/engine/src/flutter/impeller/impeller/primitives/box.mm b/engine/src/flutter/impeller/impeller/primitives/box.mm index 8e5895cf937..e3e3fa9d7b0 100644 --- a/engine/src/flutter/impeller/impeller/primitives/box.mm +++ b/engine/src/flutter/impeller/impeller/primitives/box.mm @@ -6,21 +6,21 @@ #include "box.frag.h" #include "box.vert.h" -#include "impeller/compositor/pipeline_builder.h" +#include "impeller/compositor/pipeline_descriptor.h" +#include "impeller/compositor/shader_library.h" namespace impeller { void RenderBox(std::shared_ptr context) { - PipelineBuilder builder; - auto fragment_function = context->GetShaderLibrary()->GetFunction( shader::BoxFragmentInfo::kEntrypointName, ShaderStage::kFragment); auto vertex_function = context->GetShaderLibrary()->GetFunction( shader::BoxVertexInfo::kEntrypointName, ShaderStage::kVertex); + PipelineDescriptor builder; + builder.SetLabel(shader::BoxVertexInfo::kLabel); builder.AddStageEntrypoint(vertex_function); builder.AddStageEntrypoint(fragment_function); - builder.SetLabel(shader::BoxVertexInfo::kLabel); } } // namespace impeller