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