blob: 989c33998425a293ee40bcd48e9a16b2cc498df7 [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.
#ifndef FLUTTER_IMPELLER_RENDERER_PIPELINE_H_
#define FLUTTER_IMPELLER_RENDERER_PIPELINE_H_
#include <future>
#include "compute_pipeline_descriptor.h"
#include "impeller/core/raw_ptr.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"
#include "impeller/renderer/shader_stage_compatibility_checker.h"
namespace impeller {
using PipelineKey = int64_t;
class PipelineLibrary;
template <typename PipelineDescriptor_>
class Pipeline;
template <typename T>
struct PipelineFuture {
std::optional<T> descriptor;
std::shared_future<std::shared_ptr<Pipeline<T>>> future;
const std::shared_ptr<Pipeline<T>> Get() const { return future.get(); }
bool IsValid() const { return future.valid(); }
};
//------------------------------------------------------------------------------
/// @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(
bool async,
const std::function<void(T& desc)>& descriptor_callback) const;
protected:
const std::weak_ptr<PipelineLibrary> library_;
const T desc_;
Pipeline(std::weak_ptr<PipelineLibrary> library, const T& desc);
private:
Pipeline(const Pipeline&) = delete;
Pipeline& operator=(const Pipeline&) = delete;
};
/// @brief A raw ptr to a pipeline object.
///
/// These pipeline refs are safe to use as the context will keep the
/// pipelines alive throughout rendering.
using PipelineRef = raw_ptr<Pipeline<PipelineDescriptor>>;
extern template class Pipeline<PipelineDescriptor>;
extern template class Pipeline<ComputePipelineDescriptor>;
/// @brief Create a pipeline for the given descriptor.
///
/// If `async` is true, the compilation is performed on a worker thread. The
/// returned future will complete once that work is done. If `async` is false,
/// the work is done on the current thread.
///
/// It is more performant to set async to false than to spawn a
/// worker and immediately block on the future completion.
PipelineFuture<PipelineDescriptor> CreatePipelineFuture(
const Context& context,
std::optional<PipelineDescriptor> desc,
bool async = true);
PipelineFuture<ComputePipelineDescriptor> CreatePipelineFuture(
const Context& context,
std::optional<ComputePipelineDescriptor> desc);
/// Holds a reference to a Pipeline used for rendering.
///
/// @see RenderPipelineHandle the templated subclass that stores compile-time
/// shader information.
class GenericRenderPipelineHandle {
public:
explicit GenericRenderPipelineHandle(const Context& context,
std::optional<PipelineDescriptor> desc,
bool async = true)
: GenericRenderPipelineHandle(
CreatePipelineFuture(context, std::move(desc), /*async=*/async)) {}
explicit GenericRenderPipelineHandle(
PipelineFuture<PipelineDescriptor> future)
: pipeline_future_(std::move(future)) {}
virtual ~GenericRenderPipelineHandle() = default;
std::shared_ptr<Pipeline<PipelineDescriptor>> WaitAndGet() {
if (did_wait_) {
return pipeline_;
}
did_wait_ = true;
if (pipeline_future_.IsValid()) {
pipeline_ = pipeline_future_.Get();
}
return pipeline_;
}
std::optional<PipelineDescriptor> GetDescriptor() const {
return pipeline_future_.descriptor;
}
private:
PipelineFuture<PipelineDescriptor> pipeline_future_;
std::shared_ptr<Pipeline<PipelineDescriptor>> pipeline_;
bool did_wait_ = false;
GenericRenderPipelineHandle(const GenericRenderPipelineHandle&) = delete;
GenericRenderPipelineHandle& operator=(const GenericRenderPipelineHandle&) =
delete;
};
/// Holds a reference to a Pipeline used for rendering while also maintaining
/// the vertex shader and fragment shader types at compile-time.
///
/// See also:
/// - impeller::ContentContext::Variants - the typical container for
/// RenderPipelineHandles.
template <class VertexShader_, class FragmentShader_>
class RenderPipelineHandle : public GenericRenderPipelineHandle {
public:
using VertexShader = VertexShader_;
using FragmentShader = FragmentShader_;
using Builder = PipelineBuilder<VertexShader, FragmentShader>;
explicit RenderPipelineHandle(const Context& context, bool async = true)
: GenericRenderPipelineHandle(CreatePipelineFuture(
context,
Builder::MakeDefaultPipelineDescriptor(context),
async)) {}
explicit RenderPipelineHandle(const Context& context,
std::optional<PipelineDescriptor> desc,
bool async = true)
: GenericRenderPipelineHandle(context, std::move(desc), async) {}
explicit RenderPipelineHandle(PipelineFuture<PipelineDescriptor> future)
: GenericRenderPipelineHandle(std::move(future)) {}
private:
RenderPipelineHandle(const RenderPipelineHandle&) = delete;
RenderPipelineHandle& operator=(const RenderPipelineHandle&) = delete;
};
template <class ComputeShader_>
class ComputePipelineHandle {
public:
using ComputeShader = ComputeShader_;
using Builder = ComputePipelineBuilder<ComputeShader>;
explicit ComputePipelineHandle(const Context& context)
: ComputePipelineHandle(CreatePipelineFuture(
context,
Builder::MakeDefaultPipelineDescriptor(context))) {}
explicit ComputePipelineHandle(
const Context& context,
std::optional<ComputePipelineDescriptor> compute_desc)
: ComputePipelineHandle(CreatePipelineFuture(context, compute_desc)) {}
explicit ComputePipelineHandle(
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_.IsValid()) {
pipeline_ = pipeline_future_.Get();
}
return pipeline_;
}
private:
PipelineFuture<ComputePipelineDescriptor> pipeline_future_;
std::shared_ptr<Pipeline<ComputePipelineDescriptor>> pipeline_;
bool did_wait_ = false;
ComputePipelineHandle(const ComputePipelineHandle&) = delete;
ComputePipelineHandle& operator=(const ComputePipelineHandle&) = delete;
};
} // namespace impeller
#endif // FLUTTER_IMPELLER_RENDERER_PIPELINE_H_