GrGLProgram.cpp revision 824c346b6e0e114063c1a8ad4ba7c3a669ee2cff
1/* 2 * Copyright 2011 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 "GrGLProgram.h" 9 10#include "GrAllocator.h" 11#include "GrEffect.h" 12#include "GrCoordTransform.h" 13#include "GrDrawEffect.h" 14#include "GrGLEffect.h" 15#include "GrGpuGL.h" 16#include "GrGLShaderVar.h" 17#include "GrGLSL.h" 18#include "SkXfermode.h" 19 20SK_DEFINE_INST_COUNT(GrGLProgram) 21 22#define GL_CALL(X) GR_GL_CALL(fGpu->glInterface(), X) 23#define GL_CALL_RET(R, X) GR_GL_CALL_RET(fGpu->glInterface(), R, X) 24 25GrGLProgram* GrGLProgram::Create(GrGpuGL* gpu, 26 const GrGLProgramDesc& desc, 27 const GrEffectStage* colorStages[], 28 const GrEffectStage* coverageStages[]) { 29 GrGLProgram* program = SkNEW_ARGS(GrGLProgram, (gpu, desc, colorStages, coverageStages)); 30 if (!program->succeeded()) { 31 delete program; 32 program = NULL; 33 } 34 return program; 35} 36 37GrGLProgram::GrGLProgram(GrGpuGL* gpu, 38 const GrGLProgramDesc& desc, 39 const GrEffectStage* colorStages[], 40 const GrEffectStage* coverageStages[]) 41: fGpu(gpu) 42, fUniformManager(gpu) 43, fHasVertexShader(false) 44, fNumTexCoordSets(0) { 45 fDesc = desc; 46 fProgramID = 0; 47 48 fDstCopyTexUnit = -1; 49 50 fColor = GrColor_ILLEGAL; 51 fColorFilterColor = GrColor_ILLEGAL; 52 53 if (fDesc.getHeader().fHasVertexCode || 54 !fGpu->glCaps().fixedFunctionSupport() || 55 !fGpu->glCaps().pathRenderingSupport()) { 56 57 GrGLFullShaderBuilder fullBuilder(fGpu, fUniformManager, fDesc); 58 if (this->genProgram(&fullBuilder, colorStages, coverageStages)) { 59 fUniformHandles.fViewMatrixUni = fullBuilder.getViewMatrixUniform(); 60 fHasVertexShader = true; 61 } 62 } else { 63 GrGLFragmentOnlyShaderBuilder fragmentOnlyBuilder(fGpu, fUniformManager, fDesc); 64 if (this->genProgram(&fragmentOnlyBuilder, colorStages, coverageStages)) { 65 fNumTexCoordSets = fragmentOnlyBuilder.getNumTexCoordSets(); 66 } 67 } 68} 69 70GrGLProgram::~GrGLProgram() { 71 if (fProgramID) { 72 GL_CALL(DeleteProgram(fProgramID)); 73 } 74} 75 76void GrGLProgram::abandon() { 77 fProgramID = 0; 78} 79 80void GrGLProgram::overrideBlend(GrBlendCoeff* srcCoeff, 81 GrBlendCoeff* dstCoeff) const { 82 switch (fDesc.getHeader().fCoverageOutput) { 83 case GrGLProgramDesc::kModulate_CoverageOutput: 84 break; 85 // The prog will write a coverage value to the secondary 86 // output and the dst is blended by one minus that value. 87 case GrGLProgramDesc::kSecondaryCoverage_CoverageOutput: 88 case GrGLProgramDesc::kSecondaryCoverageISA_CoverageOutput: 89 case GrGLProgramDesc::kSecondaryCoverageISC_CoverageOutput: 90 *dstCoeff = (GrBlendCoeff)GrGpu::kIS2C_GrBlendCoeff; 91 break; 92 case GrGLProgramDesc::kCombineWithDst_CoverageOutput: 93 // We should only have set this if the blend was specified as (1, 0) 94 SkASSERT(kOne_GrBlendCoeff == *srcCoeff && kZero_GrBlendCoeff == *dstCoeff); 95 break; 96 default: 97 GrCrash("Unexpected coverage output"); 98 break; 99 } 100} 101 102namespace { 103// given two blend coefficients determine whether the src 104// and/or dst computation can be omitted. 105inline void need_blend_inputs(SkXfermode::Coeff srcCoeff, 106 SkXfermode::Coeff dstCoeff, 107 bool* needSrcValue, 108 bool* needDstValue) { 109 if (SkXfermode::kZero_Coeff == srcCoeff) { 110 switch (dstCoeff) { 111 // these all read the src 112 case SkXfermode::kSC_Coeff: 113 case SkXfermode::kISC_Coeff: 114 case SkXfermode::kSA_Coeff: 115 case SkXfermode::kISA_Coeff: 116 *needSrcValue = true; 117 break; 118 default: 119 *needSrcValue = false; 120 break; 121 } 122 } else { 123 *needSrcValue = true; 124 } 125 if (SkXfermode::kZero_Coeff == dstCoeff) { 126 switch (srcCoeff) { 127 // these all read the dst 128 case SkXfermode::kDC_Coeff: 129 case SkXfermode::kIDC_Coeff: 130 case SkXfermode::kDA_Coeff: 131 case SkXfermode::kIDA_Coeff: 132 *needDstValue = true; 133 break; 134 default: 135 *needDstValue = false; 136 break; 137 } 138 } else { 139 *needDstValue = true; 140 } 141} 142 143/** 144 * Create a blend_coeff * value string to be used in shader code. Sets empty 145 * string if result is trivially zero. 146 */ 147inline void blend_term_string(SkString* str, SkXfermode::Coeff coeff, 148 const char* src, const char* dst, 149 const char* value) { 150 switch (coeff) { 151 case SkXfermode::kZero_Coeff: /** 0 */ 152 *str = ""; 153 break; 154 case SkXfermode::kOne_Coeff: /** 1 */ 155 *str = value; 156 break; 157 case SkXfermode::kSC_Coeff: 158 str->printf("(%s * %s)", src, value); 159 break; 160 case SkXfermode::kISC_Coeff: 161 str->printf("((vec4(1) - %s) * %s)", src, value); 162 break; 163 case SkXfermode::kDC_Coeff: 164 str->printf("(%s * %s)", dst, value); 165 break; 166 case SkXfermode::kIDC_Coeff: 167 str->printf("((vec4(1) - %s) * %s)", dst, value); 168 break; 169 case SkXfermode::kSA_Coeff: /** src alpha */ 170 str->printf("(%s.a * %s)", src, value); 171 break; 172 case SkXfermode::kISA_Coeff: /** inverse src alpha (i.e. 1 - sa) */ 173 str->printf("((1.0 - %s.a) * %s)", src, value); 174 break; 175 case SkXfermode::kDA_Coeff: /** dst alpha */ 176 str->printf("(%s.a * %s)", dst, value); 177 break; 178 case SkXfermode::kIDA_Coeff: /** inverse dst alpha (i.e. 1 - da) */ 179 str->printf("((1.0 - %s.a) * %s)", dst, value); 180 break; 181 default: 182 GrCrash("Unexpected xfer coeff."); 183 break; 184 } 185} 186/** 187 * Adds a line to the fragment shader code which modifies the color by 188 * the specified color filter. 189 */ 190void add_color_filter(GrGLShaderBuilder* builder, 191 const char * outputVar, 192 SkXfermode::Coeff uniformCoeff, 193 SkXfermode::Coeff colorCoeff, 194 const char* filterColor, 195 const char* inColor) { 196 SkString colorStr, constStr; 197 blend_term_string(&colorStr, colorCoeff, filterColor, inColor, inColor); 198 blend_term_string(&constStr, uniformCoeff, filterColor, inColor, filterColor); 199 GrGLSLExpr<4> sum; 200 if (colorStr.isEmpty() && constStr.isEmpty()) { 201 sum = GrGLSLExpr<4>(0); 202 } else if (colorStr.isEmpty()) { 203 sum = constStr; 204 } else if (constStr.isEmpty()) { 205 sum = colorStr; 206 } else { 207 sum = GrGLSLExpr<4>(colorStr) + GrGLSLExpr<4>(constStr); 208 } 209 builder->fsCodeAppendf("\t%s = %s;\n", outputVar, sum.c_str()); 210} 211} 212 213bool GrGLProgram::genProgram(GrGLShaderBuilder* builder, 214 const GrEffectStage* colorStages[], 215 const GrEffectStage* coverageStages[]) { 216 SkASSERT(0 == fProgramID); 217 218 const GrGLProgramDesc::KeyHeader& header = fDesc.getHeader(); 219 220 // incoming color to current stage being processed. 221 GrGLSLExpr<4> inColor = builder->getInputColor(); 222 223 // Get the coeffs for the Mode-based color filter, determine if color is needed. 224 SkXfermode::Coeff colorCoeff; 225 SkXfermode::Coeff filterColorCoeff; 226 SkAssertResult( 227 SkXfermode::ModeAsCoeff(header.fColorFilterXfermode, 228 &filterColorCoeff, 229 &colorCoeff)); 230 bool needColor, needFilterColor; 231 need_blend_inputs(filterColorCoeff, colorCoeff, &needFilterColor, &needColor); 232 233 fColorEffects.reset( 234 builder->createAndEmitEffects(colorStages, 235 fDesc.effectKeys(), 236 needColor ? fDesc.numColorEffects() : 0, 237 &inColor)); 238 239 // Insert the color filter. This will soon be replaced by a color effect. 240 if (SkXfermode::kDst_Mode != header.fColorFilterXfermode) { 241 const char* colorFilterColorUniName = NULL; 242 fUniformHandles.fColorFilterUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility, 243 kVec4f_GrSLType, "FilterColor", 244 &colorFilterColorUniName); 245 246 builder->fsCodeAppend("\tvec4 filteredColor;\n"); 247 add_color_filter(builder, "filteredColor", filterColorCoeff, 248 colorCoeff, colorFilterColorUniName, inColor.c_str()); 249 inColor = "filteredColor"; 250 } 251 252 /////////////////////////////////////////////////////////////////////////// 253 // compute the partial coverage 254 GrGLSLExpr<4> inCoverage = builder->getInputCoverage(); 255 256 fCoverageEffects.reset( 257 builder->createAndEmitEffects(coverageStages, 258 fDesc.getEffectKeys() + fDesc.numColorEffects(), 259 fDesc.numCoverageEffects(), 260 &inCoverage)); 261 262 // discard if coverage is zero 263 if (header.fDiscardIfZeroCoverage && !inCoverage.isOnes()) { 264 if (inCoverage.isZeros()) { 265 // This is unfortunate. 266 builder->fsCodeAppend("\tdiscard;\n"); 267 } else { 268 builder->fsCodeAppendf("\tif (all(lessThanEqual(%s, vec4(0.0)))) {\n\t\tdiscard;\n\t}\n", 269 inCoverage.c_str()); 270 } 271 } 272 273 if (GrGLProgramDesc::CoverageOutputUsesSecondaryOutput(header.fCoverageOutput)) { 274 const char* secondaryOutputName = builder->enableSecondaryOutput(); 275 276 // default coeff to ones for kCoverage_DualSrcOutput 277 GrGLSLExpr<4> coeff(1); 278 if (GrGLProgramDesc::kSecondaryCoverageISA_CoverageOutput == header.fCoverageOutput) { 279 // Get (1-A) into coeff 280 coeff = GrGLSLExprCast4(GrGLSLExpr<1>(1) - GrGLSLExprExtractAlpha(inColor)); 281 } else if (GrGLProgramDesc::kSecondaryCoverageISC_CoverageOutput == header.fCoverageOutput) { 282 // Get (1-RGBA) into coeff 283 coeff = GrGLSLExpr<4>(1) - inColor; 284 } 285 // Get coeff * coverage into modulate and then write that to the dual source output. 286 builder->fsCodeAppendf("\t%s = %s;\n", secondaryOutputName, (coeff * inCoverage).c_str()); 287 } 288 289 /////////////////////////////////////////////////////////////////////////// 290 // combine color and coverage as frag color 291 292 // Get "color * coverage" into fragColor 293 GrGLSLExpr<4> fragColor = inColor * inCoverage; 294 // Now tack on "+(1-coverage)dst onto the frag color if we were asked to do so. 295 if (GrGLProgramDesc::kCombineWithDst_CoverageOutput == header.fCoverageOutput) { 296 GrGLSLExpr<4> dstCoeff = GrGLSLExpr<4>(1) - inCoverage; 297 298 GrGLSLExpr<4> dstContribution = dstCoeff * GrGLSLExpr<4>(builder->dstColor()); 299 300 fragColor = fragColor + dstContribution; 301 } 302 builder->fsCodeAppendf("\t%s = %s;\n", builder->getColorOutputName(), fragColor.c_str()); 303 304 if (!builder->finish(&fProgramID)) { 305 return false; 306 } 307 308 fUniformHandles.fRTHeightUni = builder->getRTHeightUniform(); 309 fUniformHandles.fDstCopyTopLeftUni = builder->getDstCopyTopLeftUniform(); 310 fUniformHandles.fDstCopyScaleUni = builder->getDstCopyScaleUniform(); 311 fUniformHandles.fColorUni = builder->getColorUniform(); 312 fUniformHandles.fCoverageUni = builder->getCoverageUniform(); 313 fUniformHandles.fDstCopySamplerUni = builder->getDstCopySamplerUniform(); 314 // This must be called after we set fDstCopySamplerUni above. 315 this->initSamplerUniforms(); 316 317 return true; 318} 319 320void GrGLProgram::initSamplerUniforms() { 321 GL_CALL(UseProgram(fProgramID)); 322 GrGLint texUnitIdx = 0; 323 if (fUniformHandles.fDstCopySamplerUni.isValid()) { 324 fUniformManager.setSampler(fUniformHandles.fDstCopySamplerUni, texUnitIdx); 325 fDstCopyTexUnit = texUnitIdx++; 326 } 327 fColorEffects->initSamplers(fUniformManager, &texUnitIdx); 328 fCoverageEffects->initSamplers(fUniformManager, &texUnitIdx); 329} 330 331/////////////////////////////////////////////////////////////////////////////// 332 333void GrGLProgram::setData(GrDrawState::BlendOptFlags blendOpts, 334 const GrEffectStage* colorStages[], 335 const GrEffectStage* coverageStages[], 336 const GrDeviceCoordTexture* dstCopy, 337 SharedGLState* sharedState) { 338 const GrDrawState& drawState = fGpu->getDrawState(); 339 340 GrColor color; 341 GrColor coverage; 342 if (blendOpts & GrDrawState::kEmitTransBlack_BlendOptFlag) { 343 color = 0; 344 coverage = 0; 345 } else if (blendOpts & GrDrawState::kEmitCoverage_BlendOptFlag) { 346 color = 0xffffffff; 347 coverage = drawState.getCoverage(); 348 } else { 349 color = drawState.getColor(); 350 coverage = drawState.getCoverage(); 351 } 352 353 this->setColor(drawState, color, sharedState); 354 this->setCoverage(drawState, coverage, sharedState); 355 this->setMatrixAndRenderTargetHeight(drawState); 356 357 // Setup the SkXfermode::Mode-based colorfilter uniform if necessary 358 if (fUniformHandles.fColorFilterUni.isValid() && 359 fColorFilterColor != drawState.getColorFilterColor()) { 360 GrGLfloat c[4]; 361 GrColorToRGBAFloat(drawState.getColorFilterColor(), c); 362 fUniformManager.set4fv(fUniformHandles.fColorFilterUni, 0, 1, c); 363 fColorFilterColor = drawState.getColorFilterColor(); 364 } 365 366 if (NULL != dstCopy) { 367 if (fUniformHandles.fDstCopyTopLeftUni.isValid()) { 368 fUniformManager.set2f(fUniformHandles.fDstCopyTopLeftUni, 369 static_cast<GrGLfloat>(dstCopy->offset().fX), 370 static_cast<GrGLfloat>(dstCopy->offset().fY)); 371 fUniformManager.set2f(fUniformHandles.fDstCopyScaleUni, 372 1.f / dstCopy->texture()->width(), 373 1.f / dstCopy->texture()->height()); 374 GrGLTexture* texture = static_cast<GrGLTexture*>(dstCopy->texture()); 375 static GrTextureParams kParams; // the default is clamp, nearest filtering. 376 fGpu->bindTexture(fDstCopyTexUnit, kParams, texture); 377 } else { 378 SkASSERT(!fUniformHandles.fDstCopyScaleUni.isValid()); 379 SkASSERT(!fUniformHandles.fDstCopySamplerUni.isValid()); 380 } 381 } else { 382 SkASSERT(!fUniformHandles.fDstCopyTopLeftUni.isValid()); 383 SkASSERT(!fUniformHandles.fDstCopyScaleUni.isValid()); 384 SkASSERT(!fUniformHandles.fDstCopySamplerUni.isValid()); 385 } 386 387 fColorEffects->setData(fGpu, fUniformManager, colorStages); 388 fCoverageEffects->setData(fGpu, fUniformManager, coverageStages); 389 390 if (!fHasVertexShader) { 391 fGpu->disableUnusedTexGen(fNumTexCoordSets); 392 } 393} 394 395void GrGLProgram::setColor(const GrDrawState& drawState, 396 GrColor color, 397 SharedGLState* sharedState) { 398 const GrGLProgramDesc::KeyHeader& header = fDesc.getHeader(); 399 if (!drawState.hasColorVertexAttribute()) { 400 switch (header.fColorInput) { 401 case GrGLProgramDesc::kAttribute_ColorInput: 402 SkASSERT(-1 != header.fColorAttributeIndex); 403 if (sharedState->fConstAttribColor != color || 404 sharedState->fConstAttribColorIndex != header.fColorAttributeIndex) { 405 // OpenGL ES only supports the float varieties of glVertexAttrib 406 GrGLfloat c[4]; 407 GrColorToRGBAFloat(color, c); 408 GL_CALL(VertexAttrib4fv(header.fColorAttributeIndex, c)); 409 sharedState->fConstAttribColor = color; 410 sharedState->fConstAttribColorIndex = header.fColorAttributeIndex; 411 } 412 break; 413 case GrGLProgramDesc::kUniform_ColorInput: 414 if (fColor != color) { 415 // OpenGL ES doesn't support unsigned byte varieties of glUniform 416 GrGLfloat c[4]; 417 GrColorToRGBAFloat(color, c); 418 fUniformManager.set4fv(fUniformHandles.fColorUni, 0, 1, c); 419 fColor = color; 420 } 421 sharedState->fConstAttribColorIndex = -1; 422 break; 423 case GrGLProgramDesc::kSolidWhite_ColorInput: 424 case GrGLProgramDesc::kTransBlack_ColorInput: 425 sharedState->fConstAttribColorIndex = -1; 426 break; 427 default: 428 GrCrash("Unknown color type."); 429 } 430 } else { 431 sharedState->fConstAttribColorIndex = -1; 432 } 433} 434 435void GrGLProgram::setCoverage(const GrDrawState& drawState, 436 GrColor coverage, 437 SharedGLState* sharedState) { 438 const GrGLProgramDesc::KeyHeader& header = fDesc.getHeader(); 439 if (!drawState.hasCoverageVertexAttribute()) { 440 switch (header.fCoverageInput) { 441 case GrGLProgramDesc::kAttribute_ColorInput: 442 if (sharedState->fConstAttribCoverage != coverage || 443 sharedState->fConstAttribCoverageIndex != header.fCoverageAttributeIndex) { 444 // OpenGL ES only supports the float varieties of glVertexAttrib 445 GrGLfloat c[4]; 446 GrColorToRGBAFloat(coverage, c); 447 GL_CALL(VertexAttrib4fv(header.fCoverageAttributeIndex, c)); 448 sharedState->fConstAttribCoverage = coverage; 449 sharedState->fConstAttribCoverageIndex = header.fCoverageAttributeIndex; 450 } 451 break; 452 case GrGLProgramDesc::kUniform_ColorInput: 453 if (fCoverage != coverage) { 454 // OpenGL ES doesn't support unsigned byte varieties of glUniform 455 GrGLfloat c[4]; 456 GrColorToRGBAFloat(coverage, c); 457 fUniformManager.set4fv(fUniformHandles.fCoverageUni, 0, 1, c); 458 fCoverage = coverage; 459 } 460 sharedState->fConstAttribCoverageIndex = -1; 461 break; 462 case GrGLProgramDesc::kSolidWhite_ColorInput: 463 case GrGLProgramDesc::kTransBlack_ColorInput: 464 sharedState->fConstAttribCoverageIndex = -1; 465 break; 466 default: 467 GrCrash("Unknown coverage type."); 468 } 469 } else { 470 sharedState->fConstAttribCoverageIndex = -1; 471 } 472} 473 474void GrGLProgram::setMatrixAndRenderTargetHeight(const GrDrawState& drawState) { 475 const GrRenderTarget* rt = drawState.getRenderTarget(); 476 SkISize size; 477 size.set(rt->width(), rt->height()); 478 479 // Load the RT height uniform if it is needed to y-flip gl_FragCoord. 480 if (fUniformHandles.fRTHeightUni.isValid() && 481 fMatrixState.fRenderTargetSize.fHeight != size.fHeight) { 482 fUniformManager.set1f(fUniformHandles.fRTHeightUni, SkIntToScalar(size.fHeight)); 483 } 484 485 if (!fHasVertexShader) { 486 SkASSERT(!fUniformHandles.fViewMatrixUni.isValid()); 487 fGpu->setProjectionMatrix(drawState.getViewMatrix(), size, rt->origin()); 488 } else if (fMatrixState.fRenderTargetOrigin != rt->origin() || 489 fMatrixState.fRenderTargetSize != size || 490 !fMatrixState.fViewMatrix.cheapEqualTo(drawState.getViewMatrix())) { 491 SkASSERT(fUniformHandles.fViewMatrixUni.isValid()); 492 493 fMatrixState.fViewMatrix = drawState.getViewMatrix(); 494 fMatrixState.fRenderTargetSize = size; 495 fMatrixState.fRenderTargetOrigin = rt->origin(); 496 497 GrGLfloat viewMatrix[3 * 3]; 498 fMatrixState.getGLMatrix<3>(viewMatrix); 499 fUniformManager.setMatrix3f(fUniformHandles.fViewMatrixUni, viewMatrix); 500 } 501} 502