Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 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 "GrGLFragmentShaderBuilder.h" | |
| 9 #include "GrGLShaderStringBuilder.h" | |
| 10 #include "GrGLProgramBuilder.h" | |
| 11 #include "../GrGpuGL.h" | |
| 12 | |
| 13 //////////////////////////////////////////////////////////////////////////////// //////////////////// | |
|
bsalomon
2014/08/21 20:21:01
Having these local, static, private blocks is at o
| |
| 14 // local /////////////////////////////////////////////////////////////////////// //////////////////// | |
| 15 namespace { | |
| 16 #define GL_CALL(X) GR_GL_CALL(gpu->glInterface(), X) | |
| 17 #define GL_CALL_RET(R, X) GR_GL_CALL_RET(gpu->glInterface(), R, X) | |
| 18 // ES2 FS only guarantees mediump and lowp support | |
| 19 static const GrGLShaderVar::Precision kDefaultFragmentPrecision = GrGLShaderVar: :kMedium_Precision; | |
| 20 static const char kDstCopyColorName[] = "_dstColor"; | |
| 21 inline const char* declared_color_output_name() { return "fsColorOut"; } | |
| 22 inline const char* dual_source_output_name() { return "dualSourceOut"; } | |
| 23 inline void append_default_precision_qualifier(GrGLShaderVar::Precision p, | |
| 24 GrGLStandard standard, | |
| 25 SkString* str) { | |
| 26 // Desktop GLSL has added precision qualifiers but they don't do anything. | |
| 27 if (kGLES_GrGLStandard == standard) { | |
| 28 switch (p) { | |
| 29 case GrGLShaderVar::kHigh_Precision: | |
| 30 str->append("precision highp float;\n"); | |
| 31 break; | |
| 32 case GrGLShaderVar::kMedium_Precision: | |
| 33 str->append("precision mediump float;\n"); | |
| 34 break; | |
| 35 case GrGLShaderVar::kLow_Precision: | |
| 36 str->append("precision lowp float;\n"); | |
| 37 break; | |
| 38 case GrGLShaderVar::kDefault_Precision: | |
| 39 SkFAIL("Default precision now allowed."); | |
| 40 default: | |
| 41 SkFAIL("Unknown precision value."); | |
| 42 } | |
| 43 } | |
| 44 } | |
| 45 } | |
| 46 | |
| 47 //////////////////////////////////////////////////////////////////////////////// //////////////////// | |
| 48 // GrGLFragmentShaderBuilder static //////////////////////////////////////////// //////////////////// | |
| 49 GrGLFragmentShaderBuilder::DstReadKey GrGLFragmentShaderBuilder::KeyForDstRead( | |
| 50 const GrTexture* dstCopy, const GrGLCaps& caps) { | |
| 51 uint32_t key = kYesDstRead_DstReadKeyBit; | |
| 52 if (caps.fbFetchSupport()) { | |
| 53 return key; | |
| 54 } | |
| 55 SkASSERT(NULL != dstCopy); | |
| 56 if (!caps.textureSwizzleSupport() && GrPixelConfigIsAlphaOnly(dstCopy->confi g())) { | |
| 57 // The fact that the config is alpha-only must be considered when genera ting code. | |
| 58 key |= kUseAlphaConfig_DstReadKeyBit; | |
| 59 } | |
| 60 if (kTopLeft_GrSurfaceOrigin == dstCopy->origin()) { | |
| 61 key |= kTopLeftOrigin_DstReadKeyBit; | |
| 62 } | |
| 63 SkASSERT(static_cast<DstReadKey>(key) == key); | |
| 64 return static_cast<DstReadKey>(key); | |
| 65 } | |
| 66 | |
| 67 GrGLFragmentShaderBuilder::FragPosKey GrGLFragmentShaderBuilder::KeyForFragmentP osition( | |
| 68 const GrRenderTarget* dst, const GrGLCaps&) { | |
| 69 if (kTopLeft_GrSurfaceOrigin == dst->origin()) { | |
| 70 return kTopLeftFragPosRead_FragPosKey; | |
| 71 } else { | |
| 72 return kBottomLeftFragPosRead_FragPosKey; | |
| 73 } | |
| 74 } | |
| 75 | |
| 76 // GrGLFragmentShaderBuilder public //////////////////////////////////////////// /////////////////// | |
| 77 GrGLFragmentShaderBuilder::GrGLFragmentShaderBuilder(GrGLProgramBuilder* program , | |
| 78 const GrGLProgramDesc& desc ) | |
| 79 : INHERITED(program) | |
| 80 , fHasCustomColorOutput(false) | |
| 81 , fHasSecondaryOutput(false) | |
| 82 , fSetupFragPosition(false) | |
| 83 , fTopLeftFragPosRead(kTopLeftFragPosRead_FragPosKey == desc.getHeader().fFr agPosKey){ | |
| 84 } | |
| 85 | |
| 86 const char* GrGLFragmentShaderBuilder::dstColor() { | |
| 87 if (fProgram->fCodeStage.inStageCode()) { | |
| 88 const GrEffect* effect = fProgram->fCodeStage.effectStage()->getEffect() ; | |
| 89 if (!effect->willReadDstColor()) { | |
| 90 SkDEBUGFAIL("GrGLEffect asked for dst color but its generating GrEff ect " | |
| 91 "did not request access."); | |
| 92 return ""; | |
| 93 } | |
| 94 } | |
| 95 | |
| 96 GrGpuGL* gpu = fProgram->gpu(); | |
| 97 if (gpu->glCaps().fbFetchSupport()) { | |
| 98 this->addFeature(1 << (GrGLFragmentShaderBuilder::kLastGLSLPrivateFeatur e + 1), | |
| 99 gpu->glCaps().fbFetchExtensionString()); | |
| 100 return gpu->glCaps().fbFetchColorName(); | |
| 101 } else if (fProgram->fUniformHandles.fDstCopySamplerUni.isValid()) { | |
| 102 return kDstCopyColorName; | |
| 103 } else { | |
| 104 return ""; | |
| 105 } | |
| 106 } | |
| 107 | |
| 108 bool GrGLFragmentShaderBuilder::enableFeature(GLSLFeature feature) { | |
| 109 switch (feature) { | |
| 110 case kStandardDerivatives_GLSLFeature: { | |
| 111 GrGpuGL* gpu = fProgram->gpu(); | |
| 112 if (!gpu->glCaps().shaderDerivativeSupport()) { | |
| 113 return false; | |
| 114 } | |
| 115 if (kGLES_GrGLStandard == gpu->glStandard()) { | |
| 116 this->addFeature(1 << kStandardDerivatives_GLSLFeature, | |
| 117 "GL_OES_standard_derivatives"); | |
| 118 } | |
| 119 return true; | |
| 120 } | |
| 121 default: | |
| 122 SkFAIL("Unexpected GLSLFeature requested."); | |
| 123 return false; | |
| 124 } | |
| 125 } | |
| 126 | |
| 127 SkString GrGLFragmentShaderBuilder::ensureFSCoords2D(const TransformedCoordsArra y& coords, int index) { | |
| 128 if (kVec3f_GrSLType != coords[index].type()) { | |
| 129 SkASSERT(kVec2f_GrSLType == coords[index].type()); | |
| 130 return coords[index].getName(); | |
| 131 } | |
| 132 | |
| 133 SkString coords2D("coords2D"); | |
| 134 if (0 != index) { | |
| 135 coords2D.appendf("_%i", index); | |
| 136 } | |
| 137 this->codeAppendf("\tvec2 %s = %s.xy / %s.z;", | |
| 138 coords2D.c_str(), coords[index].c_str(), coords[index].c_s tr()); | |
| 139 return coords2D; | |
| 140 } | |
| 141 | |
| 142 const char* GrGLFragmentShaderBuilder::fragmentPosition() { | |
| 143 GrGLProgramBuilder::CodeStage* cs = &fProgram->fCodeStage; | |
| 144 if (cs->inStageCode()) { | |
| 145 const GrEffect* effect = cs->effectStage()->getEffect(); | |
| 146 if (!effect->willReadFragmentPosition()) { | |
| 147 SkDEBUGFAIL("GrGLEffect asked for frag position but its generating G rEffect " | |
| 148 "did not request access."); | |
| 149 return ""; | |
| 150 } | |
| 151 } | |
| 152 | |
| 153 GrGpuGL* gpu = fProgram->gpu(); | |
| 154 // We only declare "gl_FragCoord" when we're in the case where we want to us e layout qualifiers | |
| 155 // to reverse y. Otherwise it isn't necessary and whether the "in" qualifier appears in the | |
| 156 // declaration varies in earlier GLSL specs. So it is simpler to omit it. | |
| 157 if (fTopLeftFragPosRead) { | |
| 158 fSetupFragPosition = true; | |
| 159 return "gl_FragCoord"; | |
| 160 } else if (gpu->glCaps().fragCoordConventionsSupport()) { | |
| 161 if (!fSetupFragPosition) { | |
| 162 if (gpu->glslGeneration() < k150_GrGLSLGeneration) { | |
| 163 this->addFeature(1 << kFragCoordConventions_GLSLPrivateFeature, | |
| 164 "GL_ARB_fragment_coord_conventions"); | |
| 165 } | |
| 166 fInputs.push_back().set(kVec4f_GrSLType, | |
| 167 GrGLShaderVar::kIn_TypeModifier, | |
| 168 "gl_FragCoord", | |
| 169 GrGLShaderVar::kDefault_Precision, | |
| 170 GrGLShaderVar::kUpperLeft_Origin); | |
| 171 fSetupFragPosition = true; | |
| 172 } | |
| 173 return "gl_FragCoord"; | |
| 174 } else { | |
| 175 static const char* kCoordName = "fragCoordYDown"; | |
| 176 if (!fSetupFragPosition) { | |
| 177 // temporarily change the stage index because we're inserting non-st age code. | |
| 178 GrGLProgramBuilder::CodeStage::AutoStageRestore csar(cs, NULL); | |
| 179 | |
| 180 SkASSERT(!fProgram->fUniformHandles.fRTHeightUni.isValid()); | |
| 181 const char* rtHeightName; | |
| 182 | |
| 183 fProgram->fUniformHandles.fRTHeightUni = | |
| 184 fProgram->addUniform(GrGLProgramBuilder::kFragment_Visibilit y, | |
| 185 kFloat_GrSLType, | |
| 186 "RTHeight", | |
| 187 &rtHeightName); | |
| 188 | |
| 189 // Using glFragCoord.zw for the last two components tickles an Adren o driver bug that | |
| 190 // causes programs to fail to link. Making this function return a ve c2() didn't fix the | |
| 191 // problem but using 1.0 for the last two components does. | |
| 192 this->codePrependf("\tvec4 %s = vec4(gl_FragCoord.x, %s - gl_FragCoo rd.y, 1.0, " | |
| 193 "1.0);\n", kCoordName, rtHeightName); | |
| 194 fSetupFragPosition = true; | |
| 195 } | |
| 196 SkASSERT(fProgram->fUniformHandles.fRTHeightUni.isValid()); | |
| 197 return kCoordName; | |
| 198 } | |
| 199 } | |
| 200 | |
| 201 // GrGLFragmentShaderBuilder private /////////////////////////////////////////// /////////////////// | |
| 202 void GrGLFragmentShaderBuilder::addVarying(GrSLType type, | |
| 203 const char* name, | |
| 204 const char** fsInName) { | |
| 205 fInputs.push_back().set(type, GrGLShaderVar::kVaryingIn_TypeModifier, name); | |
| 206 if (fsInName) { | |
| 207 *fsInName = name; | |
| 208 } | |
| 209 } | |
| 210 | |
| 211 void GrGLFragmentShaderBuilder::bindProgramLocations(GrGLuint programId) { | |
| 212 GrGpuGL* gpu = fProgram->gpu(); | |
| 213 if (fHasCustomColorOutput) { | |
| 214 GL_CALL(BindFragDataLocation(programId, 0, declared_color_output_name()) ); | |
| 215 } | |
| 216 if (fHasSecondaryOutput) { | |
| 217 GL_CALL(BindFragDataLocationIndexed(programId, 0, 1, dual_source_output_ name())); | |
| 218 } | |
| 219 } | |
| 220 | |
| 221 bool GrGLFragmentShaderBuilder::compileAndAttachShaders(GrGLuint programId, | |
| 222 SkTDArray<GrGLuint>* sha derIds) const { | |
| 223 GrGpuGL* gpu = fProgram->gpu(); | |
| 224 SkString fragShaderSrc(GrGetGLSLVersionDecl(gpu->ctxInfo())); | |
| 225 fragShaderSrc.append(fExtensions); | |
| 226 append_default_precision_qualifier(kDefaultFragmentPrecision, | |
| 227 gpu->glStandard(), | |
| 228 &fragShaderSrc); | |
| 229 fProgram->appendUniformDecls(GrGLProgramBuilder::kFragment_Visibility, &frag ShaderSrc); | |
| 230 fProgram->appendDecls(fInputs, &fragShaderSrc); | |
| 231 // We shouldn't have declared outputs on 1.10 | |
| 232 SkASSERT(k110_GrGLSLGeneration != gpu->glslGeneration() || fOutputs.empty()) ; | |
| 233 fProgram->appendDecls(fOutputs, &fragShaderSrc); | |
| 234 fragShaderSrc.append(fFunctions); | |
| 235 fragShaderSrc.append("void main() {\n"); | |
| 236 fragShaderSrc.append(fCode); | |
| 237 fragShaderSrc.append("}\n"); | |
| 238 | |
| 239 GrGLuint fragShaderId = GrGLCompileAndAttachShader(gpu->glContext(), | |
| 240 programId, GR_GL_FRAGMENT_SHADER, fragShaderSrc); | |
| 241 if (!fragShaderId) { | |
| 242 return false; | |
| 243 } | |
| 244 | |
| 245 *shaderIds->append() = fragShaderId; | |
| 246 | |
| 247 return true; | |
| 248 } | |
| 249 | |
| 250 void GrGLFragmentShaderBuilder::emitCodeBeforeEffects() { | |
| 251 const GrGLProgramDesc::KeyHeader& header = fProgram->desc().getHeader(); | |
| 252 GrGpuGL* gpu = fProgram->gpu(); | |
| 253 | |
| 254 /////////////////////////////////////////////////////////////////////////// | |
| 255 // emit code to read the dst copy texture, if necessary | |
| 256 if (kNoDstRead_DstReadKey != header.fDstReadKey && !gpu->glCaps().fbFetchSup port()) { | |
| 257 bool topDown = SkToBool(kTopLeftOrigin_DstReadKeyBit & header.fDstReadKe y); | |
| 258 const char* dstCopyTopLeftName; | |
| 259 const char* dstCopyCoordScaleName; | |
| 260 const char* dstCopySamplerName; | |
| 261 uint32_t configMask; | |
| 262 if (SkToBool(kUseAlphaConfig_DstReadKeyBit & header.fDstReadKey)) { | |
| 263 configMask = kA_GrColorComponentFlag; | |
| 264 } else { | |
| 265 configMask = kRGBA_GrColorComponentFlags; | |
| 266 } | |
| 267 fProgram->fUniformHandles.fDstCopySamplerUni = | |
| 268 fProgram->addUniform(GrGLProgramBuilder::kFragment_Visibility, | |
| 269 kSampler2D_GrSLType, | |
| 270 "DstCopySampler", | |
| 271 &dstCopySamplerName); | |
| 272 fProgram->fUniformHandles.fDstCopyTopLeftUni = | |
| 273 fProgram->addUniform(GrGLProgramBuilder::kFragment_Visibility, | |
| 274 kVec2f_GrSLType, | |
| 275 "DstCopyUpperLeft", | |
| 276 &dstCopyTopLeftName); | |
| 277 fProgram->fUniformHandles.fDstCopyScaleUni = | |
| 278 fProgram->addUniform(GrGLProgramBuilder::kFragment_Visibility, | |
| 279 kVec2f_GrSLType, | |
| 280 "DstCopyCoordScale", | |
| 281 &dstCopyCoordScaleName); | |
| 282 const char* fragPos = fragmentPosition(); | |
| 283 | |
| 284 this->codeAppend("// Read color from copy of the destination.\n"); | |
| 285 this->codeAppendf("vec2 _dstTexCoord = (%s.xy - %s) * %s;", | |
| 286 fragPos, dstCopyTopLeftName, dstCopyCoordScaleName); | |
| 287 if (!topDown) { | |
| 288 this->codeAppend("_dstTexCoord.y = 1.0 - _dstTexCoord.y;"); | |
| 289 } | |
| 290 this->codeAppendf("vec4 %s = ", kDstCopyColorName); | |
| 291 this->appendTextureLookup(dstCopySamplerName, | |
| 292 "_dstTexCoord", | |
| 293 configMask, | |
| 294 "rgba"); | |
| 295 this->codeAppend(";"); | |
| 296 } | |
| 297 | |
| 298 if (k110_GrGLSLGeneration != gpu->glslGeneration()) { | |
| 299 fOutputs.push_back().set(kVec4f_GrSLType, | |
| 300 GrGLShaderVar::kOut_TypeModifier, | |
| 301 declared_color_output_name()); | |
| 302 fHasCustomColorOutput = true; | |
| 303 } | |
| 304 } | |
| 305 | |
| 306 void GrGLFragmentShaderBuilder::emitCodeAfterEffects(const GrGLSLExpr4& inputCol or, const GrGLSLExpr4& inputCoverage) { | |
| 307 const GrGLProgramDesc::KeyHeader& header = fProgram->desc().getHeader(); | |
| 308 | |
| 309 /////////////////////////////////////////////////////////////////////////// | |
| 310 // write the secondary color output if necessary | |
| 311 if (GrGLProgramDesc::CoverageOutputUsesSecondaryOutput(header.fCoverageOutpu t)) { | |
| 312 const char* secondaryOutputName = this->enableSecondaryOutput(); | |
| 313 | |
| 314 // default coeff to ones for kCoverage_DualSrcOutput | |
| 315 GrGLSLExpr4 coeff(1); | |
| 316 if (GrGLProgramDesc::kSecondaryCoverageISA_CoverageOutput == header.fCov erageOutput) { | |
| 317 // Get (1-A) into coeff | |
| 318 coeff = GrGLSLExpr4::VectorCast(GrGLSLExpr1(1) - inputColor.a()); | |
| 319 } else if (GrGLProgramDesc::kSecondaryCoverageISC_CoverageOutput == | |
| 320 header.fCoverageOutput){ | |
| 321 // Get (1-RGBA) into coeff | |
| 322 coeff = GrGLSLExpr4(1) - inputColor; | |
| 323 } | |
| 324 // Get coeff * coverage into modulate and then write that to the dual so urce output. | |
| 325 codeAppendf("\t%s = %s;\n", secondaryOutputName, (coeff * inputCoverage) .c_str()); | |
| 326 } | |
| 327 | |
| 328 /////////////////////////////////////////////////////////////////////////// | |
| 329 // combine color and coverage as frag color | |
| 330 | |
| 331 // Get "color * coverage" into fragColor | |
| 332 GrGLSLExpr4 fragColor = inputColor * inputCoverage; | |
| 333 // Now tack on "+(1-coverage)dst onto the frag color if we were asked to do so. | |
| 334 if (GrGLProgramDesc::kCombineWithDst_CoverageOutput == header.fCoverageOutpu t) { | |
| 335 GrGLSLExpr4 dstCoeff = GrGLSLExpr4(1) - inputCoverage; | |
| 336 | |
| 337 GrGLSLExpr4 dstContribution = dstCoeff * GrGLSLExpr4(dstColor()); | |
| 338 | |
| 339 fragColor = fragColor + dstContribution; | |
| 340 } | |
| 341 codeAppendf("\t%s = %s;\n", this->getColorOutputName(), fragColor.c_str()); | |
| 342 } | |
| 343 | |
| 344 const char* GrGLFragmentShaderBuilder::enableSecondaryOutput() { | |
| 345 if (!fHasSecondaryOutput) { | |
| 346 fOutputs.push_back().set(kVec4f_GrSLType, | |
| 347 GrGLShaderVar::kOut_TypeModifier, | |
| 348 dual_source_output_name()); | |
| 349 fHasSecondaryOutput = true; | |
| 350 } | |
| 351 return dual_source_output_name(); | |
| 352 } | |
| 353 | |
| 354 const char* GrGLFragmentShaderBuilder::getColorOutputName() const { | |
| 355 return fHasCustomColorOutput ? declared_color_output_name() : "gl_FragColor" ; | |
| 356 } | |
| 357 | |
| OLD | NEW |