| // 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 <memory> | |
| #include "impeller/renderer/context.h" | |
| #include "impeller/renderer/pipeline_descriptor.h" | |
| #include "impeller/scene/shaders/geometry.vert.h" | |
| #include "impeller/scene/shaders/unlit.frag.h" | |
| namespace impeller { | |
| namespace scene { | |
| using UnlitPipeline = | |
| RenderPipelineT<GeometryVertexShader, UnlitFragmentShader>; | |
| 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(PipelineDescriptor& desc) const; | |
| }; | |
| class SceneContext { | |
| public: | |
| explicit SceneContext(std::shared_ptr<Context> context); | |
| ~SceneContext(); | |
| bool IsValid() const; | |
| std::shared_ptr<Context> GetContext() const; | |
| std::shared_ptr<Texture> GetPlaceholderTexture() const; | |
| std::shared_ptr<Pipeline<PipelineDescriptor>> GetUnlitPipeline( | |
| SceneContextOptions opts) const { | |
| return GetPipeline(unlit_pipeline_, opts); | |
| } | |
| private: | |
| template <class T> | |
| using Variants = std::unordered_map<SceneContextOptions, | |
| std::unique_ptr<T>, | |
| SceneContextOptions::Hash, | |
| SceneContextOptions::Equal>; | |
| template <class TypedPipeline> | |
| std::shared_ptr<Pipeline<PipelineDescriptor>> GetPipeline( | |
| Variants<TypedPipeline>& container, | |
| SceneContextOptions opts) const { | |
| if (!IsValid()) { | |
| return nullptr; | |
| } | |
| if (auto found = container.find(opts); found != container.end()) { | |
| return found->second->WaitAndGet(); | |
| } | |
| auto prototype = container.find({}); | |
| // The prototype must always be initialized in the constructor. | |
| FML_CHECK(prototype != container.end()); | |
| auto variant_future = prototype->second->WaitAndGet()->CreateVariant( | |
| [&opts, variants_count = container.size()](PipelineDescriptor& desc) { | |
| opts.ApplyToPipelineDescriptor(desc); | |
| desc.SetLabel( | |
| SPrintF("%s V#%zu", desc.GetLabel().c_str(), variants_count)); | |
| }); | |
| auto variant = std::make_unique<TypedPipeline>(std::move(variant_future)); | |
| auto variant_pipeline = variant->WaitAndGet(); | |
| container[opts] = std::move(variant); | |
| return variant_pipeline; | |
| } | |
| std::shared_ptr<Context> context_; | |
| mutable Variants<UnlitPipeline> unlit_pipeline_; | |
| 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_; | |
| FML_DISALLOW_COPY_AND_ASSIGN(SceneContext); | |
| }; | |
| } // namespace scene | |
| } // namespace impeller |