| // 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_SCENE_SCENE_CONTEXT_H_ |
| #define FLUTTER_IMPELLER_SCENE_SCENE_CONTEXT_H_ |
| |
| #include <memory> |
| |
| #include "impeller/core/host_buffer.h" |
| #include "impeller/renderer/context.h" |
| #include "impeller/renderer/pipeline.h" |
| #include "impeller/renderer/pipeline_descriptor.h" |
| #include "impeller/scene/pipeline_key.h" |
| |
| namespace impeller { |
| namespace scene { |
| |
| struct SceneContextOptions { |
| SampleCount sample_count = SampleCount::kCount1; |
| PrimitiveType primitive_type = PrimitiveType::kTriangle; |
| |
| struct Hash { |
| constexpr std::size_t operator()(const SceneContextOptions& o) const { |
| return fml::HashCombine(o.sample_count, o.primitive_type); |
| } |
| }; |
| |
| struct Equal { |
| constexpr bool operator()(const SceneContextOptions& lhs, |
| const SceneContextOptions& rhs) const { |
| return lhs.sample_count == rhs.sample_count && |
| lhs.primitive_type == rhs.primitive_type; |
| } |
| }; |
| |
| void ApplyToPipelineDescriptor(const Capabilities& capabilities, |
| PipelineDescriptor& desc) const; |
| }; |
| |
| class SceneContext { |
| public: |
| explicit SceneContext(std::shared_ptr<Context> context); |
| |
| ~SceneContext(); |
| |
| bool IsValid() const; |
| |
| std::shared_ptr<Pipeline<PipelineDescriptor>> GetPipeline( |
| PipelineKey key, |
| SceneContextOptions opts) const; |
| |
| std::shared_ptr<Context> GetContext() const; |
| |
| std::shared_ptr<Texture> GetPlaceholderTexture() const; |
| |
| HostBuffer& GetTransientsBuffer() const { return *host_buffer_; } |
| |
| private: |
| class PipelineVariants { |
| public: |
| virtual ~PipelineVariants() = default; |
| |
| virtual std::shared_ptr<Pipeline<PipelineDescriptor>> GetPipeline( |
| Context& context, |
| SceneContextOptions opts) = 0; |
| }; |
| |
| template <class PipelineT> |
| class PipelineVariantsT final : public PipelineVariants { |
| public: |
| explicit PipelineVariantsT(Context& context) { |
| auto desc = PipelineT::Builder::MakeDefaultPipelineDescriptor(context); |
| if (!desc.has_value()) { |
| is_valid_ = false; |
| return; |
| } |
| // Apply default ContentContextOptions to the descriptor. |
| SceneContextOptions{}.ApplyToPipelineDescriptor( |
| /*capabilities=*/*context.GetCapabilities(), |
| /*desc=*/desc.value()); |
| variants_[{}] = std::make_unique<PipelineT>(context, desc); |
| }; |
| |
| // |PipelineVariants| |
| std::shared_ptr<Pipeline<PipelineDescriptor>> GetPipeline( |
| Context& context, |
| SceneContextOptions opts) { |
| if (auto found = variants_.find(opts); found != variants_.end()) { |
| return found->second->WaitAndGet(); |
| } |
| |
| auto prototype = variants_.find({}); |
| |
| // The prototype must always be initialized in the constructor. |
| FML_CHECK(prototype != variants_.end()); |
| |
| auto variant_future = prototype->second->WaitAndGet()->CreateVariant( |
| [&context, &opts, |
| variants_count = variants_.size()](PipelineDescriptor& desc) { |
| opts.ApplyToPipelineDescriptor(*context.GetCapabilities(), desc); |
| desc.SetLabel( |
| SPrintF("%s V#%zu", desc.GetLabel().c_str(), variants_count)); |
| }); |
| auto variant = std::make_unique<PipelineT>(std::move(variant_future)); |
| auto variant_pipeline = variant->WaitAndGet(); |
| variants_[opts] = std::move(variant); |
| return variant_pipeline; |
| } |
| |
| bool IsValid() const { return is_valid_; } |
| |
| private: |
| bool is_valid_ = true; |
| std::unordered_map<SceneContextOptions, |
| std::unique_ptr<PipelineT>, |
| SceneContextOptions::Hash, |
| SceneContextOptions::Equal> |
| variants_; |
| }; |
| |
| template <typename VertexShader, typename FragmentShader> |
| /// Creates a PipelineVariantsT for the given vertex and fragment shaders. |
| /// |
| /// If a pipeline could not be created, returns nullptr. |
| std::unique_ptr<PipelineVariants> MakePipelineVariants(Context& context) { |
| auto pipeline = |
| PipelineVariantsT<RenderPipelineT<VertexShader, FragmentShader>>( |
| context); |
| if (!pipeline.IsValid()) { |
| return nullptr; |
| } |
| return std::make_unique< |
| PipelineVariantsT<RenderPipelineT<VertexShader, FragmentShader>>>( |
| std::move(pipeline)); |
| } |
| |
| std::unordered_map<PipelineKey, |
| std::unique_ptr<PipelineVariants>, |
| PipelineKey::Hash, |
| PipelineKey::Equal> |
| pipelines_; |
| |
| std::shared_ptr<Context> context_; |
| |
| bool is_valid_ = false; |
| // A 1x1 opaque white texture that can be used as a placeholder binding. |
| // Available for the lifetime of the scene context |
| std::shared_ptr<Texture> placeholder_texture_; |
| std::shared_ptr<HostBuffer> host_buffer_; |
| |
| SceneContext(const SceneContext&) = delete; |
| |
| SceneContext& operator=(const SceneContext&) = delete; |
| }; |
| |
| } // namespace scene |
| } // namespace impeller |
| |
| #endif // FLUTTER_IMPELLER_SCENE_SCENE_CONTEXT_H_ |