// 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 #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); ~SceneContext(); bool IsValid() const; std::shared_ptr> GetPipeline( PipelineKey key, SceneContextOptions opts) const; std::shared_ptr GetContext() const; std::shared_ptr GetPlaceholderTexture() const; HostBuffer& GetTransientsBuffer() const { return *host_buffer_; } private: class PipelineVariants { public: virtual ~PipelineVariants() = default; virtual std::shared_ptr> GetPipeline( Context& context, SceneContextOptions opts) = 0; }; template 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(context, desc); }; // |PipelineVariants| std::shared_ptr> 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( /*async=*/false, [&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(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::Hash, SceneContextOptions::Equal> variants_; }; template /// Creates a PipelineVariantsT for the given vertex and fragment shaders. /// /// If a pipeline could not be created, returns nullptr. std::unique_ptr MakePipelineVariants(Context& context) { auto pipeline = PipelineVariantsT>( context); if (!pipeline.IsValid()) { return nullptr; } return std::make_unique< PipelineVariantsT>>( std::move(pipeline)); } std::unordered_map, PipelineKey::Hash, PipelineKey::Equal> pipelines_; std::shared_ptr 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 placeholder_texture_; std::shared_ptr host_buffer_; SceneContext(const SceneContext&) = delete; SceneContext& operator=(const SceneContext&) = delete; }; } // namespace scene } // namespace impeller #endif // FLUTTER_IMPELLER_SCENE_SCENE_CONTEXT_H_