blob: 1a56ea190506485524674c54bb74769be15b58ad [file] [log] [blame]
// 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(
/*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<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<RenderPipelineHandle<VertexShader, FragmentShader>>(
context);
if (!pipeline.IsValid()) {
return nullptr;
}
return std::make_unique<
PipelineVariantsT<RenderPipelineHandle<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_