GrGLShaderBuilder.cpp revision 777c3aab0a902b0917871080d99b0a249ec06298
1/* 2 * Copyright 2012 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8#include "gl/GrGLShaderBuilder.h" 9#include "gl/GrGLProgram.h" 10#include "gl/GrGLUniformHandle.h" 11 12// number of each input/output type in a single allocation block 13static const int kVarsPerBlock = 8; 14 15// except FS outputs where we expect 2 at most. 16static const int kMaxFSOutputs = 2; 17 18// ES2 FS only guarantees mediump and lowp support 19static const GrGLShaderVar::Precision kDefaultFragmentPrecision = GrGLShaderVar::kMedium_Precision; 20 21typedef GrGLUniformManager::UniformHandle UniformHandle; 22/////////////////////////////////////////////////////////////////////////////// 23 24// Architectural assumption: always 2-d input coords. 25// Likely to become non-constant and non-static, perhaps even 26// varying by stage, if we use 1D textures for gradients! 27//const int GrGLShaderBuilder::fCoordDims = 2; 28 29GrGLShaderBuilder::GrGLShaderBuilder(const GrGLContextInfo& ctx, GrGLUniformManager& uniformManager) 30 : fUniforms(kVarsPerBlock) 31 , fVSAttrs(kVarsPerBlock) 32 , fVSOutputs(kVarsPerBlock) 33 , fGSInputs(kVarsPerBlock) 34 , fGSOutputs(kVarsPerBlock) 35 , fFSInputs(kVarsPerBlock) 36 , fFSOutputs(kMaxFSOutputs) 37 , fUsesGS(false) 38 , fVaryingDims(0) 39 , fComplexCoord(false) 40 , fContext(ctx) 41 , fUniformManager(uniformManager) 42 , fCurrentStage(kNonStageIdx) { 43} 44 45void GrGLShaderBuilder::computeSwizzle(uint32_t configFlags) { 46 static const uint32_t kMulByAlphaMask = 47 (GrGLProgram::StageDesc::kMulRGBByAlpha_RoundUp_InConfigFlag | 48 GrGLProgram::StageDesc::kMulRGBByAlpha_RoundDown_InConfigFlag); 49 50 fSwizzle = ""; 51 if (configFlags & GrGLProgram::StageDesc::kSwapRAndB_InConfigFlag) { 52 GrAssert(!(configFlags & 53 GrGLProgram::StageDesc::kSmearAlpha_InConfigFlag)); 54 GrAssert(!(configFlags & 55 GrGLProgram::StageDesc::kSmearRed_InConfigFlag)); 56 fSwizzle = ".bgra"; 57 } else if (configFlags & GrGLProgram::StageDesc::kSmearAlpha_InConfigFlag) { 58 GrAssert(!(configFlags & kMulByAlphaMask)); 59 GrAssert(!(configFlags & 60 GrGLProgram::StageDesc::kSmearRed_InConfigFlag)); 61 fSwizzle = ".aaaa"; 62 } else if (configFlags & GrGLProgram::StageDesc::kSmearRed_InConfigFlag) { 63 GrAssert(!(configFlags & kMulByAlphaMask)); 64 GrAssert(!(configFlags & 65 GrGLProgram::StageDesc::kSmearAlpha_InConfigFlag)); 66 fSwizzle = ".rrrr"; 67 } 68} 69 70void GrGLShaderBuilder::computeModulate(const char* fsInColor) { 71 if (NULL != fsInColor) { 72 fModulate.printf(" * %s", fsInColor); 73 } else { 74 fModulate.reset(); 75 } 76} 77 78void GrGLShaderBuilder::setupTextureAccess(SamplerMode samplerMode, 79 int stageNum) { 80 SkString retval; 81 82 fTexFunc = "texture2D"; 83 switch (samplerMode) { 84 case kDefault_SamplerMode: 85 GrAssert(fVaryingDims == fCoordDims); 86 // Do nothing 87 break; 88 case kProj_SamplerMode: 89 fTexFunc.append("Proj"); 90 break; 91 case kExplicitDivide_SamplerMode: 92 retval = "inCoord"; 93 retval.appendS32(stageNum); 94 fFSCode.appendf("\t%s %s = %s%s / %s%s;\n", 95 GrGLShaderVar::TypeString 96 (GrSLFloatVectorType(fCoordDims)), 97 retval.c_str(), 98 fSampleCoords.c_str(), 99 GrGLSLVectorNonhomogCoords(fVaryingDims), 100 fSampleCoords.c_str(), 101 GrGLSLVectorHomogCoord(fVaryingDims)); 102 fSampleCoords = retval; 103 break; 104 } 105 fComplexCoord = false; 106} 107 108void GrGLShaderBuilder::emitTextureLookup(const char* samplerName, 109 const char* coordName) { 110 if (NULL == coordName) { 111 coordName = fSampleCoords.c_str(); 112 } 113 fFSCode.appendf("%s(%s, %s)", fTexFunc.c_str(), samplerName, coordName); 114} 115 116void GrGLShaderBuilder::emitDefaultFetch(const char* outColor, 117 const char* samplerName) { 118 fFSCode.appendf("\t%s = ", outColor); 119 this->emitTextureLookup(samplerName); 120 fFSCode.appendf("%s%s;\n", fSwizzle.c_str(), fModulate.c_str()); 121} 122 123GrGLUniformManager::UniformHandle GrGLShaderBuilder::addUniformArray(uint32_t visibility, 124 GrSLType type, 125 const char* name, 126 int count, 127 const char** outName) { 128 GrAssert(name && strlen(name)); 129 static const uint32_t kVisibilityMask = kVertex_ShaderType | kFragment_ShaderType; 130 GrAssert(0 == (~kVisibilityMask & visibility)); 131 GrAssert(0 != visibility); 132 133 BuilderUniform& uni = fUniforms.push_back(); 134 UniformHandle h = index_to_handle(fUniforms.count() - 1); 135 GR_DEBUGCODE(UniformHandle h2 =) 136 fUniformManager.appendUniform(type, count); 137 // We expect the uniform manager to initially have no uniforms and that all uniforms are added 138 // by this function. Therefore, the handles should match. 139 GrAssert(h2 == h); 140 uni.fVariable.setType(type); 141 uni.fVariable.setTypeModifier(GrGLShaderVar::kUniform_TypeModifier); 142 SkString* uniName = uni.fVariable.accessName(); 143 if (kNonStageIdx == fCurrentStage) { 144 uniName->printf("u%s", name); 145 } else { 146 uniName->printf("u%s%d", name, fCurrentStage); 147 } 148 uni.fVariable.setArrayCount(count); 149 uni.fVisibility = visibility; 150 151 // If it is visible in both the VS and FS, the precision must match. 152 // We declare a default FS precision, but not a default VS. So set the var 153 // to use the default FS precision. 154 if ((kVertex_ShaderType | kFragment_ShaderType) == visibility) { 155 // the fragment and vertex precisions must match 156 uni.fVariable.setPrecision(kDefaultFragmentPrecision); 157 } 158 159 if (NULL != outName) { 160 *outName = uni.fVariable.c_str(); 161 } 162 163 return h; 164} 165 166const GrGLShaderVar& GrGLShaderBuilder::getUniformVariable(UniformHandle u) const { 167 return fUniforms[handle_to_index(u)].fVariable; 168} 169 170void GrGLShaderBuilder::addVarying(GrSLType type, 171 const char* name, 172 const char** vsOutName, 173 const char** fsInName) { 174 fVSOutputs.push_back(); 175 fVSOutputs.back().setType(type); 176 fVSOutputs.back().setTypeModifier(GrGLShaderVar::kOut_TypeModifier); 177 if (kNonStageIdx == fCurrentStage) { 178 fVSOutputs.back().accessName()->printf("v%s", name); 179 } else { 180 fVSOutputs.back().accessName()->printf("v%s%d", name, fCurrentStage); 181 } 182 if (vsOutName) { 183 *vsOutName = fVSOutputs.back().getName().c_str(); 184 } 185 // input to FS comes either from VS or GS 186 const SkString* fsName; 187 if (fUsesGS) { 188 // if we have a GS take each varying in as an array 189 // and output as non-array. 190 fGSInputs.push_back(); 191 fGSInputs.back().setType(type); 192 fGSInputs.back().setTypeModifier(GrGLShaderVar::kIn_TypeModifier); 193 fGSInputs.back().setUnsizedArray(); 194 *fGSInputs.back().accessName() = fVSOutputs.back().getName(); 195 fGSOutputs.push_back(); 196 fGSOutputs.back().setType(type); 197 fGSOutputs.back().setTypeModifier(GrGLShaderVar::kOut_TypeModifier); 198 fGSOutputs.back().accessName()->printf("g%s", name); 199 fsName = fGSOutputs.back().accessName(); 200 } else { 201 fsName = fVSOutputs.back().accessName(); 202 } 203 fFSInputs.push_back(); 204 fFSInputs.back().setType(type); 205 fFSInputs.back().setTypeModifier(GrGLShaderVar::kIn_TypeModifier); 206 fFSInputs.back().setName(*fsName); 207 if (fsInName) { 208 *fsInName = fsName->c_str(); 209 } 210} 211 212 213namespace { 214 215inline void append_default_precision_qualifier(GrGLShaderVar::Precision p, 216 GrGLBinding binding, 217 SkString* str) { 218 // Desktop GLSL has added precision qualifiers but they don't do anything. 219 if (kES2_GrGLBinding == binding) { 220 switch (p) { 221 case GrGLShaderVar::kHigh_Precision: 222 str->append("precision highp float;\n"); 223 break; 224 case GrGLShaderVar::kMedium_Precision: 225 str->append("precision mediump float;\n"); 226 break; 227 case GrGLShaderVar::kLow_Precision: 228 str->append("precision lowp float;\n"); 229 break; 230 case GrGLShaderVar::kDefault_Precision: 231 GrCrash("Default precision now allowed."); 232 default: 233 GrCrash("Unknown precision value."); 234 } 235 } 236} 237} 238 239void GrGLShaderBuilder::appendDecls(const VarArray& vars, SkString* out) const { 240 for (int i = 0; i < vars.count(); ++i) { 241 vars[i].appendDecl(fContext, out); 242 } 243} 244 245void GrGLShaderBuilder::appendUniformDecls(ShaderType stype, SkString* out) const { 246 for (int i = 0; i < fUniforms.count(); ++i) { 247 if (fUniforms[i].fVisibility & stype) { 248 fUniforms[i].fVariable.appendDecl(fContext, out); 249 } 250 } 251} 252 253void GrGLShaderBuilder::getShader(ShaderType type, SkString* shaderStr) const { 254 switch (type) { 255 case kVertex_ShaderType: 256 *shaderStr = fHeader; 257 this->appendUniformDecls(kVertex_ShaderType, shaderStr); 258 this->appendDecls(fVSAttrs, shaderStr); 259 this->appendDecls(fVSOutputs, shaderStr); 260 shaderStr->append(fVSCode); 261 break; 262 case kGeometry_ShaderType: 263 if (fUsesGS) { 264 *shaderStr = fHeader; 265 shaderStr->append(fGSHeader); 266 this->appendDecls(fGSInputs, shaderStr); 267 this->appendDecls(fGSOutputs, shaderStr); 268 shaderStr->append(fGSCode); 269 } else { 270 shaderStr->reset(); 271 } 272 break; 273 case kFragment_ShaderType: 274 *shaderStr = fHeader; 275 append_default_precision_qualifier(kDefaultFragmentPrecision, 276 fContext.binding(), 277 shaderStr); 278 this->appendUniformDecls(kFragment_ShaderType, shaderStr); 279 this->appendDecls(fFSInputs, shaderStr); 280 // We shouldn't have declared outputs on 1.10 281 GrAssert(k110_GrGLSLGeneration != fContext.glslGeneration() || fFSOutputs.empty()); 282 this->appendDecls(fFSOutputs, shaderStr); 283 shaderStr->append(fFSFunctions); 284 shaderStr->append(fFSCode); 285 break; 286 } 287 } 288 289void GrGLShaderBuilder::finished(GrGLuint programID) { 290 fUniformManager.getUniformLocations(programID, fUniforms); 291} 292