blob: 7bed0902d2b4833ee88239e5db6b17e0aab78d1f [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_RENDERER_PIPELINE_H_
#define FLUTTER_IMPELLER_RENDERER_PIPELINE_H_
#include <future>
#include "compute_pipeline_descriptor.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 {
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(
std::function<void(T& desc)> descriptor_callback) const;
protected:
const std::weak_ptr<PipelineLibrary> library_;
const T desc_;
Pipeline(std::weak_ptr<PipelineLibrary> library, T desc);
private:
Pipeline(const Pipeline&) = delete;
Pipeline& operator=(const Pipeline&) = delete;
};
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 {
static_assert(
ShaderStageCompatibilityChecker<VertexShader_, FragmentShader_>::Check(),
"The output slots for the fragment shader don't have matches in the "
"vertex shader's output slots. This will result in a linker error.");
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_.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;
RenderPipelineT(const RenderPipelineT&) = delete;
RenderPipelineT& operator=(const RenderPipelineT&) = delete;
};
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_.IsValid()) {
pipeline_ = pipeline_future_.Get();
}
return pipeline_;
}
private:
PipelineFuture<ComputePipelineDescriptor> pipeline_future_;
std::shared_ptr<Pipeline<ComputePipelineDescriptor>> pipeline_;
bool did_wait_ = false;
ComputePipelineT(const ComputePipelineT&) = delete;
ComputePipelineT& operator=(const ComputePipelineT&) = delete;
};
} // namespace impeller
#endif // FLUTTER_IMPELLER_RENDERER_PIPELINE_H_