text: /*
   * Copyright 2014 Google Inc.
   *
   * Use of this source code is governed by a BSD-style license that can be
   * found in the LICENSE file.
   */
  
  #ifndef GrGLSLShaderBuilder_DEFINED
  #define GrGLSLShaderBuilder_DEFINED
  
  #include "include/private/SkTDArray.h"
  #include "src/gpu/GrShaderVar.h"
  #include "src/gpu/GrTBlockList.h"
  #include "src/gpu/glsl/GrGLSLUniformHandler.h"
  #include "src/sksl/SkSLString.h"
  
  #include <stdarg.h>
  
  class GrGLSLColorSpaceXformHelper;
  
  /**
    base class for all shaders builders
  */
  class GrGLSLShaderBuilder {
  public:
      GrGLSLShaderBuilder(GrGLSLProgramBuilder* program);
      virtual ~GrGLSLShaderBuilder() {}
  
      using SamplerHandle      = GrGLSLUniformHandler::SamplerHandle;
  
      /** Appends a 2D texture sample with projection if necessary. The vec length and swizzle
          order of the result depends on the GrProcessor::TextureSampler associated with the
          SamplerHandle.
          */
      void appendTextureLookup(SkString* out, SamplerHandle, const char* coordName) const;
  
      /** Version of above that appends the result to the shader code instead.*/
      void appendTextureLookup(SamplerHandle,
                               const char* coordName,
                               GrGLSLColorSpaceXformHelper* colorXformHelper = nullptr);
  
      /** Does the work of appendTextureLookup and blends the result by dst, treating the texture
          lookup a the src input to the blend. The dst is assumed to be half4 and the result is always
          a half4. If dst is nullptr we use half4(1) as the blend dst. */
      void appendTextureLookupAndBlend(const char* dst,
                                       SkBlendMode,
                                       SamplerHandle,
                                       const char* coordName,
                                       GrGLSLColorSpaceXformHelper* colorXformHelper = nullptr);
  
      /** Appends a load of an input attachment into the shader code. */
      void appendInputLoad(SamplerHandle);
  
      /** Adds a helper function to facilitate color gamut transformation, and produces code that
          returns the srcColor transformed into a new gamut (via multiplication by the xform from
          colorXformHelper). Premultiplied sources are also handled correctly (colorXformHelper
          determines if the source is premultipled or not). */
      void appendColorGamutXform(SkString* out, const char* srcColor,
                                 GrGLSLColorSpaceXformHelper* colorXformHelper);
  
      /** Version of above that appends the result to the shader code instead. */
      void appendColorGamutXform(const char* srcColor, GrGLSLColorSpaceXformHelper* colorXformHelper);
  
      /**
      * Adds a constant declaration to the top of the shader.
      */
      void defineConstant(const char* type, const char* name, const char* value) {
          this->definitions().appendf("const %s %s = %s;\n", type, name, value);
      }
  
      void defineConstant(const char* name, int value) {
          this->definitions().appendf("const int %s = %i;\n", name, value);
      }
  
      void defineConstant(const char* name, float value) {
          this->definitions().appendf("const float %s = %f;\n", name, value);
      }
  
      void defineConstantf(const char* type, const char* name, const char* fmt, ...) {
         this->definitions().appendf("const %s %s = ", type, name);
         va_list args;
         va_start(args, fmt);
         this->definitions().appendVAList(fmt, args);
         va_end(args);
         this->definitions().append(";\n");
      }
  
      void declareGlobal(const GrShaderVar&);
  
      // Generates a unique variable name for holding the result of a temporary expression when it's
      // not reasonable to just add a new block for scoping. Does not declare anything.
      SkString newTmpVarName(const char* suffix) {
          int tmpIdx = fTmpVariableCounter++;
          return SkStringPrintf("_tmp_%d_%s", tmpIdx, suffix);
      }
  
      /**
      * Called by GrGLSLProcessors to add code to one of the shaders.
      */
      void codeAppendf(const char format[], ...) SK_PRINTF_LIKE(2, 3) {
         va_list args;
         va_start(args, format);
         this->code().appendVAList(format, args);
         va_end(args);
      }
  
      void codeAppend(const char* str) { this->code().append(str); }
  
      void codeAppend(const char* str, size_t length) { this->code().append(str, length); }
  
      void codePrependf(const char format[], ...) SK_PRINTF_LIKE(2, 3) {
         va_list args;
         va_start(args, format);
         this->code().prependVAList(format, args);
         va_end(args);
      }
  
      /**
       * Appends a variable declaration to one of the shaders
       */
      void declAppend(const GrShaderVar& var);
  
      /** Emits a helper function outside of main() in the fragment shader. */
      void emitFunction(GrSLType returnType,
                        const char* name,
                        int argCnt,
                        const GrShaderVar* args,
                        const char* body,
                        SkString* outName,
                        bool forceInline = false);
  
      /*
       * Combines the various parts of the shader to create a single finalized shader string.
       */
      void finalize(uint32_t visibility);
  
      /*
       * Get parent builder for adding uniforms
       */
      GrGLSLProgramBuilder* getProgramBuilder() { return fProgramBuilder; }
  
      /**
       * Helper for begining and ending a block in the shader code.
       */
      class ShaderBlock {
      public:
          ShaderBlock(GrGLSLShaderBuilder* builder) : fBuilder(builder) {
              SkASSERT(builder);
              fBuilder->codeAppend("{");
          }
  
          ~ShaderBlock() {
              fBuilder->codeAppend("}");
          }
      private:
          GrGLSLShaderBuilder* fBuilder;
      };
  
  protected:
      typedef GrTBlockList<GrShaderVar> VarArray;
      void appendDecls(const VarArray& vars, SkString* out) const;
  
      /**
       * Features that should only be enabled internally by the builders.
       */
      enum GLSLPrivateFeature {
          kFragCoordConventions_GLSLPrivateFeature,
          kBlendEquationAdvanced_GLSLPrivateFeature,
          kBlendFuncExtended_GLSLPrivateFeature,
          kFramebufferFetch_GLSLPrivateFeature,
          kNoPerspectiveInterpolation_GLSLPrivateFeature,
          kSampleVariables_GLSLPrivateFeature,
          kLastGLSLPrivateFeature = kSampleVariables_GLSLPrivateFeature
      };
  
      /*
       * A general function which enables an extension in a shader if the feature bit is not present
       *
       * @return true if the feature bit was not yet present, false otherwise.
       */
      bool addFeature(uint32_t featureBit, const char* extensionName);
  
      enum InterfaceQualifier {
          kIn_InterfaceQualifier,
          kOut_InterfaceQualifier,
          kLastInterfaceQualifier = kOut_InterfaceQualifier
      };
  
      /*
       * A low level function to build default layout qualifiers.
       *
       *   e.g. layout(param1, param2, ...) out;
       *
       * GLSL allows default layout qualifiers for in, out, and uniform.
       */
      void addLayoutQualifier(const char* param, InterfaceQualifier);
  
      void compileAndAppendLayoutQualifiers();
  
      void nextStage() {
          fShaderStrings.push_back();
          fCodeIndex++;
      }
  
      void deleteStage() {
          fShaderStrings.pop_back();
          fCodeIndex--;
      }
  
      SkString& extensions() { return fShaderStrings[kExtensions]; }
      SkString& definitions() { return fShaderStrings[kDefinitions]; }
      SkString& precisionQualifier() { return fShaderStrings[kPrecisionQualifier]; }
      SkString& layoutQualifiers() { return fShaderStrings[kLayoutQualifiers]; }
      SkString& uniforms() { return fShaderStrings[kUniforms]; }
      SkString& inputs() { return fShaderStrings[kInputs]; }
      SkString& outputs() { return fShaderStrings[kOutputs]; }
      SkString& functions() { return fShaderStrings[kFunctions]; }
      SkString& main() { return fShaderStrings[kMain]; }
      SkString& code() { return fShaderStrings[fCodeIndex]; }
  
      virtual void onFinalize() = 0;
  
      enum {
          kExtensions,
          kDefinitions,
          kPrecisionQualifier,
          kLayoutQualifiers,
          kUniforms,
          kInputs,
          kOutputs,
          kFunctions,
          kMain,
          kCode,
  
          kPrealloc = kCode + 6,  // 6 == Reasonable upper bound on number of processor stages
      };
  
      GrGLSLProgramBuilder* fProgramBuilder;
      SkSL::String fCompilerString;
      SkSTArray<kPrealloc, SkString> fShaderStrings;
      SkString fCode;
      SkString fFunctions;
      SkString fExtensions;
  
      VarArray fInputs;
      VarArray fOutputs;
      uint32_t fFeaturesAddedMask;
      SkSTArray<1, SkString> fLayoutParams[kLastInterfaceQualifier + 1];
      int fCodeIndex;
      bool fFinalized;
  
      // Counter for generating unique scratch variable names in a shader.
      int fTmpVariableCounter;
  
      friend class GrCCCoverageProcessor; // to access code().
      friend class GrGLSLProgramBuilder;
      friend class GrGLProgramBuilder;
      friend class GrD3DPipelineStateBuilder;
      friend class GrDawnProgramBuilder;
      friend class GrGLSLVaryingHandler; // to access noperspective interpolation feature.
      friend class GrGLPathProgramBuilder; // to access fInputs.
      friend class GrVkPipelineStateBuilder;
      friend class GrMtlPipelineStateBuilder;
  };
  #endif
  