michael@0: /* michael@0: * Copyright 2011 Google Inc. michael@0: * michael@0: * Use of this source code is governed by a BSD-style license that can be michael@0: * found in the LICENSE file. michael@0: */ michael@0: michael@0: #ifndef GrGLShaderVar_DEFINED michael@0: #define GrGLShaderVar_DEFINED michael@0: michael@0: #include "GrGLContext.h" michael@0: #include "GrGLSL.h" michael@0: #include "SkString.h" michael@0: michael@0: #define USE_UNIFORM_FLOAT_ARRAYS true michael@0: michael@0: /** michael@0: * Represents a variable in a shader michael@0: */ michael@0: class GrGLShaderVar { michael@0: public: michael@0: michael@0: /** michael@0: * Early versions of GLSL have Varying and Attribute; those are later michael@0: * deprecated, but we still need to know whether a Varying variable michael@0: * should be treated as In or Out. michael@0: */ michael@0: enum TypeModifier { michael@0: kNone_TypeModifier, michael@0: kOut_TypeModifier, michael@0: kIn_TypeModifier, michael@0: kInOut_TypeModifier, michael@0: kUniform_TypeModifier, michael@0: kAttribute_TypeModifier, michael@0: kVaryingIn_TypeModifier, michael@0: kVaryingOut_TypeModifier michael@0: }; michael@0: michael@0: enum Precision { michael@0: kLow_Precision, // lowp michael@0: kMedium_Precision, // mediump michael@0: kHigh_Precision, // highp michael@0: kDefault_Precision, // Default for the current context. We make michael@0: // fragment shaders default to mediump on ES2 michael@0: // because highp support is not guaranteed (and michael@0: // we haven't been motivated to test for it). michael@0: // Otherwise, highp. michael@0: }; michael@0: michael@0: /** michael@0: * See GL_ARB_fragment_coord_conventions. michael@0: */ michael@0: enum Origin { michael@0: kDefault_Origin, // when set to kDefault the origin field is ignored. michael@0: kUpperLeft_Origin, // only used to declare vec4 in gl_FragCoord. michael@0: }; michael@0: michael@0: /** michael@0: * Defaults to a float with no precision specifier michael@0: */ michael@0: GrGLShaderVar() { michael@0: fType = kFloat_GrSLType; michael@0: fTypeModifier = kNone_TypeModifier; michael@0: fCount = kNonArray; michael@0: fPrecision = kDefault_Precision; michael@0: fOrigin = kDefault_Origin; michael@0: fUseUniformFloatArrays = USE_UNIFORM_FLOAT_ARRAYS; michael@0: } michael@0: michael@0: GrGLShaderVar(const char* name, GrSLType type, int arrayCount = kNonArray, michael@0: Precision precision = kDefault_Precision) { michael@0: SkASSERT(kVoid_GrSLType != type); michael@0: fType = type; michael@0: fTypeModifier = kNone_TypeModifier; michael@0: fCount = arrayCount; michael@0: fPrecision = precision; michael@0: fOrigin = kDefault_Origin; michael@0: fUseUniformFloatArrays = USE_UNIFORM_FLOAT_ARRAYS; michael@0: fName = name; michael@0: } michael@0: michael@0: GrGLShaderVar(const GrGLShaderVar& var) michael@0: : fType(var.fType) michael@0: , fTypeModifier(var.fTypeModifier) michael@0: , fName(var.fName) michael@0: , fCount(var.fCount) michael@0: , fPrecision(var.fPrecision) michael@0: , fOrigin(var.fOrigin) michael@0: , fUseUniformFloatArrays(var.fUseUniformFloatArrays) { michael@0: SkASSERT(kVoid_GrSLType != var.fType); michael@0: } michael@0: michael@0: /** michael@0: * Values for array count that have special meaning. We allow 1-sized arrays. michael@0: */ michael@0: enum { michael@0: kNonArray = 0, // not an array michael@0: kUnsizedArray = -1, // an unsized array (declared with []) michael@0: }; michael@0: michael@0: /** michael@0: * Sets as a non-array. michael@0: */ michael@0: void set(GrSLType type, michael@0: TypeModifier typeModifier, michael@0: const SkString& name, michael@0: Precision precision = kDefault_Precision, michael@0: Origin origin = kDefault_Origin, michael@0: bool useUniformFloatArrays = USE_UNIFORM_FLOAT_ARRAYS) { michael@0: SkASSERT(kVoid_GrSLType != type); michael@0: fType = type; michael@0: fTypeModifier = typeModifier; michael@0: fName = name; michael@0: fCount = kNonArray; michael@0: fPrecision = precision; michael@0: fOrigin = origin; michael@0: fUseUniformFloatArrays = useUniformFloatArrays; michael@0: } michael@0: michael@0: /** michael@0: * Sets as a non-array. michael@0: */ michael@0: void set(GrSLType type, michael@0: TypeModifier typeModifier, michael@0: const char* name, michael@0: Precision precision = kDefault_Precision, michael@0: Origin origin = kDefault_Origin, michael@0: bool useUniformFloatArrays = USE_UNIFORM_FLOAT_ARRAYS) { michael@0: SkASSERT(kVoid_GrSLType != type); michael@0: fType = type; michael@0: fTypeModifier = typeModifier; michael@0: fName = name; michael@0: fCount = kNonArray; michael@0: fPrecision = precision; michael@0: fOrigin = origin; michael@0: fUseUniformFloatArrays = useUniformFloatArrays; michael@0: } michael@0: michael@0: /** michael@0: * Set all var options michael@0: */ michael@0: void set(GrSLType type, michael@0: TypeModifier typeModifier, michael@0: const SkString& name, michael@0: int count, michael@0: Precision precision = kDefault_Precision, michael@0: Origin origin = kDefault_Origin, michael@0: bool useUniformFloatArrays = USE_UNIFORM_FLOAT_ARRAYS) { michael@0: SkASSERT(kVoid_GrSLType != type); michael@0: fType = type; michael@0: fTypeModifier = typeModifier; michael@0: fName = name; michael@0: fCount = count; michael@0: fPrecision = precision; michael@0: fOrigin = origin; michael@0: fUseUniformFloatArrays = useUniformFloatArrays; michael@0: } michael@0: michael@0: /** michael@0: * Set all var options michael@0: */ michael@0: void set(GrSLType type, michael@0: TypeModifier typeModifier, michael@0: const char* name, michael@0: int count, michael@0: Precision precision = kDefault_Precision, michael@0: Origin origin = kDefault_Origin, michael@0: bool useUniformFloatArrays = USE_UNIFORM_FLOAT_ARRAYS) { michael@0: SkASSERT(kVoid_GrSLType != type); michael@0: fType = type; michael@0: fTypeModifier = typeModifier; michael@0: fName = name; michael@0: fCount = count; michael@0: fPrecision = precision; michael@0: fOrigin = origin; michael@0: fUseUniformFloatArrays = useUniformFloatArrays; michael@0: } michael@0: michael@0: /** michael@0: * Is the var an array. michael@0: */ michael@0: bool isArray() const { return kNonArray != fCount; } michael@0: /** michael@0: * Is this an unsized array, (i.e. declared with []). michael@0: */ michael@0: bool isUnsizedArray() const { return kUnsizedArray == fCount; } michael@0: /** michael@0: * Get the array length of the var. michael@0: */ michael@0: int getArrayCount() const { return fCount; } michael@0: /** michael@0: * Set the array length of the var michael@0: */ michael@0: void setArrayCount(int count) { fCount = count; } michael@0: /** michael@0: * Set to be a non-array. michael@0: */ michael@0: void setNonArray() { fCount = kNonArray; } michael@0: /** michael@0: * Set to be an unsized array. michael@0: */ michael@0: void setUnsizedArray() { fCount = kUnsizedArray; } michael@0: michael@0: /** michael@0: * Access the var name as a writable string michael@0: */ michael@0: SkString* accessName() { return &fName; } michael@0: /** michael@0: * Set the var name michael@0: */ michael@0: void setName(const SkString& n) { fName = n; } michael@0: void setName(const char* n) { fName = n; } michael@0: michael@0: /** michael@0: * Get the var name. michael@0: */ michael@0: const SkString& getName() const { return fName; } michael@0: michael@0: /** michael@0: * Shortcut for this->getName().c_str(); michael@0: */ michael@0: const char* c_str() const { return this->getName().c_str(); } michael@0: michael@0: /** michael@0: * Get the type of the var michael@0: */ michael@0: GrSLType getType() const { return fType; } michael@0: /** michael@0: * Set the type of the var michael@0: */ michael@0: void setType(GrSLType type) { fType = type; } michael@0: michael@0: TypeModifier getTypeModifier() const { return fTypeModifier; } michael@0: void setTypeModifier(TypeModifier type) { fTypeModifier = type; } michael@0: michael@0: /** michael@0: * Get the precision of the var michael@0: */ michael@0: Precision getPrecision() const { return fPrecision; } michael@0: michael@0: /** michael@0: * Set the precision of the var michael@0: */ michael@0: void setPrecision(Precision p) { fPrecision = p; } michael@0: michael@0: /** michael@0: * Get the origin of the var michael@0: */ michael@0: Origin getOrigin() const { return fOrigin; } michael@0: michael@0: /** michael@0: * Set the origin of the var michael@0: */ michael@0: void setOrigin(Origin origin) { fOrigin = origin; } michael@0: michael@0: /** michael@0: * Write a declaration of this variable to out. michael@0: */ michael@0: void appendDecl(const GrGLContextInfo& ctxInfo, SkString* out) const { michael@0: if (kUpperLeft_Origin == fOrigin) { michael@0: // this is the only place where we specify a layout modifier. If we use other layout michael@0: // modifiers in the future then they should be placed in a list. michael@0: out->append("layout(origin_upper_left) "); michael@0: } michael@0: if (this->getTypeModifier() != kNone_TypeModifier) { michael@0: out->append(TypeModifierString(this->getTypeModifier(), michael@0: ctxInfo.glslGeneration())); michael@0: out->append(" "); michael@0: } michael@0: out->append(PrecisionString(fPrecision, ctxInfo.standard())); michael@0: GrSLType effectiveType = this->getType(); michael@0: if (this->isArray()) { michael@0: if (this->isUnsizedArray()) { michael@0: out->appendf("%s %s[]", michael@0: GrGLSLTypeString(effectiveType), michael@0: this->getName().c_str()); michael@0: } else { michael@0: SkASSERT(this->getArrayCount() > 0); michael@0: out->appendf("%s %s[%d]", michael@0: GrGLSLTypeString(effectiveType), michael@0: this->getName().c_str(), michael@0: this->getArrayCount()); michael@0: } michael@0: } else { michael@0: out->appendf("%s %s", michael@0: GrGLSLTypeString(effectiveType), michael@0: this->getName().c_str()); michael@0: } michael@0: } michael@0: michael@0: void appendArrayAccess(int index, SkString* out) const { michael@0: out->appendf("%s[%d]%s", michael@0: this->getName().c_str(), michael@0: index, michael@0: fUseUniformFloatArrays ? "" : ".x"); michael@0: } michael@0: michael@0: void appendArrayAccess(const char* indexName, SkString* out) const { michael@0: out->appendf("%s[%s]%s", michael@0: this->getName().c_str(), michael@0: indexName, michael@0: fUseUniformFloatArrays ? "" : ".x"); michael@0: } michael@0: michael@0: static const char* PrecisionString(Precision p, GrGLStandard standard) { michael@0: // Desktop GLSL has added precision qualifiers but they don't do anything. michael@0: if (kGLES_GrGLStandard == standard) { michael@0: switch (p) { michael@0: case kLow_Precision: michael@0: return "lowp "; michael@0: case kMedium_Precision: michael@0: return "mediump "; michael@0: case kHigh_Precision: michael@0: return "highp "; michael@0: case kDefault_Precision: michael@0: return ""; michael@0: default: michael@0: GrCrash("Unexpected precision type."); michael@0: } michael@0: } michael@0: return ""; michael@0: } michael@0: michael@0: private: michael@0: static const char* TypeModifierString(TypeModifier t, GrGLSLGeneration gen) { michael@0: switch (t) { michael@0: case kNone_TypeModifier: michael@0: return ""; michael@0: case kIn_TypeModifier: michael@0: return "in"; michael@0: case kInOut_TypeModifier: michael@0: return "inout"; michael@0: case kOut_TypeModifier: michael@0: return "out"; michael@0: case kUniform_TypeModifier: michael@0: return "uniform"; michael@0: case kAttribute_TypeModifier: michael@0: return k110_GrGLSLGeneration == gen ? "attribute" : "in"; michael@0: case kVaryingIn_TypeModifier: michael@0: return k110_GrGLSLGeneration == gen ? "varying" : "in"; michael@0: case kVaryingOut_TypeModifier: michael@0: return k110_GrGLSLGeneration == gen ? "varying" : "out"; michael@0: default: michael@0: GrCrash("Unknown shader variable type modifier."); michael@0: return ""; // suppress warning michael@0: } michael@0: } michael@0: michael@0: GrSLType fType; michael@0: TypeModifier fTypeModifier; michael@0: SkString fName; michael@0: int fCount; michael@0: Precision fPrecision; michael@0: Origin fOrigin; michael@0: /// Work around driver bugs on some hardware that don't correctly michael@0: /// support uniform float [] michael@0: bool fUseUniformFloatArrays; michael@0: }; michael@0: michael@0: #endif