text: /*
   * Copyright 2011 Google Inc.
   *
   * Use of this source code is governed by a BSD-style license that can be
   * found in the LICENSE file.
   */
  
  #ifndef GrGLSLShaderVar_DEFINED
  #define GrGLSLShaderVar_DEFINED
  
  #include "GrShaderVar.h"
  #include "../glsl/GrGLSL.h"
  #include "../glsl/GrGLSLCaps.h"
  
  #define USE_UNIFORM_FLOAT_ARRAYS true
  
  /**
   * Represents a variable in a shader
   */
  class GrGLSLShaderVar : public GrShaderVar {
  public:
      /**
       * Defaults to a float with no precision specifier
       */
      GrGLSLShaderVar()
          : GrShaderVar()
          , fUseUniformFloatArrays(USE_UNIFORM_FLOAT_ARRAYS) {
      }
  
      GrGLSLShaderVar(const char* name, GrSLType type, int arrayCount = kNonArray,
                      GrSLPrecision precision = kDefault_GrSLPrecision)
          : GrShaderVar(name, type, arrayCount, precision)
          , fUseUniformFloatArrays(USE_UNIFORM_FLOAT_ARRAYS) {
          SkASSERT(kVoid_GrSLType != type);
          fUseUniformFloatArrays = USE_UNIFORM_FLOAT_ARRAYS;
      }
  
      GrGLSLShaderVar(const char* name, GrSLType type, TypeModifier typeModifier,
                      int arrayCount = kNonArray, GrSLPrecision precision = kDefault_GrSLPrecision)
          : GrShaderVar(name, type, typeModifier, arrayCount, precision)
          , fUseUniformFloatArrays(USE_UNIFORM_FLOAT_ARRAYS) {
          SkASSERT(kVoid_GrSLType != type);
      }
  
      GrGLSLShaderVar(const GrShaderVar& var)
          : GrShaderVar(var)
          , fUseUniformFloatArrays(USE_UNIFORM_FLOAT_ARRAYS) {
          SkASSERT(kVoid_GrSLType != var.getType());
      }
  
      GrGLSLShaderVar(const GrGLSLShaderVar& var)
          : GrShaderVar(var.c_str(), var.getType(), var.getTypeModifier(),
                        var.getArrayCount(), var.getPrecision())
          , fUseUniformFloatArrays(var.fUseUniformFloatArrays)
          , fLayoutQualifier(var.fLayoutQualifier)
          , fExtraModifiers(var.fExtraModifiers) {
          SkASSERT(kVoid_GrSLType != var.getType());
      }
  
      /**
       * Values for array count that have special meaning. We allow 1-sized arrays.
       */
      enum {
          kNonArray     =  0, // not an array
          kUnsizedArray = -1, // an unsized array (declared with [])
      };
  
      /**
       * Sets as a non-array.
       */
      void set(GrSLType type,
               TypeModifier typeModifier,
               const SkString& name,
               GrSLPrecision precision = kDefault_GrSLPrecision,
               const char* layoutQualifier = nullptr,
               const char* extraModifiers = nullptr,
               bool useUniformFloatArrays = USE_UNIFORM_FLOAT_ARRAYS) {
          SkASSERT(kVoid_GrSLType != type);
          SkASSERT(kDefault_GrSLPrecision == precision || GrSLTypeAcceptsPrecision(type));
          INHERITED::set(type, name, typeModifier, precision);
          fLayoutQualifier = layoutQualifier;
          if (extraModifiers) {
              fExtraModifiers.printf("%s ", extraModifiers);
          }
          fUseUniformFloatArrays = useUniformFloatArrays;
      }
  
      /**
       * Sets as a non-array.
       */
      void set(GrSLType type,
               TypeModifier typeModifier,
               const char* name,
               GrSLPrecision precision = kDefault_GrSLPrecision,
               const char* layoutQualifier = nullptr,
               const char* extraModifiers = nullptr,
               bool useUniformFloatArrays = USE_UNIFORM_FLOAT_ARRAYS) {
          SkASSERT(kVoid_GrSLType != type);
          SkASSERT(kDefault_GrSLPrecision == precision || GrSLTypeAcceptsPrecision(type));
          INHERITED::set(type, name, typeModifier, precision);
          fLayoutQualifier = layoutQualifier;
          if (extraModifiers) {
              fExtraModifiers.printf("%s ", extraModifiers);
          }
          fUseUniformFloatArrays = useUniformFloatArrays;
      }
  
      /**
       * Set all var options
       */
      void set(GrSLType type,
               TypeModifier typeModifier,
               const SkString& name,
               int count,
               GrSLPrecision precision = kDefault_GrSLPrecision,
               const char* layoutQualifier = nullptr,
               const char* extraModifiers = nullptr,
               bool useUniformFloatArrays = USE_UNIFORM_FLOAT_ARRAYS) {
          SkASSERT(kVoid_GrSLType != type);
          SkASSERT(kDefault_GrSLPrecision == precision || GrSLTypeAcceptsPrecision(type));
          INHERITED::set(type, name, typeModifier, precision, count);
          fLayoutQualifier = layoutQualifier;
          if (extraModifiers) {
              fExtraModifiers.printf("%s ", extraModifiers);
          }
          fUseUniformFloatArrays = useUniformFloatArrays;
      }
  
      /**
       * Set all var options
       */
      void set(GrSLType type,
               TypeModifier typeModifier,
               const char* name,
               int count,
               GrSLPrecision precision = kDefault_GrSLPrecision,
               const char* layoutQualifier = nullptr,
               const char* extraModifiers = nullptr,
               bool useUniformFloatArrays = USE_UNIFORM_FLOAT_ARRAYS) {
          SkASSERT(kVoid_GrSLType != type);
          SkASSERT(kDefault_GrSLPrecision == precision || GrSLTypeAcceptsPrecision(type));
          INHERITED::set(type, name, typeModifier, precision, count);
          fLayoutQualifier = layoutQualifier;
          if (extraModifiers) {
              fExtraModifiers.printf("%s ", extraModifiers);
          }
          fUseUniformFloatArrays = useUniformFloatArrays;
      }
  
      /**
       * Set the layout qualifier
       */
      void setLayoutQualifier(const char* layoutQualifier) {
          fLayoutQualifier = layoutQualifier;
      }
  
      void addModifier(const char* modifier) {
          if (modifier) {
              fExtraModifiers.appendf("%s ", modifier);
          }
      }
  
      /**
       * Write a declaration of this variable to out.
       */
      void appendDecl(const GrGLSLCaps* glslCaps, SkString* out) const {
          SkASSERT(kDefault_GrSLPrecision == fPrecision || GrSLTypeAcceptsPrecision(fType));
          if (!fLayoutQualifier.isEmpty()) {
              out->appendf("layout(%s) ", fLayoutQualifier.c_str());
          }
          out->append(fExtraModifiers);
          if (this->getTypeModifier() != kNone_TypeModifier) {
              out->append(TypeModifierString(glslCaps, this->getTypeModifier()));
              out->append(" ");
          }
          GrSLType effectiveType = this->getType();
          if (glslCaps->usesPrecisionModifiers() && GrSLTypeAcceptsPrecision(effectiveType)) {
              // Desktop GLSL has added precision qualifiers but they don't do anything.
              out->appendf("%s ", GrGLSLPrecisionString(fPrecision));
          }
          if (this->isArray()) {
              if (this->isUnsizedArray()) {
                  out->appendf("%s %s[]",
                               GrGLSLTypeString(effectiveType),
                               this->getName().c_str());
              } else {
                  SkASSERT(this->getArrayCount() > 0);
                  out->appendf("%s %s[%d]",
                               GrGLSLTypeString(effectiveType),
                               this->getName().c_str(),
                               this->getArrayCount());
              }
          } else {
              out->appendf("%s %s",
                           GrGLSLTypeString(effectiveType),
                           this->getName().c_str());
          }
      }
  
      void appendArrayAccess(int index, SkString* out) const {
          out->appendf("%s[%d]%s",
                       this->getName().c_str(),
                       index,
                       fUseUniformFloatArrays ? "" : ".x");
      }
  
      void appendArrayAccess(const char* indexName, SkString* out) const {
          out->appendf("%s[%s]%s",
                       this->getName().c_str(),
                       indexName,
                       fUseUniformFloatArrays ? "" : ".x");
      }
  
  private:
      static const char* TypeModifierString(const GrGLSLCaps* glslCaps, TypeModifier t) {
          switch (t) {
              case kNone_TypeModifier:
                  return "";
              case kAttribute_TypeModifier: // fall through
              case kVaryingIn_TypeModifier: // fall through
              case kIn_TypeModifier:
                  return "in";
              case kInOut_TypeModifier:
                  return "inout";
              case kVaryingOut_TypeModifier: // fall through
              case kOut_TypeModifier:
                  return "out";
              case kUniform_TypeModifier:
                  return "uniform";
              default:
                  SkFAIL("Unknown shader variable type modifier.");
                  return ""; // suppress warning
          }
      }
  
      /// Work around driver bugs on some hardware that don't correctly
      /// support uniform float []
      bool        fUseUniformFloatArrays;
  
      SkString    fLayoutQualifier;
      SkString    fExtraModifiers;
  
      typedef GrShaderVar INHERITED;
  };
  
  #endif
  