| 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 ////////////////////////////////////////////////////////////////////////////////
//////////////////// |
| 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 == |
| 84 desc.getHeader().fFragPosKey){ |
| 85 } |
| 86 |
| 87 const char* GrGLFragmentShaderBuilder::dstColor() { |
| 88 if (fProgram->fCodeStage.inStageCode()) { |
| 89 const GrEffect* effect = fProgram->fCodeStage.effectStage()->getEffect()
; |
| 90 if (!effect->willReadDstColor()) { |
| 91 SkDEBUGFAIL("GrGLEffect asked for dst color but its generating GrEff
ect " |
| 92 "did not request access."); |
| 93 return ""; |
| 94 } |
| 95 } |
| 96 |
| 97 GrGpuGL* gpu = fProgram->gpu(); |
| 98 if (gpu->glCaps().fbFetchSupport()) { |
| 99 this->addFeature(1 << (GrGLFragmentShaderBuilder::kLastGLSLPrivateFeatur
e + 1), |
| 100 gpu->glCaps().fbFetchExtensionString()); |
| 101 return gpu->glCaps().fbFetchColorName(); |
| 102 } else if (fProgram->fUniformHandles.fDstCopySamplerUni.isValid()) { |
| 103 return kDstCopyColorName; |
| 104 } else { |
| 105 return ""; |
| 106 } |
| 107 } |
| 108 |
| 109 bool GrGLFragmentShaderBuilder::enableFeature(GLSLFeature feature) { |
| 110 switch (feature) { |
| 111 case kStandardDerivatives_GLSLFeature: { |
| 112 GrGpuGL* gpu = fProgram->gpu(); |
| 113 if (!gpu->glCaps().shaderDerivativeSupport()) { |
| 114 return false; |
| 115 } |
| 116 if (kGLES_GrGLStandard == gpu->glStandard()) { |
| 117 this->addFeature(1 << kStandardDerivatives_GLSLFeature, |
| 118 "GL_OES_standard_derivatives"); |
| 119 } |
| 120 return true; |
| 121 } |
| 122 default: |
| 123 SkFAIL("Unexpected GLSLFeature requested."); |
| 124 return false; |
| 125 } |
| 126 } |
| 127 |
| 128 SkString GrGLFragmentShaderBuilder::ensureFSCoords2D(const TransformedCoordsArra
y& coords, int index) { |
| 129 if (kVec3f_GrSLType != coords[index].type()) { |
| 130 SkASSERT(kVec2f_GrSLType == coords[index].type()); |
| 131 return coords[index].getName(); |
| 132 } |
| 133 |
| 134 SkString coords2D("coords2D"); |
| 135 if (0 != index) { |
| 136 coords2D.appendf("_%i", index); |
| 137 } |
| 138 this->codeAppendf("\tvec2 %s = %s.xy / %s.z;", |
| 139 coords2D.c_str(), coords[index].c_str(), coords[index].c_s
tr()); |
| 140 return coords2D; |
| 141 } |
| 142 |
| 143 const char* GrGLFragmentShaderBuilder::fragmentPosition() { |
| 144 GrGLProgramBuilder::CodeStage* cs = &fProgram->fCodeStage; |
| 145 if (cs->inStageCode()) { |
| 146 const GrEffect* effect = cs->effectStage()->getEffect(); |
| 147 if (!effect->willReadFragmentPosition()) { |
| 148 SkDEBUGFAIL("GrGLEffect asked for frag position but its generating G
rEffect " |
| 149 "did not request access."); |
| 150 return ""; |
| 151 } |
| 152 } |
| 153 |
| 154 GrGpuGL* gpu = fProgram->gpu(); |
| 155 // We only declare "gl_FragCoord" when we're in the case where we want to us
e layout qualifiers |
| 156 // to reverse y. Otherwise it isn't necessary and whether the "in" qualifier
appears in the |
| 157 // declaration varies in earlier GLSL specs. So it is simpler to omit it. |
| 158 if (fTopLeftFragPosRead) { |
| 159 fSetupFragPosition = true; |
| 160 return "gl_FragCoord"; |
| 161 } else if (gpu->glCaps().fragCoordConventionsSupport()) { |
| 162 if (!fSetupFragPosition) { |
| 163 if (gpu->glslGeneration() < k150_GrGLSLGeneration) { |
| 164 this->addFeature(1 << kFragCoordConventions_GLSLPrivateFeature, |
| 165 "GL_ARB_fragment_coord_conventions"); |
| 166 } |
| 167 GrGLShaderVar t = GrGLShaderVar(); |
| 168 t.set(kVec4f_GrSLType, |
| 169 GrGLShaderVar::kIn_TypeModifier, |
| 170 "gl_FragCoord", |
| 171 GrGLShaderVar::kDefault_Precision, |
| 172 GrGLShaderVar::kUpperLeft_Origin); |
| 173 this->addInput(t); |
| 174 fSetupFragPosition = true; |
| 175 } |
| 176 return "gl_FragCoord"; |
| 177 } else { |
| 178 static const char* kCoordName = "fragCoordYDown"; |
| 179 if (!fSetupFragPosition) { |
| 180 // temporarily change the stage index because we're inserting non-st
age code. |
| 181 GrGLProgramBuilder::CodeStage::AutoStageRestore csar(cs, NULL); |
| 182 |
| 183 SkASSERT(!fProgram->fUniformHandles.fRTHeightUni.isValid()); |
| 184 const char* rtHeightName; |
| 185 |
| 186 fProgram->fUniformHandles.fRTHeightUni = |
| 187 fProgram->addUniform(GrGLProgramBuilder::kFragment_Visibility, k
Float_GrSLType, |
| 188 "RTHeight", &rtHeightName); |
| 189 |
| 190 // Using glFragCoord.zw for the last two components tickles an Adren
o driver bug that |
| 191 // causes programs to fail to link. Making this function return a ve
c2() didn't fix the |
| 192 // problem but using 1.0 for the last two components does. |
| 193 this->codePrependf("\tvec4 %s = vec4(gl_FragCoord.x, %s - gl_FragCoo
rd.y, 1.0, " |
| 194 "1.0);\n", kCoordName, rtHeightName); |
| 195 fSetupFragPosition = true; |
| 196 } |
| 197 SkASSERT(fProgram->fUniformHandles.fRTHeightUni.isValid()); |
| 198 return kCoordName; |
| 199 } |
| 200 } |
| 201 |
| 202 // GrGLFragmentShaderBuilder private ///////////////////////////////////////////
/////////////////// |
| 203 void GrGLFragmentShaderBuilder::addVarying(GrSLType type, |
| 204 const char* name, |
| 205 const char** fsInName) { |
| 206 fInputs.push_back().set(type, GrGLShaderVar::kVaryingIn_TypeModifier, name); |
| 207 if (fsInName) { |
| 208 *fsInName = name; |
| 209 } |
| 210 } |
| 211 |
| 212 void GrGLFragmentShaderBuilder::bindProgramLocations(GrGLuint programId) { |
| 213 GrGpuGL* gpu = fProgram->gpu(); |
| 214 if (fHasCustomColorOutput) { |
| 215 GL_CALL(BindFragDataLocation(programId, 0, declared_color_output_name())
); |
| 216 } |
| 217 if (fHasSecondaryOutput) { |
| 218 GL_CALL(BindFragDataLocationIndexed(programId, 0, 1, dual_source_output_
name())); |
| 219 } |
| 220 } |
| 221 |
| 222 bool GrGLFragmentShaderBuilder::compileAndAttachShaders(GrGLuint programId, SkTD
Array<GrGLuint>* shaderIds) 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 = GrGLShaderStringBuilder::attachShader(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 // emit code to read the dst copy texture, if necessary |
| 255 if (kNoDstRead_DstReadKey != header.fDstReadKey && !gpu->glCaps().fbFetchSup
port()) { |
| 256 bool topDown = SkToBool(kTopLeftOrigin_DstReadKeyBit & header.fDstReadKe
y); |
| 257 const char* dstCopyTopLeftName; |
| 258 const char* dstCopyCoordScaleName; |
| 259 const char* dstCopySamplerName; |
| 260 uint32_t configMask; |
| 261 if (SkToBool(kUseAlphaConfig_DstReadKeyBit & header.fDstReadKey)) { |
| 262 configMask = kA_GrColorComponentFlag; |
| 263 } else { |
| 264 configMask = kRGBA_GrColorComponentFlags; |
| 265 } |
| 266 fProgram->fUniformHandles.fDstCopySamplerUni = |
| 267 fProgram->addUniform(GrGLProgramBuilder::kFragment_Visibility, kSamp
ler2D_GrSLType, "DstCopySampler", |
| 268 &dstCopySamplerName); |
| 269 fProgram->fUniformHandles.fDstCopyTopLeftUni = |
| 270 fProgram->addUniform(GrGLProgramBuilder::kFragment_Visibility, kVec2
f_GrSLType, "DstCopyUpperLeft", |
| 271 &dstCopyTopLeftName); |
| 272 fProgram->fUniformHandles.fDstCopyScaleUni = |
| 273 fProgram->addUniform(GrGLProgramBuilder::kFragment_Visibility, kVec2
f_GrSLType, "DstCopyCoordScale", |
| 274 &dstCopyCoordScaleName); |
| 275 const char* fragPos = fragmentPosition(); |
| 276 |
| 277 this->codeAppend("// Read color from copy of the destination.\n"); |
| 278 this->codeAppendf("vec2 _dstTexCoord = (%s.xy - %s) * %s;", |
| 279 fragPos, dstCopyTopLeftName, dstCopyCoordScaleName); |
| 280 if (!topDown) { |
| 281 this->codeAppend("_dstTexCoord.y = 1.0 - _dstTexCoord.y;"); |
| 282 } |
| 283 this->codeAppendf("vec4 %s = ", kDstCopyColorName); |
| 284 this->appendTextureLookup(dstCopySamplerName, |
| 285 "_dstTexCoord", |
| 286 configMask, |
| 287 "rgba"); |
| 288 this->codeAppend(";"); |
| 289 } |
| 290 |
| 291 if (k110_GrGLSLGeneration != gpu->glslGeneration()) { |
| 292 fOutputs.push_back().set(kVec4f_GrSLType, |
| 293 GrGLShaderVar::kOut_TypeModifier, |
| 294 declared_color_output_name()); |
| 295 fHasCustomColorOutput = true; |
| 296 } |
| 297 } |
| 298 |
| 299 void GrGLFragmentShaderBuilder::emitCodeAfterEffects(const GrGLSLExpr4& inputCol
or, const GrGLSLExpr4& inputCoverage) { |
| 300 const GrGLProgramDesc::KeyHeader& header = fProgram->desc().getHeader(); |
| 301 /////////////////////////////////////////////////////////////////////////// |
| 302 // write the secondary color output if necessary |
| 303 if (GrGLProgramDesc::CoverageOutputUsesSecondaryOutput(header.fCoverageOutpu
t)) { |
| 304 const char* secondaryOutputName = this->enableSecondaryOutput(); |
| 305 |
| 306 // default coeff to ones for kCoverage_DualSrcOutput |
| 307 GrGLSLExpr4 coeff(1); |
| 308 if (GrGLProgramDesc::kSecondaryCoverageISA_CoverageOutput == header.fCov
erageOutput) { |
| 309 // Get (1-A) into coeff |
| 310 coeff = GrGLSLExpr4::VectorCast(GrGLSLExpr1(1) - inputColor.a()); |
| 311 } else if (GrGLProgramDesc::kSecondaryCoverageISC_CoverageOutput == |
| 312 header.fCoverageOutput){ |
| 313 // Get (1-RGBA) into coeff |
| 314 coeff = GrGLSLExpr4(1) - inputColor; |
| 315 } |
| 316 // Get coeff * coverage into modulate and then write that to the dual so
urce output. |
| 317 codeAppendf("\t%s = %s;\n", secondaryOutputName, (coeff * inputCoverage)
.c_str()); |
| 318 } |
| 319 |
| 320 /////////////////////////////////////////////////////////////////////////// |
| 321 // combine color and coverage as frag color |
| 322 |
| 323 // Get "color * coverage" into fragColor |
| 324 GrGLSLExpr4 fragColor = inputColor * inputCoverage; |
| 325 // Now tack on "+(1-coverage)dst onto the frag color if we were asked to do
so. |
| 326 if (GrGLProgramDesc::kCombineWithDst_CoverageOutput == header.fCoverageOutpu
t) { |
| 327 GrGLSLExpr4 dstCoeff = GrGLSLExpr4(1) - inputCoverage; |
| 328 |
| 329 GrGLSLExpr4 dstContribution = dstCoeff * GrGLSLExpr4(dstColor()); |
| 330 |
| 331 fragColor = fragColor + dstContribution; |
| 332 } |
| 333 codeAppendf("\t%s = %s;\n", this->getColorOutputName(), fragColor.c_str()); |
| 334 } |
| 335 |
| 336 const char* GrGLFragmentShaderBuilder::enableSecondaryOutput() { |
| 337 if (!fHasSecondaryOutput) { |
| 338 fOutputs.push_back().set(kVec4f_GrSLType, |
| 339 GrGLShaderVar::kOut_TypeModifier, |
| 340 dual_source_output_name()); |
| 341 fHasSecondaryOutput = true; |
| 342 } |
| 343 return dual_source_output_name(); |
| 344 } |
| 345 |
| 346 const char* GrGLFragmentShaderBuilder::getColorOutputName() const { |
| 347 return fHasCustomColorOutput ? declared_color_output_name() : "gl_FragColor"
; |
| 348 } |
| 349 |
| OLD | NEW |