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 #include "GrCoordTransform.h" 12 #include "GrDrawEffect.h" 13 #include "GrGpuGL.h" 14 #include "GrTexture.h" 15 #include "SkRTConf.h" 16 #include "SkTraceEvent.h" 17 18 #define GL_CALL(X) GR_GL_CALL(this->gpu()->glInterface(), X) 19 #define GL_CALL_RET(R, X) GR_GL_CALL_RET(this->gpu()->glInterface(), R, X) 20 21 // number of each input/output type in a single allocation block 22 static const int kVarsPerBlock = 8; 23 24 // except FS outputs where we expect 2 at most. 25 static const int kMaxFSOutputs = 2; 26 27 // ES2 FS only guarantees mediump and lowp support 28 static const GrGLShaderVar::Precision kDefaultFragmentPrecision = GrGLShaderVar::kMedium_Precision; 29 30 typedef GrGLUniformManager::UniformHandle UniformHandle; 31 32 SK_CONF_DECLARE(bool, c_PrintShaders, "gpu.printShaders", false, 33 "Print the source code for all shaders generated."); 34 35 /////////////////////////////////////////////////////////////////////////////// 36 37 namespace { 38 39 inline const char* color_attribute_name() { return "aColor"; } 40 inline const char* coverage_attribute_name() { return "aCoverage"; } 41 inline const char* declared_color_output_name() { return "fsColorOut"; } 42 inline const char* dual_source_output_name() { return "dualSourceOut"; } 43 inline const char* sample_function_name(GrSLType type, GrGLSLGeneration glslGen) { 44 if (kVec2f_GrSLType == type) { 45 return glslGen >= k130_GrGLSLGeneration ? "texture" : "texture2D"; 46 } else { 47 SkASSERT(kVec3f_GrSLType == type); 48 return glslGen >= k130_GrGLSLGeneration ? "textureProj" : "texture2DProj"; 49 } 50 } 51 52 void append_texture_lookup(SkString* out, 53 GrGpuGL* gpu, 54 const char* samplerName, 55 const char* coordName, 56 uint32_t configComponentMask, 57 const char* swizzle, 58 GrSLType varyingType = kVec2f_GrSLType) { 59 SkASSERT(NULL != coordName); 60 61 out->appendf("%s(%s, %s)", 62 sample_function_name(varyingType, gpu->glslGeneration()), 63 samplerName, 64 coordName); 65 66 char mangledSwizzle[5]; 67 68 // The swizzling occurs using texture params instead of shader-mangling if ARB_texture_swizzle 69 // is available. 70 if (!gpu->glCaps().textureSwizzleSupport() && 71 (kA_GrColorComponentFlag == configComponentMask)) { 72 char alphaChar = gpu->glCaps().textureRedSupport() ? 'r' : 'a'; 73 int i; 74 for (i = 0; '\0' != swizzle[i]; ++i) { 75 mangledSwizzle[i] = alphaChar; 76 } 77 mangledSwizzle[i] ='\0'; 78 swizzle = mangledSwizzle; 79 } 80 // For shader prettiness we omit the swizzle rather than appending ".rgba". 81 if (memcmp(swizzle, "rgba", 4)) { 82 out->appendf(".%s", swizzle); 83 } 84 } 85 86 } 87 88 static const char kDstCopyColorName[] = "_dstColor"; 89 90 /////////////////////////////////////////////////////////////////////////////// 91 92 bool GrGLShaderBuilder::GenProgram(GrGpuGL* gpu, 93 GrGLUniformManager* uman, 94 const GrGLProgramDesc& desc, 95 const GrEffectStage* inColorStages[], 96 const GrEffectStage* inCoverageStages[], 97 GenProgramOutput* output) { 98 SkAutoTDelete<GrGLShaderBuilder> builder; 99 if (desc.getHeader().fHasVertexCode ||!gpu->shouldUseFixedFunctionTexturing()) { 100 builder.reset(SkNEW_ARGS(GrGLFullShaderBuilder, (gpu, uman, desc))); 101 } else { 102 builder.reset(SkNEW_ARGS(GrGLFragmentOnlyShaderBuilder, (gpu, uman, desc))); 103 } 104 if (builder->genProgram(inColorStages, inCoverageStages)) { 105 *output = builder->getOutput(); 106 return true; 107 } 108 return false; 109 } 110 111 bool GrGLShaderBuilder::genProgram(const GrEffectStage* colorStages[], 112 const GrEffectStage* coverageStages[]) { 113 const GrGLProgramDesc::KeyHeader& header = this->desc().getHeader(); 114 115 /////////////////////////////////////////////////////////////////////////// 116 // emit code to read the dst copy texture, if necessary 117 if (kNoDstRead_DstReadKey != header.fDstReadKey && 118 GrGLCaps::kNone_FBFetchType == fGpu->glCaps().fbFetchType()) { 119 bool topDown = SkToBool(kTopLeftOrigin_DstReadKeyBit & header.fDstReadKey); 120 const char* dstCopyTopLeftName; 121 const char* dstCopyCoordScaleName; 122 const char* dstCopySamplerName; 123 uint32_t configMask; 124 if (SkToBool(kUseAlphaConfig_DstReadKeyBit & header.fDstReadKey)) { 125 configMask = kA_GrColorComponentFlag; 126 } else { 127 configMask = kRGBA_GrColorComponentFlags; 128 } 129 fOutput.fUniformHandles.fDstCopySamplerUni = 130 this->addUniform(kFragment_Visibility, kSampler2D_GrSLType, "DstCopySampler", 131 &dstCopySamplerName); 132 fOutput.fUniformHandles.fDstCopyTopLeftUni = 133 this->addUniform(kFragment_Visibility, kVec2f_GrSLType, "DstCopyUpperLeft", 134 &dstCopyTopLeftName); 135 fOutput.fUniformHandles.fDstCopyScaleUni = 136 this->addUniform(kFragment_Visibility, kVec2f_GrSLType, "DstCopyCoordScale", 137 &dstCopyCoordScaleName); 138 const char* fragPos = this->fragmentPosition(); 139 this->fsCodeAppend("\t// Read color from copy of the destination.\n"); 140 this->fsCodeAppendf("\tvec2 _dstTexCoord = (%s.xy - %s) * %s;\n", 141 fragPos, dstCopyTopLeftName, dstCopyCoordScaleName); 142 if (!topDown) { 143 this->fsCodeAppend("\t_dstTexCoord.y = 1.0 - _dstTexCoord.y;\n"); 144 } 145 this->fsCodeAppendf("\tvec4 %s = ", kDstCopyColorName); 146 append_texture_lookup(&fFSCode, 147 fGpu, 148 dstCopySamplerName, 149 "_dstTexCoord", 150 configMask, 151 "rgba"); 152 this->fsCodeAppend(";\n\n"); 153 } 154 155 /////////////////////////////////////////////////////////////////////////// 156 // get the initial color and coverage to feed into the first effect in each effect chain 157 158 GrGLSLExpr4 inputColor; 159 GrGLSLExpr4 inputCoverage; 160 161 if (GrGLProgramDesc::kUniform_ColorInput == header.fColorInput) { 162 const char* name; 163 fOutput.fUniformHandles.fColorUni = 164 this->addUniform(GrGLShaderBuilder::kFragment_Visibility, kVec4f_GrSLType, "Color", 165 &name); 166 inputColor = GrGLSLExpr4(name); 167 } else if (GrGLProgramDesc::kSolidWhite_ColorInput == header.fColorInput) { 168 inputColor = GrGLSLExpr4(1); 169 } else if (GrGLProgramDesc::kTransBlack_ColorInput == header.fColorInput) { 170 inputColor = GrGLSLExpr4(0); 171 } 172 173 if (GrGLProgramDesc::kUniform_ColorInput == header.fCoverageInput) { 174 const char* name; 175 fOutput.fUniformHandles.fCoverageUni = 176 this->addUniform(GrGLShaderBuilder::kFragment_Visibility, kVec4f_GrSLType, "Coverage", 177 &name); 178 inputCoverage = GrGLSLExpr4(name); 179 } else if (GrGLProgramDesc::kSolidWhite_ColorInput == header.fCoverageInput) { 180 inputCoverage = GrGLSLExpr4(1); 181 } else if (GrGLProgramDesc::kTransBlack_ColorInput == header.fCoverageInput) { 182 inputCoverage = GrGLSLExpr4(0); 183 } 184 185 if (k110_GrGLSLGeneration != fGpu->glslGeneration()) { 186 fFSOutputs.push_back().set(kVec4f_GrSLType, 187 GrGLShaderVar::kOut_TypeModifier, 188 declared_color_output_name()); 189 fHasCustomColorOutput = true; 190 } 191 192 this->emitCodeBeforeEffects(&inputColor, &inputCoverage); 193 194 /////////////////////////////////////////////////////////////////////////// 195 // emit the per-effect code for both color and coverage effects 196 197 fOutput.fColorEffects.reset(this->createAndEmitEffects(colorStages, 198 this->desc().getEffectKeys(), 199 this->desc().numColorEffects(), 200 &inputColor)); 201 202 fOutput.fCoverageEffects.reset(this->createAndEmitEffects(coverageStages, 203 this->desc().getEffectKeys() + this->desc().numColorEffects(), 204 this->desc().numCoverageEffects(), 205 &inputCoverage)); 206 207 this->emitCodeAfterEffects(); 208 209 /////////////////////////////////////////////////////////////////////////// 210 // write the secondary color output if necessary 211 if (GrGLProgramDesc::CoverageOutputUsesSecondaryOutput(header.fCoverageOutput)) { 212 const char* secondaryOutputName = this->enableSecondaryOutput(); 213 214 // default coeff to ones for kCoverage_DualSrcOutput 215 GrGLSLExpr4 coeff(1); 216 if (GrGLProgramDesc::kSecondaryCoverageISA_CoverageOutput == header.fCoverageOutput) { 217 // Get (1-A) into coeff 218 coeff = GrGLSLExpr4::VectorCast(GrGLSLExpr1(1) - inputColor.a()); 219 } else if (GrGLProgramDesc::kSecondaryCoverageISC_CoverageOutput == 220 header.fCoverageOutput){ 221 // Get (1-RGBA) into coeff 222 coeff = GrGLSLExpr4(1) - inputColor; 223 } 224 // Get coeff * coverage into modulate and then write that to the dual source output. 225 this->fsCodeAppendf("\t%s = %s;\n", secondaryOutputName, (coeff * inputCoverage).c_str()); 226 } 227 228 /////////////////////////////////////////////////////////////////////////// 229 // combine color and coverage as frag color 230 231 // Get "color * coverage" into fragColor 232 GrGLSLExpr4 fragColor = inputColor * inputCoverage; 233 // Now tack on "+(1-coverage)dst onto the frag color if we were asked to do so. 234 if (GrGLProgramDesc::kCombineWithDst_CoverageOutput == header.fCoverageOutput) { 235 GrGLSLExpr4 dstCoeff = GrGLSLExpr4(1) - inputCoverage; 236 237 GrGLSLExpr4 dstContribution = dstCoeff * GrGLSLExpr4(this->dstColor()); 238 239 fragColor = fragColor + dstContribution; 240 } 241 this->fsCodeAppendf("\t%s = %s;\n", this->getColorOutputName(), fragColor.c_str()); 242 243 if (!this->finish()) { 244 return false; 245 } 246 247 return true; 248 } 249 250 ////////////////////////////////////////////////////////////////////////////// 251 252 GrGLShaderBuilder::GrGLShaderBuilder(GrGpuGL* gpu, 253 GrGLUniformManager* uniformManager, 254 const GrGLProgramDesc& desc) 255 : fDesc(desc) 256 , fGpu(gpu) 257 , fUniformManager(SkRef(uniformManager)) 258 , fFSFeaturesAddedMask(0) 259 , fFSInputs(kVarsPerBlock) 260 , fFSOutputs(kMaxFSOutputs) 261 , fUniforms(kVarsPerBlock) 262 , fSetupFragPosition(false) 263 , fTopLeftFragPosRead(kTopLeftFragPosRead_FragPosKey == desc.getHeader().fFragPosKey) 264 , fHasCustomColorOutput(false) 265 , fHasSecondaryOutput(false) { 266 } 267 268 bool GrGLShaderBuilder::enableFeature(GLSLFeature feature) { 269 switch (feature) { 270 case kStandardDerivatives_GLSLFeature: 271 if (!fGpu->glCaps().shaderDerivativeSupport()) { 272 return false; 273 } 274 if (kGLES_GrGLStandard == fGpu->glStandard()) { 275 this->addFSFeature(1 << kStandardDerivatives_GLSLFeature, 276 "GL_OES_standard_derivatives"); 277 } 278 return true; 279 default: 280 SkFAIL("Unexpected GLSLFeature requested."); 281 return false; 282 } 283 } 284 285 bool GrGLShaderBuilder::enablePrivateFeature(GLSLPrivateFeature feature) { 286 switch (feature) { 287 case kFragCoordConventions_GLSLPrivateFeature: 288 if (!fGpu->glCaps().fragCoordConventionsSupport()) { 289 return false; 290 } 291 if (fGpu->glslGeneration() < k150_GrGLSLGeneration) { 292 this->addFSFeature(1 << kFragCoordConventions_GLSLPrivateFeature, 293 "GL_ARB_fragment_coord_conventions"); 294 } 295 return true; 296 case kEXTShaderFramebufferFetch_GLSLPrivateFeature: 297 if (GrGLCaps::kEXT_FBFetchType != fGpu->glCaps().fbFetchType()) { 298 return false; 299 } 300 this->addFSFeature(1 << kEXTShaderFramebufferFetch_GLSLPrivateFeature, 301 "GL_EXT_shader_framebuffer_fetch"); 302 return true; 303 case kNVShaderFramebufferFetch_GLSLPrivateFeature: 304 if (GrGLCaps::kNV_FBFetchType != fGpu->glCaps().fbFetchType()) { 305 return false; 306 } 307 this->addFSFeature(1 << kNVShaderFramebufferFetch_GLSLPrivateFeature, 308 "GL_NV_shader_framebuffer_fetch"); 309 return true; 310 default: 311 SkFAIL("Unexpected GLSLPrivateFeature requested."); 312 return false; 313 } 314 } 315 316 void GrGLShaderBuilder::addFSFeature(uint32_t featureBit, const char* extensionName) { 317 if (!(featureBit & fFSFeaturesAddedMask)) { 318 fFSExtensions.appendf("#extension %s: require\n", extensionName); 319 fFSFeaturesAddedMask |= featureBit; 320 } 321 } 322 323 void GrGLShaderBuilder::nameVariable(SkString* out, char prefix, const char* name) { 324 if ('\0' == prefix) { 325 *out = name; 326 } else { 327 out->printf("%c%s", prefix, name); 328 } 329 if (fCodeStage.inStageCode()) { 330 if (out->endsWith('_')) { 331 // Names containing "__" are reserved. 332 out->append("x"); 333 } 334 out->appendf("_Stage%d", fCodeStage.stageIndex()); 335 } 336 } 337 338 const char* GrGLShaderBuilder::dstColor() { 339 if (fCodeStage.inStageCode()) { 340 const GrEffectRef& effect = *fCodeStage.effectStage()->getEffect(); 341 if (!effect->willReadDstColor()) { 342 SkDEBUGFAIL("GrGLEffect asked for dst color but its generating GrEffect " 343 "did not request access."); 344 return ""; 345 } 346 } 347 static const char kFBFetchColorName[] = "gl_LastFragData[0]"; 348 GrGLCaps::FBFetchType fetchType = fGpu->glCaps().fbFetchType(); 349 if (GrGLCaps::kEXT_FBFetchType == fetchType) { 350 SkAssertResult(this->enablePrivateFeature(kEXTShaderFramebufferFetch_GLSLPrivateFeature)); 351 return kFBFetchColorName; 352 } else if (GrGLCaps::kNV_FBFetchType == fetchType) { 353 SkAssertResult(this->enablePrivateFeature(kNVShaderFramebufferFetch_GLSLPrivateFeature)); 354 return kFBFetchColorName; 355 } else if (fOutput.fUniformHandles.fDstCopySamplerUni.isValid()) { 356 return kDstCopyColorName; 357 } else { 358 return ""; 359 } 360 } 361 362 void GrGLShaderBuilder::appendTextureLookup(SkString* out, 363 const GrGLShaderBuilder::TextureSampler& sampler, 364 const char* coordName, 365 GrSLType varyingType) const { 366 append_texture_lookup(out, 367 fGpu, 368 this->getUniformCStr(sampler.samplerUniform()), 369 coordName, 370 sampler.configComponentMask(), 371 sampler.swizzle(), 372 varyingType); 373 } 374 375 void GrGLShaderBuilder::fsAppendTextureLookup(const GrGLShaderBuilder::TextureSampler& sampler, 376 const char* coordName, 377 GrSLType varyingType) { 378 this->appendTextureLookup(&fFSCode, sampler, coordName, varyingType); 379 } 380 381 void GrGLShaderBuilder::fsAppendTextureLookupAndModulate( 382 const char* modulation, 383 const GrGLShaderBuilder::TextureSampler& sampler, 384 const char* coordName, 385 GrSLType varyingType) { 386 SkString lookup; 387 this->appendTextureLookup(&lookup, sampler, coordName, varyingType); 388 fFSCode.append((GrGLSLExpr4(modulation) * GrGLSLExpr4(lookup)).c_str()); 389 } 390 391 GrGLShaderBuilder::DstReadKey GrGLShaderBuilder::KeyForDstRead(const GrTexture* dstCopy, 392 const GrGLCaps& caps) { 393 uint32_t key = kYesDstRead_DstReadKeyBit; 394 if (GrGLCaps::kNone_FBFetchType != caps.fbFetchType()) { 395 return key; 396 } 397 SkASSERT(NULL != dstCopy); 398 if (!caps.textureSwizzleSupport() && GrPixelConfigIsAlphaOnly(dstCopy->config())) { 399 // The fact that the config is alpha-only must be considered when generating code. 400 key |= kUseAlphaConfig_DstReadKeyBit; 401 } 402 if (kTopLeft_GrSurfaceOrigin == dstCopy->origin()) { 403 key |= kTopLeftOrigin_DstReadKeyBit; 404 } 405 SkASSERT(static_cast<DstReadKey>(key) == key); 406 return static_cast<DstReadKey>(key); 407 } 408 409 GrGLShaderBuilder::FragPosKey GrGLShaderBuilder::KeyForFragmentPosition(const GrRenderTarget* dst, 410 const GrGLCaps&) { 411 if (kTopLeft_GrSurfaceOrigin == dst->origin()) { 412 return kTopLeftFragPosRead_FragPosKey; 413 } else { 414 return kBottomLeftFragPosRead_FragPosKey; 415 } 416 } 417 418 419 const GrGLenum* GrGLShaderBuilder::GetTexParamSwizzle(GrPixelConfig config, const GrGLCaps& caps) { 420 if (caps.textureSwizzleSupport() && GrPixelConfigIsAlphaOnly(config)) { 421 if (caps.textureRedSupport()) { 422 static const GrGLenum gRedSmear[] = { GR_GL_RED, GR_GL_RED, GR_GL_RED, GR_GL_RED }; 423 return gRedSmear; 424 } else { 425 static const GrGLenum gAlphaSmear[] = { GR_GL_ALPHA, GR_GL_ALPHA, 426 GR_GL_ALPHA, GR_GL_ALPHA }; 427 return gAlphaSmear; 428 } 429 } else { 430 static const GrGLenum gStraight[] = { GR_GL_RED, GR_GL_GREEN, GR_GL_BLUE, GR_GL_ALPHA }; 431 return gStraight; 432 } 433 } 434 435 GrGLUniformManager::UniformHandle GrGLShaderBuilder::addUniformArray(uint32_t visibility, 436 GrSLType type, 437 const char* name, 438 int count, 439 const char** outName) { 440 SkASSERT(name && strlen(name)); 441 SkDEBUGCODE(static const uint32_t kVisibilityMask = kVertex_Visibility | kFragment_Visibility); 442 SkASSERT(0 == (~kVisibilityMask & visibility)); 443 SkASSERT(0 != visibility); 444 445 BuilderUniform& uni = fUniforms.push_back(); 446 UniformHandle h = GrGLUniformManager::UniformHandle::CreateFromUniformIndex(fUniforms.count() - 1); 447 SkDEBUGCODE(UniformHandle h2 =) 448 fUniformManager->appendUniform(type, count); 449 // We expect the uniform manager to initially have no uniforms and that all uniforms are added 450 // by this function. Therefore, the handles should match. 451 SkASSERT(h2 == h); 452 uni.fVariable.setType(type); 453 uni.fVariable.setTypeModifier(GrGLShaderVar::kUniform_TypeModifier); 454 this->nameVariable(uni.fVariable.accessName(), 'u', name); 455 uni.fVariable.setArrayCount(count); 456 uni.fVisibility = visibility; 457 458 // If it is visible in both the VS and FS, the precision must match. 459 // We declare a default FS precision, but not a default VS. So set the var 460 // to use the default FS precision. 461 if ((kVertex_Visibility | kFragment_Visibility) == visibility) { 462 // the fragment and vertex precisions must match 463 uni.fVariable.setPrecision(kDefaultFragmentPrecision); 464 } 465 466 if (NULL != outName) { 467 *outName = uni.fVariable.c_str(); 468 } 469 470 return h; 471 } 472 473 SkString GrGLShaderBuilder::ensureFSCoords2D(const TransformedCoordsArray& coords, int index) { 474 if (kVec3f_GrSLType != coords[index].type()) { 475 SkASSERT(kVec2f_GrSLType == coords[index].type()); 476 return coords[index].getName(); 477 } 478 479 SkString coords2D("coords2D"); 480 if (0 != index) { 481 coords2D.appendf("_%i", index); 482 } 483 this->fsCodeAppendf("\tvec2 %s = %s.xy / %s.z;", 484 coords2D.c_str(), coords[index].c_str(), coords[index].c_str()); 485 return coords2D; 486 } 487 488 const char* GrGLShaderBuilder::fragmentPosition() { 489 if (fCodeStage.inStageCode()) { 490 const GrEffectRef& effect = *fCodeStage.effectStage()->getEffect(); 491 if (!effect->willReadFragmentPosition()) { 492 SkDEBUGFAIL("GrGLEffect asked for frag position but its generating GrEffect " 493 "did not request access."); 494 return ""; 495 } 496 } 497 // We only declare "gl_FragCoord" when we're in the case where we want to use layout qualifiers 498 // to reverse y. Otherwise it isn't necessary and whether the "in" qualifier appears in the 499 // declaration varies in earlier GLSL specs. So it is simpler to omit it. 500 if (fTopLeftFragPosRead) { 501 fSetupFragPosition = true; 502 return "(gl_FragCoord.xy)"; 503 } else if (fGpu->glCaps().fragCoordConventionsSupport()) { 504 if (!fSetupFragPosition) { 505 SkAssertResult(this->enablePrivateFeature(kFragCoordConventions_GLSLPrivateFeature)); 506 fFSInputs.push_back().set(kVec4f_GrSLType, 507 GrGLShaderVar::kIn_TypeModifier, 508 "gl_FragCoord", 509 GrGLShaderVar::kDefault_Precision, 510 GrGLShaderVar::kUpperLeft_Origin); 511 fSetupFragPosition = true; 512 } 513 return "(gl_FragCoord.xy)"; 514 } else { 515 static const char* kCoordName = "fragCoordYDown"; 516 if (!fSetupFragPosition) { 517 // temporarily change the stage index because we're inserting non-stage code. 518 CodeStage::AutoStageRestore csar(&fCodeStage, NULL); 519 520 SkASSERT(!fOutput.fUniformHandles.fRTHeightUni.isValid()); 521 const char* rtHeightName; 522 523 fOutput.fUniformHandles.fRTHeightUni = 524 this->addUniform(kFragment_Visibility, kFloat_GrSLType, "RTHeight", &rtHeightName); 525 526 this->fFSCode.prependf("\tvec2 %s = vec2(gl_FragCoord.x, %s - gl_FragCoord.y);\n", 527 kCoordName, rtHeightName); 528 fSetupFragPosition = true; 529 } 530 SkASSERT(fOutput.fUniformHandles.fRTHeightUni.isValid()); 531 return kCoordName; 532 } 533 } 534 535 void GrGLShaderBuilder::fsEmitFunction(GrSLType returnType, 536 const char* name, 537 int argCnt, 538 const GrGLShaderVar* args, 539 const char* body, 540 SkString* outName) { 541 fFSFunctions.append(GrGLSLTypeString(returnType)); 542 this->nameVariable(outName, '\0', name); 543 fFSFunctions.appendf(" %s", outName->c_str()); 544 fFSFunctions.append("("); 545 for (int i = 0; i < argCnt; ++i) { 546 args[i].appendDecl(this->ctxInfo(), &fFSFunctions); 547 if (i < argCnt - 1) { 548 fFSFunctions.append(", "); 549 } 550 } 551 fFSFunctions.append(") {\n"); 552 fFSFunctions.append(body); 553 fFSFunctions.append("}\n\n"); 554 } 555 556 namespace { 557 558 inline void append_default_precision_qualifier(GrGLShaderVar::Precision p, 559 GrGLStandard standard, 560 SkString* str) { 561 // Desktop GLSL has added precision qualifiers but they don't do anything. 562 if (kGLES_GrGLStandard == standard) { 563 switch (p) { 564 case GrGLShaderVar::kHigh_Precision: 565 str->append("precision highp float;\n"); 566 break; 567 case GrGLShaderVar::kMedium_Precision: 568 str->append("precision mediump float;\n"); 569 break; 570 case GrGLShaderVar::kLow_Precision: 571 str->append("precision lowp float;\n"); 572 break; 573 case GrGLShaderVar::kDefault_Precision: 574 SkFAIL("Default precision now allowed."); 575 default: 576 SkFAIL("Unknown precision value."); 577 } 578 } 579 } 580 } 581 582 void GrGLShaderBuilder::appendDecls(const VarArray& vars, SkString* out) const { 583 for (int i = 0; i < vars.count(); ++i) { 584 vars[i].appendDecl(this->ctxInfo(), out); 585 out->append(";\n"); 586 } 587 } 588 589 void GrGLShaderBuilder::appendUniformDecls(ShaderVisibility visibility, 590 SkString* out) const { 591 for (int i = 0; i < fUniforms.count(); ++i) { 592 if (fUniforms[i].fVisibility & visibility) { 593 fUniforms[i].fVariable.appendDecl(this->ctxInfo(), out); 594 out->append(";\n"); 595 } 596 } 597 } 598 599 void GrGLShaderBuilder::createAndEmitEffects(GrGLProgramEffectsBuilder* programEffectsBuilder, 600 const GrEffectStage* effectStages[], 601 const EffectKey effectKeys[], 602 int effectCnt, 603 GrGLSLExpr4* fsInOutColor) { 604 bool effectEmitted = false; 605 606 GrGLSLExpr4 inColor = *fsInOutColor; 607 GrGLSLExpr4 outColor; 608 609 for (int e = 0; e < effectCnt; ++e) { 610 SkASSERT(NULL != effectStages[e] && NULL != effectStages[e]->getEffect()); 611 const GrEffectStage& stage = *effectStages[e]; 612 613 CodeStage::AutoStageRestore csar(&fCodeStage, &stage); 614 615 if (inColor.isZeros()) { 616 SkString inColorName; 617 618 // Effects have no way to communicate zeros, they treat an empty string as ones. 619 this->nameVariable(&inColorName, '\0', "input"); 620 this->fsCodeAppendf("\tvec4 %s = %s;\n", inColorName.c_str(), inColor.c_str()); 621 inColor = inColorName; 622 } 623 624 // create var to hold stage result 625 SkString outColorName; 626 this->nameVariable(&outColorName, '\0', "output"); 627 this->fsCodeAppendf("\tvec4 %s;\n", outColorName.c_str()); 628 outColor = outColorName; 629 630 631 programEffectsBuilder->emitEffect(stage, 632 effectKeys[e], 633 outColor.c_str(), 634 inColor.isOnes() ? NULL : inColor.c_str(), 635 fCodeStage.stageIndex()); 636 637 inColor = outColor; 638 effectEmitted = true; 639 } 640 641 if (effectEmitted) { 642 *fsInOutColor = outColor; 643 } 644 } 645 646 const char* GrGLShaderBuilder::getColorOutputName() const { 647 return fHasCustomColorOutput ? declared_color_output_name() : "gl_FragColor"; 648 } 649 650 const char* GrGLShaderBuilder::enableSecondaryOutput() { 651 if (!fHasSecondaryOutput) { 652 fFSOutputs.push_back().set(kVec4f_GrSLType, 653 GrGLShaderVar::kOut_TypeModifier, 654 dual_source_output_name()); 655 fHasSecondaryOutput = true; 656 } 657 return dual_source_output_name(); 658 } 659 660 bool GrGLShaderBuilder::finish() { 661 SkASSERT(0 == fOutput.fProgramID); 662 GL_CALL_RET(fOutput.fProgramID, CreateProgram()); 663 if (!fOutput.fProgramID) { 664 return false; 665 } 666 667 SkTDArray<GrGLuint> shadersToDelete; 668 669 if (!this->compileAndAttachShaders(fOutput.fProgramID, &shadersToDelete)) { 670 GL_CALL(DeleteProgram(fOutput.fProgramID)); 671 return false; 672 } 673 674 this->bindProgramLocations(fOutput.fProgramID); 675 if (fUniformManager->isUsingBindUniform()) { 676 fUniformManager->getUniformLocations(fOutput.fProgramID, fUniforms); 677 } 678 679 GL_CALL(LinkProgram(fOutput.fProgramID)); 680 681 // Calling GetProgramiv is expensive in Chromium. Assume success in release builds. 682 bool checkLinked = !fGpu->ctxInfo().isChromium(); 683 #ifdef SK_DEBUG 684 checkLinked = true; 685 #endif 686 if (checkLinked) { 687 GrGLint linked = GR_GL_INIT_ZERO; 688 GL_CALL(GetProgramiv(fOutput.fProgramID, GR_GL_LINK_STATUS, &linked)); 689 if (!linked) { 690 GrGLint infoLen = GR_GL_INIT_ZERO; 691 GL_CALL(GetProgramiv(fOutput.fProgramID, GR_GL_INFO_LOG_LENGTH, &infoLen)); 692 SkAutoMalloc log(sizeof(char)*(infoLen+1)); // outside if for debugger 693 if (infoLen > 0) { 694 // retrieve length even though we don't need it to workaround 695 // bug in chrome cmd buffer param validation. 696 GrGLsizei length = GR_GL_INIT_ZERO; 697 GL_CALL(GetProgramInfoLog(fOutput.fProgramID, 698 infoLen+1, 699 &length, 700 (char*)log.get())); 701 GrPrintf((char*)log.get()); 702 } 703 SkDEBUGFAIL("Error linking program"); 704 GL_CALL(DeleteProgram(fOutput.fProgramID)); 705 fOutput.fProgramID = 0; 706 return false; 707 } 708 } 709 710 if (!fUniformManager->isUsingBindUniform()) { 711 fUniformManager->getUniformLocations(fOutput.fProgramID, fUniforms); 712 } 713 714 for (int i = 0; i < shadersToDelete.count(); ++i) { 715 GL_CALL(DeleteShader(shadersToDelete[i])); 716 } 717 718 return true; 719 } 720 721 // Compiles a GL shader and attaches it to a program. Returns the shader ID if 722 // successful, or 0 if not. 723 static GrGLuint attach_shader(const GrGLContext& glCtx, 724 GrGLuint programId, 725 GrGLenum type, 726 const SkString& shaderSrc) { 727 const GrGLInterface* gli = glCtx.interface(); 728 729 GrGLuint shaderId; 730 GR_GL_CALL_RET(gli, shaderId, CreateShader(type)); 731 if (0 == shaderId) { 732 return 0; 733 } 734 735 const GrGLchar* sourceStr = shaderSrc.c_str(); 736 GrGLint sourceLength = static_cast<GrGLint>(shaderSrc.size()); 737 GR_GL_CALL(gli, ShaderSource(shaderId, 1, &sourceStr, &sourceLength)); 738 GR_GL_CALL(gli, CompileShader(shaderId)); 739 740 // Calling GetShaderiv in Chromium is quite expensive. Assume success in release builds. 741 bool checkCompiled = !glCtx.isChromium(); 742 #ifdef SK_DEBUG 743 checkCompiled = true; 744 #endif 745 if (checkCompiled) { 746 GrGLint compiled = GR_GL_INIT_ZERO; 747 GR_GL_CALL(gli, GetShaderiv(shaderId, GR_GL_COMPILE_STATUS, &compiled)); 748 749 if (!compiled) { 750 GrGLint infoLen = GR_GL_INIT_ZERO; 751 GR_GL_CALL(gli, GetShaderiv(shaderId, GR_GL_INFO_LOG_LENGTH, &infoLen)); 752 SkAutoMalloc log(sizeof(char)*(infoLen+1)); // outside if for debugger 753 if (infoLen > 0) { 754 // retrieve length even though we don't need it to workaround bug in Chromium cmd 755 // buffer param validation. 756 GrGLsizei length = GR_GL_INIT_ZERO; 757 GR_GL_CALL(gli, GetShaderInfoLog(shaderId, infoLen+1, 758 &length, (char*)log.get())); 759 GrPrintf(shaderSrc.c_str()); 760 GrPrintf("\n%s", log.get()); 761 } 762 SkDEBUGFAIL("Shader compilation failed!"); 763 GR_GL_CALL(gli, DeleteShader(shaderId)); 764 return 0; 765 } 766 } 767 if (c_PrintShaders) { 768 GrPrintf(shaderSrc.c_str()); 769 GrPrintf("\n"); 770 } 771 772 // Attach the shader, but defer deletion until after we have linked the program. 773 // This works around a bug in the Android emulator's GLES2 wrapper which 774 // will immediately delete the shader object and free its memory even though it's 775 // attached to a program, which then causes glLinkProgram to fail. 776 GR_GL_CALL(gli, AttachShader(programId, shaderId)); 777 778 return shaderId; 779 } 780 781 bool GrGLShaderBuilder::compileAndAttachShaders(GrGLuint programId, SkTDArray<GrGLuint>* shaderIds) const { 782 SkString fragShaderSrc(GrGetGLSLVersionDecl(this->ctxInfo())); 783 fragShaderSrc.append(fFSExtensions); 784 append_default_precision_qualifier(kDefaultFragmentPrecision, 785 fGpu->glStandard(), 786 &fragShaderSrc); 787 this->appendUniformDecls(kFragment_Visibility, &fragShaderSrc); 788 this->appendDecls(fFSInputs, &fragShaderSrc); 789 // We shouldn't have declared outputs on 1.10 790 SkASSERT(k110_GrGLSLGeneration != fGpu->glslGeneration() || fFSOutputs.empty()); 791 this->appendDecls(fFSOutputs, &fragShaderSrc); 792 fragShaderSrc.append(fFSFunctions); 793 fragShaderSrc.append("void main() {\n"); 794 fragShaderSrc.append(fFSCode); 795 fragShaderSrc.append("}\n"); 796 797 GrGLuint fragShaderId = attach_shader(fGpu->glContext(), programId, GR_GL_FRAGMENT_SHADER, fragShaderSrc); 798 if (!fragShaderId) { 799 return false; 800 } 801 802 *shaderIds->append() = fragShaderId; 803 804 return true; 805 } 806 807 void GrGLShaderBuilder::bindProgramLocations(GrGLuint programId) const { 808 if (fHasCustomColorOutput) { 809 GL_CALL(BindFragDataLocation(programId, 0, declared_color_output_name())); 810 } 811 if (fHasSecondaryOutput) { 812 GL_CALL(BindFragDataLocationIndexed(programId, 0, 1, dual_source_output_name())); 813 } 814 } 815 816 const GrGLContextInfo& GrGLShaderBuilder::ctxInfo() const { 817 return fGpu->ctxInfo(); 818 } 819 820 //////////////////////////////////////////////////////////////////////////////// 821 822 GrGLFullShaderBuilder::GrGLFullShaderBuilder(GrGpuGL* gpu, 823 GrGLUniformManager* uniformManager, 824 const GrGLProgramDesc& desc) 825 : INHERITED(gpu, uniformManager, desc) 826 , fVSAttrs(kVarsPerBlock) 827 , fVSOutputs(kVarsPerBlock) 828 , fGSInputs(kVarsPerBlock) 829 , fGSOutputs(kVarsPerBlock) { 830 } 831 832 void GrGLFullShaderBuilder::emitCodeBeforeEffects(GrGLSLExpr4* color, GrGLSLExpr4* coverage) { 833 const GrGLProgramDesc::KeyHeader& header = this->desc().getHeader(); 834 835 fOutput.fHasVertexShader = true; 836 837 fPositionVar = &fVSAttrs.push_back(); 838 fPositionVar->set(kVec2f_GrSLType, GrGLShaderVar::kAttribute_TypeModifier, "aPosition"); 839 if (-1 != header.fLocalCoordAttributeIndex) { 840 fLocalCoordsVar = &fVSAttrs.push_back(); 841 fLocalCoordsVar->set(kVec2f_GrSLType, 842 GrGLShaderVar::kAttribute_TypeModifier, 843 "aLocalCoords"); 844 } else { 845 fLocalCoordsVar = fPositionVar; 846 } 847 848 const char* viewMName; 849 fOutput.fUniformHandles.fViewMatrixUni = 850 this->addUniform(GrGLShaderBuilder::kVertex_Visibility, kMat33f_GrSLType, "ViewM", 851 &viewMName); 852 853 // Transform the position into Skia's device coords. 854 this->vsCodeAppendf("\tvec3 pos3 = %s * vec3(%s, 1);\n", 855 viewMName, fPositionVar->c_str()); 856 857 // we output point size in the GS if present 858 if (header.fEmitsPointSize 859 #if GR_GL_EXPERIMENTAL_GS 860 && !header.fExperimentalGS 861 #endif 862 ) { 863 this->vsCodeAppend("\tgl_PointSize = 1.0;\n"); 864 } 865 866 if (GrGLProgramDesc::kAttribute_ColorInput == header.fColorInput) { 867 this->addAttribute(kVec4f_GrSLType, color_attribute_name()); 868 const char *vsName, *fsName; 869 this->addVarying(kVec4f_GrSLType, "Color", &vsName, &fsName); 870 this->vsCodeAppendf("\t%s = %s;\n", vsName, color_attribute_name()); 871 *color = fsName; 872 } 873 874 if (GrGLProgramDesc::kAttribute_ColorInput == header.fCoverageInput) { 875 this->addAttribute(kVec4f_GrSLType, coverage_attribute_name()); 876 const char *vsName, *fsName; 877 this->addVarying(kVec4f_GrSLType, "Coverage", &vsName, &fsName); 878 this->vsCodeAppendf("\t%s = %s;\n", vsName, coverage_attribute_name()); 879 *coverage = fsName; 880 } 881 } 882 883 void GrGLFullShaderBuilder::emitCodeAfterEffects() { 884 const char* rtAdjustName; 885 fOutput.fUniformHandles.fRTAdjustmentUni = 886 this->addUniform(GrGLShaderBuilder::kVertex_Visibility, kVec4f_GrSLType, "rtAdjustment", 887 &rtAdjustName); 888 889 // Transform from Skia's device coords to GL's normalized device coords. 890 this->vsCodeAppendf( 891 "\tgl_Position = vec4(dot(pos3.xz, %s.xy), dot(pos3.yz, %s.zw), 0, pos3.z);\n", 892 rtAdjustName, rtAdjustName); 893 } 894 895 bool GrGLFullShaderBuilder::addAttribute(GrSLType type, const char* name) { 896 for (int i = 0; i < fVSAttrs.count(); ++i) { 897 const GrGLShaderVar& attr = fVSAttrs[i]; 898 // if attribute already added, don't add it again 899 if (attr.getName().equals(name)) { 900 SkASSERT(attr.getType() == type); 901 return false; 902 } 903 } 904 fVSAttrs.push_back().set(type, 905 GrGLShaderVar::kAttribute_TypeModifier, 906 name); 907 return true; 908 } 909 910 bool GrGLFullShaderBuilder::addEffectAttribute(int attributeIndex, 911 GrSLType type, 912 const SkString& name) { 913 if (!this->addAttribute(type, name.c_str())) { 914 return false; 915 } 916 917 fEffectAttributes.push_back().set(attributeIndex, name); 918 return true; 919 } 920 921 void GrGLFullShaderBuilder::addVarying(GrSLType type, 922 const char* name, 923 const char** vsOutName, 924 const char** fsInName) { 925 fVSOutputs.push_back(); 926 fVSOutputs.back().setType(type); 927 fVSOutputs.back().setTypeModifier(GrGLShaderVar::kVaryingOut_TypeModifier); 928 this->nameVariable(fVSOutputs.back().accessName(), 'v', name); 929 930 if (vsOutName) { 931 *vsOutName = fVSOutputs.back().getName().c_str(); 932 } 933 // input to FS comes either from VS or GS 934 const SkString* fsName; 935 #if GR_GL_EXPERIMENTAL_GS 936 if (this->desc().getHeader().fExperimentalGS) { 937 // if we have a GS take each varying in as an array 938 // and output as non-array. 939 fGSInputs.push_back(); 940 fGSInputs.back().setType(type); 941 fGSInputs.back().setTypeModifier(GrGLShaderVar::kVaryingIn_TypeModifier); 942 fGSInputs.back().setUnsizedArray(); 943 *fGSInputs.back().accessName() = fVSOutputs.back().getName(); 944 fGSOutputs.push_back(); 945 fGSOutputs.back().setType(type); 946 fGSOutputs.back().setTypeModifier(GrGLShaderVar::kVaryingOut_TypeModifier); 947 this->nameVariable(fGSOutputs.back().accessName(), 'g', name); 948 fsName = fGSOutputs.back().accessName(); 949 } else 950 #endif 951 { 952 fsName = fVSOutputs.back().accessName(); 953 } 954 this->fsInputAppend().set(type, GrGLShaderVar::kVaryingIn_TypeModifier, *fsName); 955 if (fsInName) { 956 *fsInName = fsName->c_str(); 957 } 958 } 959 960 const SkString* GrGLFullShaderBuilder::getEffectAttributeName(int attributeIndex) const { 961 const AttributePair* attribEnd = fEffectAttributes.end(); 962 for (const AttributePair* attrib = fEffectAttributes.begin(); attrib != attribEnd; ++attrib) { 963 if (attrib->fIndex == attributeIndex) { 964 return &attrib->fName; 965 } 966 } 967 968 return NULL; 969 } 970 971 GrGLProgramEffects* GrGLFullShaderBuilder::createAndEmitEffects( 972 const GrEffectStage* effectStages[], 973 const EffectKey effectKeys[], 974 int effectCnt, 975 GrGLSLExpr4* inOutFSColor) { 976 977 GrGLVertexProgramEffectsBuilder programEffectsBuilder(this, effectCnt); 978 this->INHERITED::createAndEmitEffects(&programEffectsBuilder, 979 effectStages, 980 effectKeys, 981 effectCnt, 982 inOutFSColor); 983 return programEffectsBuilder.finish(); 984 } 985 986 bool GrGLFullShaderBuilder::compileAndAttachShaders(GrGLuint programId, 987 SkTDArray<GrGLuint>* shaderIds) const { 988 const GrGLContext& glCtx = this->gpu()->glContext(); 989 SkString vertShaderSrc(GrGetGLSLVersionDecl(this->ctxInfo())); 990 this->appendUniformDecls(kVertex_Visibility, &vertShaderSrc); 991 this->appendDecls(fVSAttrs, &vertShaderSrc); 992 this->appendDecls(fVSOutputs, &vertShaderSrc); 993 vertShaderSrc.append("void main() {\n"); 994 vertShaderSrc.append(fVSCode); 995 vertShaderSrc.append("}\n"); 996 GrGLuint vertShaderId = attach_shader(glCtx, programId, GR_GL_VERTEX_SHADER, vertShaderSrc); 997 if (!vertShaderId) { 998 return false; 999 } 1000 *shaderIds->append() = vertShaderId; 1001 1002 #if GR_GL_EXPERIMENTAL_GS 1003 if (this->desc().getHeader().fExperimentalGS) { 1004 SkASSERT(this->ctxInfo().glslGeneration() >= k150_GrGLSLGeneration); 1005 SkString geomShaderSrc(GrGetGLSLVersionDecl(this->ctxInfo())); 1006 geomShaderSrc.append("layout(triangles) in;\n" 1007 "layout(triangle_strip, max_vertices = 6) out;\n"); 1008 this->appendDecls(fGSInputs, &geomShaderSrc); 1009 this->appendDecls(fGSOutputs, &geomShaderSrc); 1010 geomShaderSrc.append("void main() {\n"); 1011 geomShaderSrc.append("\tfor (int i = 0; i < 3; ++i) {\n" 1012 "\t\tgl_Position = gl_in[i].gl_Position;\n"); 1013 if (this->desc().getHeader().fEmitsPointSize) { 1014 geomShaderSrc.append("\t\tgl_PointSize = 1.0;\n"); 1015 } 1016 SkASSERT(fGSInputs.count() == fGSOutputs.count()); 1017 for (int i = 0; i < fGSInputs.count(); ++i) { 1018 geomShaderSrc.appendf("\t\t%s = %s[i];\n", 1019 fGSOutputs[i].getName().c_str(), 1020 fGSInputs[i].getName().c_str()); 1021 } 1022 geomShaderSrc.append("\t\tEmitVertex();\n" 1023 "\t}\n" 1024 "\tEndPrimitive();\n"); 1025 geomShaderSrc.append("}\n"); 1026 GrGLuint geomShaderId = attach_shader(glCtx, programId, GR_GL_GEOMETRY_SHADER, geomShaderSrc); 1027 if (!geomShaderId) { 1028 return false; 1029 } 1030 *shaderIds->append() = geomShaderId; 1031 } 1032 #endif 1033 1034 return this->INHERITED::compileAndAttachShaders(programId, shaderIds); 1035 } 1036 1037 void GrGLFullShaderBuilder::bindProgramLocations(GrGLuint programId) const { 1038 this->INHERITED::bindProgramLocations(programId); 1039 1040 const GrGLProgramDesc::KeyHeader& header = this->desc().getHeader(); 1041 1042 // Bind the attrib locations to same values for all shaders 1043 SkASSERT(-1 != header.fPositionAttributeIndex); 1044 GL_CALL(BindAttribLocation(programId, 1045 header.fPositionAttributeIndex, 1046 fPositionVar->c_str())); 1047 if (-1 != header.fLocalCoordAttributeIndex) { 1048 GL_CALL(BindAttribLocation(programId, 1049 header.fLocalCoordAttributeIndex, 1050 fLocalCoordsVar->c_str())); 1051 } 1052 if (-1 != header.fColorAttributeIndex) { 1053 GL_CALL(BindAttribLocation(programId, 1054 header.fColorAttributeIndex, 1055 color_attribute_name())); 1056 } 1057 if (-1 != header.fCoverageAttributeIndex) { 1058 GL_CALL(BindAttribLocation(programId, 1059 header.fCoverageAttributeIndex, 1060 coverage_attribute_name())); 1061 } 1062 1063 const AttributePair* attribEnd = fEffectAttributes.end(); 1064 for (const AttributePair* attrib = fEffectAttributes.begin(); attrib != attribEnd; ++attrib) { 1065 GL_CALL(BindAttribLocation(programId, attrib->fIndex, attrib->fName.c_str())); 1066 } 1067 } 1068 1069 //////////////////////////////////////////////////////////////////////////////// 1070 1071 GrGLFragmentOnlyShaderBuilder::GrGLFragmentOnlyShaderBuilder(GrGpuGL* gpu, 1072 GrGLUniformManager* uniformManager, 1073 const GrGLProgramDesc& desc) 1074 : INHERITED(gpu, uniformManager, desc) { 1075 SkASSERT(!desc.getHeader().fHasVertexCode); 1076 SkASSERT(gpu->glCaps().pathRenderingSupport()); 1077 SkASSERT(GrGLProgramDesc::kAttribute_ColorInput != desc.getHeader().fColorInput); 1078 SkASSERT(GrGLProgramDesc::kAttribute_ColorInput != desc.getHeader().fCoverageInput); 1079 } 1080 1081 int GrGLFragmentOnlyShaderBuilder::addTexCoordSets(int count) { 1082 int firstFreeCoordSet = fOutput.fTexCoordSetCnt; 1083 fOutput.fTexCoordSetCnt += count; 1084 SkASSERT(gpu()->glCaps().maxFixedFunctionTextureCoords() >= fOutput.fTexCoordSetCnt); 1085 return firstFreeCoordSet; 1086 } 1087 1088 GrGLProgramEffects* GrGLFragmentOnlyShaderBuilder::createAndEmitEffects( 1089 const GrEffectStage* effectStages[], 1090 const EffectKey effectKeys[], 1091 int effectCnt, 1092 GrGLSLExpr4* inOutFSColor) { 1093 1094 GrGLPathTexGenProgramEffectsBuilder pathTexGenEffectsBuilder(this, 1095 effectCnt); 1096 this->INHERITED::createAndEmitEffects(&pathTexGenEffectsBuilder, 1097 effectStages, 1098 effectKeys, 1099 effectCnt, 1100 inOutFSColor); 1101 return pathTexGenEffectsBuilder.finish(); 1102 } 1103