// 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 #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 class Pipeline; template struct PipelineFuture { std::optional descriptor; std::shared_future>> future; const std::shared_ptr> 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 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 CreateVariant( bool async, std::function descriptor_callback) const; protected: const std::weak_ptr library_; const T desc_; Pipeline(std::weak_ptr library, T desc); private: Pipeline(const Pipeline&) = delete; Pipeline& operator=(const Pipeline&) = delete; }; extern template class Pipeline; extern template class Pipeline; PipelineFuture CreatePipelineFuture( const Context& context, std::optional desc); PipelineFuture CreatePipelineFuture( const Context& context, std::optional desc); /// 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 RenderPipelineHandle { static_assert( ShaderStageCompatibilityChecker::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; explicit RenderPipelineHandle(const Context& context) : RenderPipelineHandle(CreatePipelineFuture( context, Builder::MakeDefaultPipelineDescriptor(context))) {} explicit RenderPipelineHandle(const Context& context, std::optional desc) : RenderPipelineHandle(CreatePipelineFuture(context, desc)) {} explicit RenderPipelineHandle(PipelineFuture future) : pipeline_future_(std::move(future)) {} std::shared_ptr> WaitAndGet() { if (did_wait_) { return pipeline_; } did_wait_ = true; if (pipeline_future_.IsValid()) { pipeline_ = pipeline_future_.Get(); } return pipeline_; } std::optional GetDescriptor() const { return pipeline_future_.descriptor; } private: PipelineFuture pipeline_future_; std::shared_ptr> pipeline_; bool did_wait_ = false; RenderPipelineHandle(const RenderPipelineHandle&) = delete; RenderPipelineHandle& operator=(const RenderPipelineHandle&) = delete; }; template class ComputePipelineHandle { public: using ComputeShader = ComputeShader_; using Builder = ComputePipelineBuilder; explicit ComputePipelineHandle(const Context& context) : ComputePipelineHandle(CreatePipelineFuture( context, Builder::MakeDefaultPipelineDescriptor(context))) {} explicit ComputePipelineHandle( const Context& context, std::optional compute_desc) : ComputePipelineHandle(CreatePipelineFuture(context, compute_desc)) {} explicit ComputePipelineHandle( PipelineFuture future) : pipeline_future_(std::move(future)) {} std::shared_ptr> WaitAndGet() { if (did_wait_) { return pipeline_; } did_wait_ = true; if (pipeline_future_.IsValid()) { pipeline_ = pipeline_future_.Get(); } return pipeline_; } private: PipelineFuture pipeline_future_; std::shared_ptr> pipeline_; bool did_wait_ = false; ComputePipelineHandle(const ComputePipelineHandle&) = delete; ComputePipelineHandle& operator=(const ComputePipelineHandle&) = delete; }; } // namespace impeller #endif // FLUTTER_IMPELLER_RENDERER_PIPELINE_H_