blob: a38821a33f0a7c1ab461dbaf34a40fa8eaf19561 [file] [log] [blame] [edit]
// 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 <future>
#include "compute_pipeline_descriptor.h"
#include "flutter/fml/macros.h"
#include "impeller/renderer/compute_pipeline_builder.h"
#include "impeller/renderer/compute_pipeline_descriptor.h"
#include "impeller/renderer/context.h"
#include "impeller/renderer/pipeline_builder.h"
#include "impeller/renderer/pipeline_descriptor.h"
namespace impeller {
class PipelineLibrary;
template <typename PipelineDescriptor_>
class Pipeline;
// TODO(csg): Using a simple future is sub-optimal since callers that want to
// eagerly create and cache pipeline variants will have to await on the future
// to get its pipeline descriptor (unless they have explicitly cached it). This
// would be a concurrency pessimization.
//
// Use a struct that stores the future and the descriptor separately.
template <class T>
using PipelineFuture = std::shared_future<std::shared_ptr<Pipeline<T>>>;
//------------------------------------------------------------------------------
/// @brief Describes the fixed function and programmable aspects of
/// rendering and compute operations performed by commands submitted
/// to the GPU via a command buffer.
///
/// A pipeline handle must be allocated upfront and kept alive for
/// as long as possible. Do not create a pipeline object within a
/// frame workload.
///
/// This pipeline object is almost never used directly as it is
/// untyped. Use reflected shader information generated by the
/// Impeller offline shader compiler to generate a typed pipeline
/// object.
///
template <typename T>
class Pipeline {
public:
virtual ~Pipeline();
virtual bool IsValid() const = 0;
//----------------------------------------------------------------------------
/// @brief Get the descriptor that was responsible for creating this
/// pipeline. It may be copied and modified to create a pipeline
/// variant.
///
/// @return The descriptor.
///
const T& GetDescriptor() const;
PipelineFuture<T> CreateVariant(
std::function<void(T& desc)> descriptor_callback) const;
protected:
Pipeline(std::weak_ptr<PipelineLibrary> library, T desc);
private:
const std::weak_ptr<PipelineLibrary> library_;
const T desc_;
FML_DISALLOW_COPY_AND_ASSIGN(Pipeline);
};
extern template class Pipeline<PipelineDescriptor>;
extern template class Pipeline<ComputePipelineDescriptor>;
PipelineFuture<PipelineDescriptor> CreatePipelineFuture(
const Context& context,
std::optional<PipelineDescriptor> desc);
PipelineFuture<ComputePipelineDescriptor> CreatePipelineFuture(
const Context& context,
std::optional<ComputePipelineDescriptor> desc);
template <class VertexShader_, class FragmentShader_>
class RenderPipelineT {
public:
using VertexShader = VertexShader_;
using FragmentShader = FragmentShader_;
using Builder = PipelineBuilder<VertexShader, FragmentShader>;
explicit RenderPipelineT(const Context& context)
: RenderPipelineT(CreatePipelineFuture(
context,
Builder::MakeDefaultPipelineDescriptor(context))) {}
explicit RenderPipelineT(const Context& context,
std::optional<PipelineDescriptor> desc)
: RenderPipelineT(CreatePipelineFuture(context, desc)) {}
explicit RenderPipelineT(PipelineFuture<PipelineDescriptor> future)
: pipeline_future_(std::move(future)) {}
std::shared_ptr<Pipeline<PipelineDescriptor>> WaitAndGet() {
if (did_wait_) {
return pipeline_;
}
did_wait_ = true;
if (pipeline_future_.valid()) {
pipeline_ = pipeline_future_.get();
}
return pipeline_;
}
private:
PipelineFuture<PipelineDescriptor> pipeline_future_;
std::shared_ptr<Pipeline<PipelineDescriptor>> pipeline_;
bool did_wait_ = false;
FML_DISALLOW_COPY_AND_ASSIGN(RenderPipelineT);
};
template <class ComputeShader_>
class ComputePipelineT {
public:
using ComputeShader = ComputeShader_;
using Builder = ComputePipelineBuilder<ComputeShader>;
explicit ComputePipelineT(const Context& context)
: ComputePipelineT(CreatePipelineFuture(
context,
Builder::MakeDefaultPipelineDescriptor(context))) {}
explicit ComputePipelineT(
const Context& context,
std::optional<ComputePipelineDescriptor> compute_desc)
: ComputePipelineT(CreatePipelineFuture(context, compute_desc)) {}
explicit ComputePipelineT(PipelineFuture<ComputePipelineDescriptor> future)
: pipeline_future_(std::move(future)) {}
std::shared_ptr<Pipeline<ComputePipelineDescriptor>> WaitAndGet() {
if (did_wait_) {
return pipeline_;
}
did_wait_ = true;
if (pipeline_future_.valid()) {
pipeline_ = pipeline_future_.get();
}
return pipeline_;
}
private:
PipelineFuture<ComputePipelineDescriptor> pipeline_future_;
std::shared_ptr<Pipeline<ComputePipelineDescriptor>> pipeline_;
bool did_wait_ = false;
FML_DISALLOW_COPY_AND_ASSIGN(ComputePipelineT);
};
} // namespace impeller