joshualitt | 30ba436 | 2014-08-21 20:18:45 -0700 | [diff] [blame] | 1 | /* |
| 2 | * Copyright 2014 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/GrGLProgram.h" |
| 9 | #include "gl/GrGLSLPrettyPrint.h" |
| 10 | #include "gl/GrGLUniformHandle.h" |
| 11 | #include "GrCoordTransform.h" |
| 12 | #include "GrDrawEffect.h" |
| 13 | #include "../GrGpuGL.h" |
| 14 | #include "GrGLFragmentShaderBuilder.h" |
| 15 | #include "GrGLProgramBuilder.h" |
| 16 | #include "GrTexture.h" |
| 17 | #include "GrGLVertexShaderBuilder.h" |
| 18 | #include "SkRTConf.h" |
| 19 | #include "SkTraceEvent.h" |
| 20 | |
| 21 | namespace { |
| 22 | #define GL_CALL(X) GR_GL_CALL(this->gpu()->glInterface(), X) |
| 23 | #define GL_CALL_RET(R, X) GR_GL_CALL_RET(this->gpu()->glInterface(), R, X) |
| 24 | |
| 25 | // number of each input/output type in a single allocation block |
| 26 | static const int kVarsPerBlock = 8; |
| 27 | |
| 28 | // ES2 FS only guarantees mediump and lowp support |
| 29 | static const GrGLShaderVar::Precision kDefaultFragmentPrecision = GrGLShaderVar::kMedium_Precision; |
| 30 | } |
| 31 | |
| 32 | /////////////////////////////////////////////////////////////////////////////////////////////////// |
| 33 | |
| 34 | bool GrGLProgramBuilder::genProgram(const GrEffectStage* colorStages[], |
| 35 | const GrEffectStage* coverageStages[]) { |
| 36 | const GrGLProgramDesc::KeyHeader& header = this->desc().getHeader(); |
| 37 | |
| 38 | fFS.emitCodeBeforeEffects(); |
| 39 | |
| 40 | /////////////////////////////////////////////////////////////////////////// |
| 41 | // get the initial color and coverage to feed into the first effect in each effect chain |
| 42 | |
| 43 | GrGLSLExpr4 inputColor; |
| 44 | GrGLSLExpr4 inputCoverage; |
| 45 | |
| 46 | if (GrGLProgramDesc::kUniform_ColorInput == header.fColorInput) { |
| 47 | const char* name; |
| 48 | fUniformHandles.fColorUni = |
| 49 | this->addUniform(GrGLProgramBuilder::kFragment_Visibility, |
| 50 | kVec4f_GrSLType, |
| 51 | "Color", |
| 52 | &name); |
| 53 | inputColor = GrGLSLExpr4(name); |
egdaniel | 842b086 | 2014-09-02 10:01:30 -0700 | [diff] [blame] | 54 | } else if (GrGLProgramDesc::kAllOnes_ColorInput == header.fColorInput) { |
| 55 | inputColor = GrGLSLExpr4(1); |
joshualitt | 30ba436 | 2014-08-21 20:18:45 -0700 | [diff] [blame] | 56 | } |
| 57 | |
| 58 | if (GrGLProgramDesc::kUniform_ColorInput == header.fCoverageInput) { |
| 59 | const char* name; |
| 60 | fUniformHandles.fCoverageUni = |
| 61 | this->addUniform(GrGLProgramBuilder::kFragment_Visibility, |
| 62 | kVec4f_GrSLType, |
| 63 | "Coverage", |
| 64 | &name); |
| 65 | inputCoverage = GrGLSLExpr4(name); |
egdaniel | 842b086 | 2014-09-02 10:01:30 -0700 | [diff] [blame] | 66 | } else if (GrGLProgramDesc::kAllOnes_ColorInput == header.fCoverageInput) { |
joshualitt | 30ba436 | 2014-08-21 20:18:45 -0700 | [diff] [blame] | 67 | inputCoverage = GrGLSLExpr4(1); |
| 68 | } |
| 69 | |
| 70 | this->emitCodeBeforeEffects(&inputColor, &inputCoverage); |
| 71 | |
| 72 | /////////////////////////////////////////////////////////////////////////// |
| 73 | // emit the per-effect code for both color and coverage effects |
| 74 | |
| 75 | GrGLProgramDesc::EffectKeyProvider colorKeyProvider( |
| 76 | &this->desc(), GrGLProgramDesc::EffectKeyProvider::kColor_EffectType); |
| 77 | fColorEffects.reset(this->createAndEmitEffects(colorStages, |
| 78 | this->desc().numColorEffects(), |
| 79 | colorKeyProvider, |
| 80 | &inputColor)); |
| 81 | |
| 82 | GrGLProgramDesc::EffectKeyProvider coverageKeyProvider( |
| 83 | &this->desc(), GrGLProgramDesc::EffectKeyProvider::kCoverage_EffectType); |
| 84 | fCoverageEffects.reset(this->createAndEmitEffects(coverageStages, |
| 85 | this->desc().numCoverageEffects(), |
| 86 | coverageKeyProvider, |
| 87 | &inputCoverage)); |
| 88 | |
| 89 | this->emitCodeAfterEffects(); |
| 90 | |
| 91 | fFS.emitCodeAfterEffects(inputColor, inputCoverage); |
| 92 | |
| 93 | if (!this->finish()) { |
| 94 | return false; |
| 95 | } |
| 96 | |
| 97 | return true; |
| 98 | } |
| 99 | |
| 100 | ////////////////////////////////////////////////////////////////////////////// |
| 101 | |
| 102 | GrGLProgramBuilder::GrGLProgramBuilder(GrGpuGL* gpu, |
| 103 | const GrGLProgramDesc& desc) |
kkinnunen | ec56e45 | 2014-08-25 22:21:16 -0700 | [diff] [blame] | 104 | : fFragOnly(!desc.getHeader().fRequiresVertexShader && |
| 105 | gpu->glCaps().pathRenderingSupport() && |
| 106 | gpu->glPathRendering()->texturingMode() == GrGLPathRendering::FixedFunction_TexturingMode) |
joshualitt | 30ba436 | 2014-08-21 20:18:45 -0700 | [diff] [blame] | 107 | , fTexCoordSetCnt(0) |
| 108 | , fProgramID(0) |
| 109 | , fFS(this, desc) |
kkinnunen | ec56e45 | 2014-08-25 22:21:16 -0700 | [diff] [blame] | 110 | , fSeparableVaryingInfos(kVarsPerBlock) |
joshualitt | 30ba436 | 2014-08-21 20:18:45 -0700 | [diff] [blame] | 111 | , fDesc(desc) |
| 112 | , fGpu(gpu) |
| 113 | , fUniforms(kVarsPerBlock) { |
| 114 | } |
| 115 | |
| 116 | void GrGLProgramBuilder::nameVariable(SkString* out, char prefix, const char* name) { |
| 117 | if ('\0' == prefix) { |
| 118 | *out = name; |
| 119 | } else { |
| 120 | out->printf("%c%s", prefix, name); |
| 121 | } |
| 122 | if (fCodeStage.inStageCode()) { |
| 123 | if (out->endsWith('_')) { |
| 124 | // Names containing "__" are reserved. |
| 125 | out->append("x"); |
| 126 | } |
| 127 | out->appendf("_Stage%d", fCodeStage.stageIndex()); |
| 128 | } |
| 129 | } |
| 130 | |
| 131 | GrGLProgramDataManager::UniformHandle GrGLProgramBuilder::addUniformArray(uint32_t visibility, |
| 132 | GrSLType type, |
| 133 | const char* name, |
| 134 | int count, |
| 135 | const char** outName) { |
| 136 | SkASSERT(name && strlen(name)); |
| 137 | SkDEBUGCODE(static const uint32_t kVisibilityMask = kVertex_Visibility | kFragment_Visibility); |
| 138 | SkASSERT(0 == (~kVisibilityMask & visibility)); |
| 139 | SkASSERT(0 != visibility); |
| 140 | |
| 141 | UniformInfo& uni = fUniforms.push_back(); |
| 142 | uni.fVariable.setType(type); |
| 143 | uni.fVariable.setTypeModifier(GrGLShaderVar::kUniform_TypeModifier); |
| 144 | this->nameVariable(uni.fVariable.accessName(), 'u', name); |
| 145 | uni.fVariable.setArrayCount(count); |
| 146 | uni.fVisibility = visibility; |
| 147 | |
| 148 | // If it is visible in both the VS and FS, the precision must match. |
| 149 | // We declare a default FS precision, but not a default VS. So set the var |
| 150 | // to use the default FS precision. |
| 151 | if ((kVertex_Visibility | kFragment_Visibility) == visibility) { |
| 152 | // the fragment and vertex precisions must match |
| 153 | uni.fVariable.setPrecision(kDefaultFragmentPrecision); |
| 154 | } |
| 155 | |
| 156 | if (NULL != outName) { |
| 157 | *outName = uni.fVariable.c_str(); |
| 158 | } |
| 159 | return GrGLProgramDataManager::UniformHandle::CreateFromUniformIndex(fUniforms.count() - 1); |
| 160 | } |
| 161 | |
| 162 | void GrGLProgramBuilder::appendDecls(const VarArray& vars, SkString* out) const { |
| 163 | for (int i = 0; i < vars.count(); ++i) { |
| 164 | vars[i].appendDecl(this->ctxInfo(), out); |
| 165 | out->append(";\n"); |
| 166 | } |
| 167 | } |
| 168 | |
| 169 | void GrGLProgramBuilder::appendUniformDecls(ShaderVisibility visibility, |
| 170 | SkString* out) const { |
| 171 | for (int i = 0; i < fUniforms.count(); ++i) { |
| 172 | if (fUniforms[i].fVisibility & visibility) { |
| 173 | fUniforms[i].fVariable.appendDecl(this->ctxInfo(), out); |
| 174 | out->append(";\n"); |
| 175 | } |
| 176 | } |
| 177 | } |
| 178 | |
| 179 | void GrGLProgramBuilder::createAndEmitEffects(GrGLProgramEffectsBuilder* programEffectsBuilder, |
| 180 | const GrEffectStage* effectStages[], |
| 181 | int effectCnt, |
| 182 | const GrGLProgramDesc::EffectKeyProvider& keyProvider, |
| 183 | GrGLSLExpr4* fsInOutColor) { |
| 184 | bool effectEmitted = false; |
| 185 | |
| 186 | GrGLSLExpr4 inColor = *fsInOutColor; |
| 187 | GrGLSLExpr4 outColor; |
| 188 | |
| 189 | for (int e = 0; e < effectCnt; ++e) { |
| 190 | SkASSERT(NULL != effectStages[e] && NULL != effectStages[e]->getEffect()); |
| 191 | const GrEffectStage& stage = *effectStages[e]; |
| 192 | |
| 193 | CodeStage::AutoStageRestore csar(&fCodeStage, &stage); |
| 194 | |
| 195 | if (inColor.isZeros()) { |
| 196 | SkString inColorName; |
| 197 | |
| 198 | // Effects have no way to communicate zeros, they treat an empty string as ones. |
| 199 | this->nameVariable(&inColorName, '\0', "input"); |
| 200 | fFS.codeAppendf("\tvec4 %s = %s;\n", inColorName.c_str(), inColor.c_str()); |
| 201 | inColor = inColorName; |
| 202 | } |
| 203 | |
| 204 | // create var to hold stage result |
| 205 | SkString outColorName; |
| 206 | this->nameVariable(&outColorName, '\0', "output"); |
| 207 | fFS.codeAppendf("\tvec4 %s;\n", outColorName.c_str()); |
| 208 | outColor = outColorName; |
| 209 | |
| 210 | |
| 211 | programEffectsBuilder->emitEffect(stage, |
| 212 | keyProvider.get(e), |
| 213 | outColor.c_str(), |
| 214 | inColor.isOnes() ? NULL : inColor.c_str(), |
| 215 | fCodeStage.stageIndex()); |
| 216 | |
| 217 | inColor = outColor; |
| 218 | effectEmitted = true; |
| 219 | } |
| 220 | |
| 221 | if (effectEmitted) { |
| 222 | *fsInOutColor = outColor; |
| 223 | } |
| 224 | } |
| 225 | |
| 226 | bool GrGLProgramBuilder::finish() { |
| 227 | SkASSERT(0 == fProgramID); |
| 228 | GL_CALL_RET(fProgramID, CreateProgram()); |
| 229 | if (!fProgramID) { |
| 230 | return false; |
| 231 | } |
| 232 | |
| 233 | SkTDArray<GrGLuint> shadersToDelete; |
| 234 | |
| 235 | if (!this->compileAndAttachShaders(fProgramID, &shadersToDelete)) { |
| 236 | GL_CALL(DeleteProgram(fProgramID)); |
| 237 | return false; |
| 238 | } |
| 239 | |
| 240 | this->bindProgramLocations(fProgramID); |
| 241 | |
| 242 | GL_CALL(LinkProgram(fProgramID)); |
| 243 | |
| 244 | // Calling GetProgramiv is expensive in Chromium. Assume success in release builds. |
| 245 | bool checkLinked = !fGpu->ctxInfo().isChromium(); |
| 246 | #ifdef SK_DEBUG |
| 247 | checkLinked = true; |
| 248 | #endif |
| 249 | if (checkLinked) { |
| 250 | GrGLint linked = GR_GL_INIT_ZERO; |
| 251 | GL_CALL(GetProgramiv(fProgramID, GR_GL_LINK_STATUS, &linked)); |
| 252 | if (!linked) { |
| 253 | GrGLint infoLen = GR_GL_INIT_ZERO; |
| 254 | GL_CALL(GetProgramiv(fProgramID, GR_GL_INFO_LOG_LENGTH, &infoLen)); |
| 255 | SkAutoMalloc log(sizeof(char)*(infoLen+1)); // outside if for debugger |
| 256 | if (infoLen > 0) { |
| 257 | // retrieve length even though we don't need it to workaround |
| 258 | // bug in chrome cmd buffer param validation. |
| 259 | GrGLsizei length = GR_GL_INIT_ZERO; |
| 260 | GL_CALL(GetProgramInfoLog(fProgramID, |
| 261 | infoLen+1, |
| 262 | &length, |
| 263 | (char*)log.get())); |
| 264 | GrPrintf((char*)log.get()); |
| 265 | } |
| 266 | SkDEBUGFAIL("Error linking program"); |
| 267 | GL_CALL(DeleteProgram(fProgramID)); |
| 268 | fProgramID = 0; |
| 269 | return false; |
| 270 | } |
| 271 | } |
| 272 | |
| 273 | this->resolveProgramLocations(fProgramID); |
| 274 | |
| 275 | for (int i = 0; i < shadersToDelete.count(); ++i) { |
| 276 | GL_CALL(DeleteShader(shadersToDelete[i])); |
| 277 | } |
| 278 | |
| 279 | return true; |
| 280 | } |
| 281 | |
| 282 | bool GrGLProgramBuilder::compileAndAttachShaders(GrGLuint programId, |
| 283 | SkTDArray<GrGLuint>* shaderIds) const { |
| 284 | return fFS.compileAndAttachShaders(programId, shaderIds); |
| 285 | } |
| 286 | |
| 287 | void GrGLProgramBuilder::bindProgramLocations(GrGLuint programId) { |
| 288 | fFS.bindProgramLocations(programId); |
| 289 | |
| 290 | // skbug.com/2056 |
| 291 | bool usingBindUniform = fGpu->glInterface()->fFunctions.fBindUniformLocation != NULL; |
| 292 | if (usingBindUniform) { |
| 293 | int count = fUniforms.count(); |
| 294 | for (int i = 0; i < count; ++i) { |
| 295 | GL_CALL(BindUniformLocation(programId, i, fUniforms[i].fVariable.c_str())); |
| 296 | fUniforms[i].fLocation = i; |
| 297 | } |
| 298 | } |
| 299 | } |
| 300 | |
| 301 | void GrGLProgramBuilder::resolveProgramLocations(GrGLuint programId) { |
| 302 | bool usingBindUniform = fGpu->glInterface()->fFunctions.fBindUniformLocation != NULL; |
| 303 | if (!usingBindUniform) { |
| 304 | int count = fUniforms.count(); |
| 305 | for (int i = 0; i < count; ++i) { |
| 306 | GrGLint location; |
| 307 | GL_CALL_RET(location, |
| 308 | GetUniformLocation(programId, fUniforms[i].fVariable.c_str())); |
| 309 | fUniforms[i].fLocation = location; |
| 310 | } |
| 311 | } |
kkinnunen | ec56e45 | 2014-08-25 22:21:16 -0700 | [diff] [blame] | 312 | |
| 313 | int count = fSeparableVaryingInfos.count(); |
| 314 | for (int i = 0; i < count; ++i) { |
| 315 | GrGLint location; |
| 316 | GL_CALL_RET(location, |
| 317 | GetProgramResourceLocation(programId, |
| 318 | GR_GL_FRAGMENT_INPUT, |
| 319 | fSeparableVaryingInfos[i].fVariable.c_str())); |
| 320 | fSeparableVaryingInfos[i].fLocation = location; |
| 321 | } |
joshualitt | 30ba436 | 2014-08-21 20:18:45 -0700 | [diff] [blame] | 322 | } |
| 323 | |
| 324 | const GrGLContextInfo& GrGLProgramBuilder::ctxInfo() const { |
| 325 | return fGpu->ctxInfo(); |
| 326 | } |
| 327 | |
| 328 | //////////////////////////////////////////////////////////////////////////////// |
| 329 | |
| 330 | GrGLFullProgramBuilder::GrGLFullProgramBuilder(GrGpuGL* gpu, |
| 331 | const GrGLProgramDesc& desc) |
| 332 | : INHERITED(gpu, desc) |
| 333 | , fGS(this) |
| 334 | , fVS(this) { |
| 335 | } |
| 336 | |
| 337 | void GrGLFullProgramBuilder::emitCodeBeforeEffects(GrGLSLExpr4* color, GrGLSLExpr4* coverage) { |
| 338 | fVS.emitCodeBeforeEffects(color, coverage); |
| 339 | } |
| 340 | |
| 341 | void GrGLFullProgramBuilder::emitCodeAfterEffects() { |
| 342 | fVS.emitCodeAfterEffects(); |
| 343 | } |
| 344 | |
| 345 | void GrGLFullProgramBuilder::addVarying(GrSLType type, |
| 346 | const char* name, |
| 347 | const char** vsOutName, |
egdaniel | 6db9128 | 2014-09-02 08:02:38 -0700 | [diff] [blame] | 348 | const char** fsInName, |
| 349 | GrGLShaderVar::Precision fsPrecision) { |
joshualitt | 30ba436 | 2014-08-21 20:18:45 -0700 | [diff] [blame] | 350 | fVS.addVarying(type, name, vsOutName); |
| 351 | |
| 352 | SkString* fsInputName = fVS.fOutputs.back().accessName(); |
| 353 | |
| 354 | #if GR_GL_EXPERIMENTAL_GS |
| 355 | if (desc().getHeader().fExperimentalGS) { |
| 356 | // TODO let the caller use these names |
| 357 | fGS.addVarying(type, fsInputName->c_str(), NULL); |
| 358 | fsInputName = fGS.fOutputs.back().accessName(); |
| 359 | } |
| 360 | #endif |
egdaniel | 6db9128 | 2014-09-02 08:02:38 -0700 | [diff] [blame] | 361 | fFS.addVarying(type, fsInputName->c_str(), fsInName, fsPrecision); |
joshualitt | 30ba436 | 2014-08-21 20:18:45 -0700 | [diff] [blame] | 362 | } |
| 363 | |
kkinnunen | ec56e45 | 2014-08-25 22:21:16 -0700 | [diff] [blame] | 364 | GrGLFullProgramBuilder::VaryingHandle |
| 365 | GrGLFullProgramBuilder::addSeparableVarying(GrSLType type, |
| 366 | const char* name, |
| 367 | const char** vsOutName, |
| 368 | const char** fsInName) { |
| 369 | addVarying(type, name, vsOutName, fsInName); |
| 370 | SeparableVaryingInfo& varying = fSeparableVaryingInfos.push_back(); |
| 371 | varying.fVariable = fFS.fInputs.back(); |
| 372 | return VaryingHandle::CreateFromSeparableVaryingIndex(fSeparableVaryingInfos.count() - 1); |
| 373 | } |
| 374 | |
| 375 | |
joshualitt | 30ba436 | 2014-08-21 20:18:45 -0700 | [diff] [blame] | 376 | GrGLProgramEffects* GrGLFullProgramBuilder::createAndEmitEffects( |
| 377 | const GrEffectStage* effectStages[], |
| 378 | int effectCnt, |
| 379 | const GrGLProgramDesc::EffectKeyProvider& keyProvider, |
| 380 | GrGLSLExpr4* inOutFSColor) { |
| 381 | |
| 382 | GrGLVertexProgramEffectsBuilder programEffectsBuilder(this, effectCnt); |
| 383 | this->INHERITED::createAndEmitEffects(&programEffectsBuilder, |
| 384 | effectStages, |
| 385 | effectCnt, |
| 386 | keyProvider, |
| 387 | inOutFSColor); |
| 388 | return programEffectsBuilder.finish(); |
| 389 | } |
| 390 | |
| 391 | bool GrGLFullProgramBuilder::compileAndAttachShaders(GrGLuint programId, |
| 392 | SkTDArray<GrGLuint>* shaderIds) const { |
| 393 | return INHERITED::compileAndAttachShaders(programId, shaderIds) |
| 394 | && fVS.compileAndAttachShaders(programId, shaderIds) |
| 395 | #if GR_GL_EXPERIMENTAL_GS |
| 396 | && (!desc().getHeader().fExperimentalGS |
| 397 | || fGS.compileAndAttachShaders(programId, shaderIds)) |
| 398 | #endif |
| 399 | ; |
| 400 | } |
| 401 | |
| 402 | void GrGLFullProgramBuilder::bindProgramLocations(GrGLuint programId) { |
| 403 | fVS.bindProgramLocations(programId); |
| 404 | INHERITED::bindProgramLocations(programId); |
| 405 | } |
| 406 | |
| 407 | //////////////////////////////////////////////////////////////////////////////// |
| 408 | |
| 409 | GrGLFragmentOnlyProgramBuilder::GrGLFragmentOnlyProgramBuilder(GrGpuGL* gpu, |
| 410 | const GrGLProgramDesc& desc) |
| 411 | : INHERITED(gpu, desc) { |
kkinnunen | ec56e45 | 2014-08-25 22:21:16 -0700 | [diff] [blame] | 412 | SkASSERT(!desc.getHeader().fRequiresVertexShader); |
joshualitt | 30ba436 | 2014-08-21 20:18:45 -0700 | [diff] [blame] | 413 | SkASSERT(gpu->glCaps().pathRenderingSupport()); |
| 414 | SkASSERT(GrGLProgramDesc::kAttribute_ColorInput != desc.getHeader().fColorInput); |
| 415 | SkASSERT(GrGLProgramDesc::kAttribute_ColorInput != desc.getHeader().fCoverageInput); |
| 416 | } |
| 417 | |
| 418 | int GrGLFragmentOnlyProgramBuilder::addTexCoordSets(int count) { |
| 419 | int firstFreeCoordSet = fTexCoordSetCnt; |
| 420 | fTexCoordSetCnt += count; |
| 421 | SkASSERT(gpu()->glCaps().maxFixedFunctionTextureCoords() >= fTexCoordSetCnt); |
| 422 | return firstFreeCoordSet; |
| 423 | } |
| 424 | |
| 425 | GrGLProgramEffects* GrGLFragmentOnlyProgramBuilder::createAndEmitEffects( |
| 426 | const GrEffectStage* effectStages[], int effectCnt, |
| 427 | const GrGLProgramDesc::EffectKeyProvider& keyProvider, GrGLSLExpr4* inOutFSColor) { |
| 428 | |
| 429 | GrGLPathTexGenProgramEffectsBuilder pathTexGenEffectsBuilder(this, |
| 430 | effectCnt); |
| 431 | this->INHERITED::createAndEmitEffects(&pathTexGenEffectsBuilder, |
| 432 | effectStages, |
| 433 | effectCnt, |
| 434 | keyProvider, |
| 435 | inOutFSColor); |
| 436 | return pathTexGenEffectsBuilder.finish(); |
| 437 | } |