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