text: // 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 "flutter/fml/logging.h"
  #include "flutter/fml/macros.h"
  #include "impeller/base/strings.h"
  #include "impeller/base/validation.h"
  #include "impeller/renderer/context.h"
  #include "impeller/renderer/formats.h"
  #include "impeller/renderer/pipeline_descriptor.h"
  #include "impeller/renderer/shader_library.h"
  #include "impeller/renderer/vertex_descriptor.h"
  
  namespace impeller {
  
  //------------------------------------------------------------------------------
  /// @brief      An optional (but highly recommended) utility for creating
  ///             pipelines from reflected shader information.
  ///
  /// @tparam     VertexShader_    The reflected vertex shader information. Found
  ///                              in a generated header file called
  ///                              <shader_name>.vert.h.
  /// @tparam     FragmentShader_  The reflected fragment shader information.
  ///                              Found in a generated header file called
  ///                              <shader_name>.frag.h.
  ///
  template <class VertexShader_, class FragmentShader_>
  struct PipelineBuilder {
   public:
    using VertexShader = VertexShader_;
    using FragmentShader = FragmentShader_;
  
    static constexpr size_t kVertexBufferIndex =
        VertexDescriptor::kReservedVertexBufferIndex;
  
    //----------------------------------------------------------------------------
    /// @brief      Create a default pipeline descriptor using the combination
    ///             reflected shader information. The descriptor can be configured
    ///             further before a pipeline state object is created using it.
    ///
    /// @param[in]  context  The context
    ///
    /// @return     If the combination of reflected shader information is
    ///             compatible and the requisite functions can be found in the
    ///             context, a pipeline descriptor.
    ///
    static std::optional<PipelineDescriptor> MakeDefaultPipelineDescriptor(
        const Context& context) {
      PipelineDescriptor desc;
      if (InitializePipelineDescriptorDefaults(context, desc)) {
        return {std::move(desc)};
      } else {
        return std::nullopt;
      }
    }
  
    [[nodiscard]] static bool InitializePipelineDescriptorDefaults(
        const Context& context,
        PipelineDescriptor& desc) {
      // Setup debug instrumentation.
      desc.SetLabel(SPrintF("%s Pipeline", FragmentShader::kLabel.data()));
  
      // Resolve pipeline entrypoints.
      {
        auto vertex_function = context.GetShaderLibrary()->GetFunction(
            VertexShader::kEntrypointName, ShaderStage::kVertex);
        auto fragment_function = context.GetShaderLibrary()->GetFunction(
            FragmentShader::kEntrypointName, ShaderStage::kFragment);
  
        if (!vertex_function || !fragment_function) {
          VALIDATION_LOG << "Could not resolve pipeline entrypoint(s) '"
                         << VertexShader::kEntrypointName << "' and '"
                         << FragmentShader::kEntrypointName
                         << "' for pipeline named '" << VertexShader::kLabel
                         << "'.";
          return false;
        }
  
        desc.AddStageEntrypoint(std::move(vertex_function));
        desc.AddStageEntrypoint(std::move(fragment_function));
      }
  
      // Setup the vertex descriptor from reflected information.
      {
        auto vertex_descriptor = std::make_shared<VertexDescriptor>();
        if (!vertex_descriptor->SetStageInputs(
                VertexShader::kAllShaderStageInputs)) {
          VALIDATION_LOG
              << "Could not configure vertex descriptor for pipeline named '"
              << VertexShader::kLabel << "'.";
          return false;
        }
        desc.SetVertexDescriptor(std::move(vertex_descriptor));
      }
  
      // Setup fragment shader output descriptions.
      {
        // Configure the sole color attachments pixel format. This is by
        // convention.
        ColorAttachmentDescriptor color0;
        color0.format = PixelFormat::kDefaultColor;
        color0.blending_enabled = true;
        desc.SetColorAttachmentDescriptor(0u, std::move(color0));
      }
  
      // Setup default stencil buffer descriptions.
      {
        StencilAttachmentDescriptor stencil0;
        stencil0.stencil_compare = CompareFunction::kEqual;
        desc.SetStencilAttachmentDescriptors(stencil0);
        desc.SetStencilPixelFormat(PixelFormat::kDefaultStencil);
      }
  
      return true;
    }
  };
  
  }  // namespace impeller
  