text: /*
   * Copyright 2018 Google Inc.
   *
   * Use of this source code is governed by a BSD-style license that can be
   * found in the LICENSE file.
   */
  
  #ifndef GrSkSLFP_DEFINED
  #define GrSkSLFP_DEFINED
  
  #include "include/core/SkRefCnt.h"
  #include "include/effects/SkRuntimeEffect.h"
  #include "include/gpu/GrContextOptions.h"
  #include "include/private/SkVx.h"
  #include "src/gpu/GrFragmentProcessor.h"
  
  #include <atomic>
  #include <utility>
  #include <vector>
  
  class GrShaderCaps;
  class SkData;
  class SkRuntimeEffect;
  
  #ifdef SK_DEBUG
  // UNIFORM_TYPE allows C++ types to be mapped onto SkRuntimeEffect::Uniform::Type
  template <typename T> struct GrFPUniformType {
      template <typename U> struct add_a_UNIFORM_TYPE_specialization_for {};
      static constexpr add_a_UNIFORM_TYPE_specialization_for<T> value = {};
  };
  #define UNIFORM_TYPE(E, ...)                                                                       \
      template <> struct GrFPUniformType<__VA_ARGS__> {                                              \
          static constexpr SkRuntimeEffect::Uniform::Type value = SkRuntimeEffect::Uniform::Type::E; \
      }
  
  UNIFORM_TYPE(kFloat,    float);
  UNIFORM_TYPE(kFloat2,   SkV2);
  UNIFORM_TYPE(kFloat4,   SkPMColor4f);
  UNIFORM_TYPE(kFloat4,   SkRect);
  UNIFORM_TYPE(kFloat4,   SkV4);
  UNIFORM_TYPE(kFloat4,   skvx::Vec<4, float>);
  UNIFORM_TYPE(kFloat4x4, SkM44);
  UNIFORM_TYPE(kInt,      int);
  
  #undef UNIFORM_TYPE
  #endif
  
  class GrSkSLFP : public GrFragmentProcessor {
  public:
      template <typename T> struct GrSpecializedUniform {
          bool specialize;
          T value;
      };
      template <typename T>
      static GrSpecializedUniform<T> Specialize(const T& value) {
          return {true, value};
      }
      template <typename T>
      static GrSpecializedUniform<T> SpecializeIf(bool condition, const T& value) {
          return {condition, value};
      }
  
      template <typename T> struct GrOptionalUniform {
          bool enabled;
          T value;
      };
      template <typename T>
      static GrOptionalUniform<T> When(bool condition, const T& value) {
          return {condition, value};
      }
  
      struct GrIgnoreOptFlags {
          std::unique_ptr<GrFragmentProcessor> child;
      };
      static GrIgnoreOptFlags IgnoreOptFlags(std::unique_ptr<GrFragmentProcessor> child) {
          return {std::move(child)};
      }
  
      enum class OptFlags : uint32_t {
          kNone                          = kNone_OptimizationFlags,
          kCompatibleWithCoverageAsAlpha = kCompatibleWithCoverageAsAlpha_OptimizationFlag,
          kPreservesOpaqueInput          = kPreservesOpaqueInput_OptimizationFlag,
          kAll                           = kCompatibleWithCoverageAsAlpha | kPreservesOpaqueInput,
      };
  
      /**
       * Both factories support a single 'input' FP, as well as a collection of other 'child' FPs.
       * The 'child' FPs correspond to the children declared in the effect's SkSL. The inputFP is
       * optional, and intended for instances that have color filter semantics. This is an implicit
       * child - if present, it's evaluated to produce the input color fed to the SkSL. Otherwise,
       * the SkSL receives this FP's input color directly.
       */
  
      /**
       * Creates a new fragment processor from an SkRuntimeEffect and a data blob containing values
       * for all of the 'uniform' variables in the SkSL source. The layout of the uniforms blob is
       * dictated by the SkRuntimeEffect.
       */
      static std::unique_ptr<GrSkSLFP> MakeWithData(
              sk_sp<SkRuntimeEffect> effect,
              const char* name,
              std::unique_ptr<GrFragmentProcessor> inputFP,
              std::unique_ptr<GrFragmentProcessor> destColorFP,
              sk_sp<SkData> uniforms,
              SkSpan<std::unique_ptr<GrFragmentProcessor>> childFPs);
  
      /*
       * Constructs a GrSkSLFP from a series of name-value pairs, corresponding to the children and
       * uniform data members of the effect's SkSL.
       * The variable length args... must contain all of the children and uniforms expected.
       * Each individual argument must be preceded by a name that matches the SkSL name of the value
       * being set. For children, the next argument must be a std::unique_ptr<GrFragmentProcessor>.
       * For uniforms, the next argument must be data of the correct size and type.
       *
       * For example, given:
       *   uniform shader input;
       *   uniform float scale;
       *   uniform half2 pt;
       *   half4 main() { ... }
       *
       * A call to GrSkSLFP would be formatted like:
       *   std::unique_ptr<GrFragmentProcessor> child = ...;
       *   float scaleVal = ...;
       *   SkV2 ptVal = ...;
       *   auto fp = GrSkSLFP::Make(effect, "my_effect", nullptr, GrSkSLFP::OptFlags::...,
       *                            "input", std::move(child),
       *                            "scale", scaleVal,
       *                            "pt", ptVal);
       *
       * The uniforms must appear in the correct order, as must the children. Technically, the two
       * lists can be interleaved. In debug builds, the number, names, and sizes of all arguments are
       * checked with assertions. In release builds, all checks are elided. In either case, the
       * uniform data is directly copied into the footer allocated after the FP.
       */
      template <typename... Args>
      static std::unique_ptr<GrSkSLFP> Make(sk_sp<SkRuntimeEffect> effect,
                                            const char* name,
                                            std::unique_ptr<GrFragmentProcessor> inputFP,
                                            OptFlags optFlags,
                                            Args&&... args) {
  #ifdef SK_DEBUG
          checkArgs(effect->fUniforms.begin(),
                    effect->fUniforms.end(),
                    effect->fChildren.begin(),
                    effect->fChildren.end(),
                    std::forward<Args>(args)...);
  #endif
  
          size_t uniformPayloadSize = UniformPayloadSize(effect.get());
          std::unique_ptr<GrSkSLFP> fp(new (uniformPayloadSize)
                                               GrSkSLFP(std::move(effect), name, optFlags));
          fp->appendArgs(fp->uniformData(), fp->uniformFlags(), std::forward<Args>(args)...);
          if (inputFP) {
              fp->setInput(std::move(inputFP));
          }
          return fp;
      }
  
      const char* name() const override { return fName; }
      std::unique_ptr<GrFragmentProcessor> clone() const override;
  
  private:
      GrSkSLFP(sk_sp<SkRuntimeEffect> effect, const char* name, OptFlags optFlags);
      GrSkSLFP(const GrSkSLFP& other);
  
      void addChild(std::unique_ptr<GrFragmentProcessor> child, bool mergeOptFlags);
      void setInput(std::unique_ptr<GrFragmentProcessor> input);
      void setDestColorFP(std::unique_ptr<GrFragmentProcessor> destColorFP);
  
      std::unique_ptr<GrGLSLFragmentProcessor> onMakeProgramImpl() const override;
  
      void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override;
  
      bool onIsEqual(const GrFragmentProcessor&) const override;
  
      SkPMColor4f constantOutputForConstantInput(const SkPMColor4f&) const override;
  
      // An instance of GrSkSLFP is always allocated with a payload immediately following the FP.
      // First the the values of all the uniforms, and then a set of flags (one per uniform).
      static size_t UniformPayloadSize(const SkRuntimeEffect* effect) {
          return effect->uniformSize() + effect->uniforms().count() * sizeof(UniformFlags);
      }
  
      const uint8_t* uniformData() const { return reinterpret_cast<const uint8_t*>(this + 1); }
            uint8_t* uniformData()       { return reinterpret_cast<      uint8_t*>(this + 1); }
  
      enum UniformFlags : uint8_t {
          kSpecialize_Flag = 0x1,
      };
  
      const UniformFlags* uniformFlags() const {
          return reinterpret_cast<const UniformFlags*>(this->uniformData() + fUniformSize);
      }
      UniformFlags* uniformFlags() {
          return reinterpret_cast<UniformFlags*>(this->uniformData() + fUniformSize);
      }
  
      // Helpers to attach variadic template args to a newly constructed FP:
  
      void appendArgs(uint8_t* uniformDataPtr, UniformFlags* uniformFlagsPtr) {
          // Base case -- no more args to append, so we're done
      }
      template <typename... Args>
      void appendArgs(uint8_t* uniformDataPtr,
                      UniformFlags* uniformFlagsPtr,
                      const char* name,
                      std::unique_ptr<GrFragmentProcessor>&& child,
                      Args&&... remainder) {
          // Child FP case -- register the child, then continue processing the remaining arguments.
          // Children aren't "uniforms" here, so the data & flags pointers don't advance.
          this->addChild(std::move(child), /*mergeOptFlags=*/true);
          this->appendArgs(uniformDataPtr, uniformFlagsPtr, std::forward<Args>(remainder)...);
      }
      // As above, but we don't merge in the child's optimization flags
      template <typename... Args>
      void appendArgs(uint8_t* uniformDataPtr,
                      UniformFlags* uniformFlagsPtr,
                      const char* name,
                      GrIgnoreOptFlags&& child,
                      Args&&... remainder) {
          // Child FP case -- register the child, then continue processing the remaining arguments.
          // Children aren't "uniforms" here, so the data & flags pointers don't advance.
          this->addChild(std::move(child.child), /*mergeOptFlags=*/false);
          this->appendArgs(uniformDataPtr, uniformFlagsPtr, std::forward<Args>(remainder)...);
      }
      template <typename T, typename... Args>
      void appendArgs(uint8_t* uniformDataPtr,
                      UniformFlags* uniformFlagsPtr,
                      const char* name,
                      const GrSpecializedUniform<T>& val,
                      Args&&... remainder) {
          // Specialized uniform case -- This just handles the specialization logic. If we want to
          // specialize on this particular value, set the flag. Then, continue processing the actual
          // value (by just peeling off the wrapper). This lets our generic `const T&` case (below)
          // handle copying the data into our uniform block, and advancing the per-value uniform
          // data and flags pointers.
          if (val.specialize) {
              *uniformFlagsPtr = static_cast<UniformFlags>(*uniformFlagsPtr | kSpecialize_Flag);
          }
          this->appendArgs(
                  uniformDataPtr, uniformFlagsPtr, name, val.value, std::forward<Args>(remainder)...);
      }
      template <typename T, typename... Args>
      void appendArgs(uint8_t* uniformDataPtr,
                      UniformFlags* uniformFlagsPtr,
                      const char* name,
                      const GrOptionalUniform<T>& val,
                      Args&&... remainder) {
          // Optional uniform case. Copy the data and advance pointers, but only if the uniform is
          // enabled. Then proceed as normal.
          if (val.enabled) {
              memcpy(uniformDataPtr, &val.value, sizeof(val.value));
              uniformDataPtr += sizeof(val.value);
              uniformFlagsPtr++;
          }
  
          this->appendArgs(uniformDataPtr, uniformFlagsPtr, std::forward<Args>(remainder)...);
      }
      template <typename T, typename... Args>
      void appendArgs(uint8_t* uniformDataPtr,
                      UniformFlags* uniformFlagsPtr,
                      const char* name,
                      const T& val,
                      Args&&... remainder) {
          // Raw uniform value case -- We copy the supplied value into our uniform data area,
          // then advance our uniform data and flags pointers.
          memcpy(uniformDataPtr, &val, sizeof(val));
          uniformDataPtr += sizeof(val);
          uniformFlagsPtr++;
          this->appendArgs(uniformDataPtr, uniformFlagsPtr, std::forward<Args>(remainder)...);
      }
  
  #ifdef SK_DEBUG
      using child_iterator = std::vector<SkRuntimeEffect::Child>::const_iterator;
      using uniform_iterator = std::vector<SkRuntimeEffect::Uniform>::const_iterator;
  
      // Validates that all args passed to the template factory have the right names, sizes, and types
      static void checkArgs(uniform_iterator uIter,
                            uniform_iterator uEnd,
                            child_iterator cIter,
                            child_iterator cEnd) {
          SkASSERTF(uIter == uEnd, "Expected more uniforms, starting with '%s'", uIter->name.c_str());
          SkASSERTF(cIter == cEnd, "Expected more children, starting with '%s'", cIter->name.c_str());
      }
      template <typename... Args>
      static void checkArgs(uniform_iterator uIter,
                            uniform_iterator uEnd,
                            child_iterator cIter,
                            child_iterator cEnd,
                            const char* name,
                            std::unique_ptr<GrFragmentProcessor>&& child,
                            Args&&... remainder) {
          // NOTE: This function (necessarily) gets an rvalue reference to child, but deliberately
          // does not use it. We leave it intact, and our caller (Make) will pass another rvalue
          // reference to appendArgs, which will then move it to call addChild.
          SkASSERTF(cIter != cEnd, "Too many children, wasn't expecting '%s'", name);
          SkASSERTF(cIter->name.equals(name),
                    "Expected child '%s', got '%s' instead",
                    cIter->name.c_str(), name);
          checkArgs(uIter, uEnd, ++cIter, cEnd, std::forward<Args>(remainder)...);
      }
      template <typename... Args>
      static void checkArgs(uniform_iterator uIter,
                            uniform_iterator uEnd,
                            child_iterator cIter,
                            child_iterator cEnd,
                            const char* name,
                            GrIgnoreOptFlags&& child,
                            Args&&... remainder) {
          // NOTE: This function (necessarily) gets an rvalue reference to child, but deliberately
          // does not use it. We leave it intact, and our caller (Make) will pass another rvalue
          // reference to appendArgs, which will then move it to call addChild.
          SkASSERTF(cIter != cEnd, "Too many children, wasn't expecting '%s'", name);
          SkASSERTF(cIter->name.equals(name),
                    "Expected child '%s', got '%s' instead",
                    cIter->name.c_str(), name);
          checkArgs(uIter, uEnd, ++cIter, cEnd, std::forward<Args>(remainder)...);
      }
      template <typename T, typename... Args>
      static void checkArgs(uniform_iterator uIter,
                            uniform_iterator uEnd,
                            child_iterator cIter,
                            child_iterator cEnd,
                            const char* name,
                            const GrSpecializedUniform<T>& val,
                            Args&&... remainder) {
          static_assert(!std::is_array<T>::value);  // No specializing arrays
          checkArgs(uIter, uEnd, cIter, cEnd, name, val.value, std::forward<Args>(remainder)...);
      }
      template <typename T, typename... Args>
      static void checkArgs(uniform_iterator uIter,
                            uniform_iterator uEnd,
                            child_iterator cIter,
                            child_iterator cEnd,
                            const char* name,
                            const GrOptionalUniform<T>& val,
                            Args&&... remainder) {
          if (val.enabled) {
              checkArgs(uIter, uEnd, cIter, cEnd, name, val.value, std::forward<Args>(remainder)...);
          } else {
              checkArgs(uIter, uEnd, cIter, cEnd, std::forward<Args>(remainder)...);
          }
      }
      template <typename T, typename... Args>
      static void checkArgs(uniform_iterator uIter,
                            uniform_iterator uEnd,
                            child_iterator cIter,
                            child_iterator cEnd,
                            const char* name,
                            const T& val,
                            Args&&... remainder) {
          SkASSERTF(uIter != uEnd, "Too many uniforms, wasn't expecting '%s'", name);
          SkASSERTF(uIter->name.equals(name),
                    "Expected uniform '%s', got '%s' instead",
                    uIter->name.c_str(), name);
          SkASSERTF(uIter->sizeInBytes() == sizeof(val),
                    "Expected uniform '%s' to be %zu bytes, got %zu instead",
                    name, uIter->sizeInBytes(), sizeof(val));
          SkASSERTF(GrFPUniformType<T>::value == uIter->type,
                    "Wrong type for uniform '%s'",
                    name);
          checkArgs(++uIter, uEnd, cIter, cEnd, std::forward<Args>(remainder)...);
      }
  #endif
  
      sk_sp<SkRuntimeEffect> fEffect;
      const char*            fName;
      uint32_t               fUniformSize;
      int                    fInputChildIndex = -1;
      int                    fDestColorChildIndex = -1;
  
      GR_DECLARE_FRAGMENT_PROCESSOR_TEST
  
      using INHERITED = GrFragmentProcessor;
  
      friend class GrGLSLSkSLFP;
  
      friend class GrSkSLFPFactory;
  };
  
  GR_MAKE_BITFIELD_CLASS_OPS(GrSkSLFP::OptFlags)
  
  #endif
  