| 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 namespace { | 13 #define GL_CALL(X) GR_GL_CALL(fProgramBuilder->gpu()->glInterface(), X) |
| 14 #define GL_CALL(X) GR_GL_CALL(gpu->glInterface(), X) | 14 #define GL_CALL_RET(R, X) GR_GL_CALL_RET(fProgramBuilder->gpu()->glInterface(),
R, X) |
| 15 #define GL_CALL_RET(R, X) GR_GL_CALL_RET(gpu->glInterface(), R, X) | 15 |
| 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 static const char kDstCopyColorName[] = "_dstColor"; | 18 const char* GrGLFragmentShaderBuilder::kDstCopyColorName = "_dstColor"; |
| 19 inline const char* declared_color_output_name() { return "fsColorOut"; } | 19 static const char* declared_color_output_name() { return "fsColorOut"; } |
| 20 inline const char* dual_source_output_name() { return "dualSourceOut"; } | 20 static const char* dual_source_output_name() { return "dualSourceOut"; } |
| 21 inline void append_default_precision_qualifier(GrGLShaderVar::Precision p, | 21 static 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 } | |
| 44 | 43 |
| 45 GrGLFragmentShaderBuilder::DstReadKey GrGLFragmentShaderBuilder::KeyForDstRead( | 44 GrGLFragmentShaderBuilder::DstReadKey |
| 46 const GrTexture* dstCopy, const GrGLCaps& caps) { | 45 GrGLFragmentShaderBuilder::KeyForDstRead(const GrTexture* dstCopy, |
| 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 GrGLFragmentShaderBuilder::KeyForFragmentP
osition( | 63 GrGLFragmentShaderBuilder::FragPosKey |
| 64 const GrRenderTarget* dst, const GrGLCaps&) { | 64 GrGLFragmentShaderBuilder::KeyForFragmentPosition(const GrRenderTarget* dst, |
| 65 const
GrGLCaps&) { |
| 65 if (kTopLeft_GrSurfaceOrigin == dst->origin()) { | 66 if (kTopLeft_GrSurfaceOrigin == dst->origin()) { |
| 66 return kTopLeftFragPosRead_FragPosKey; | 67 return kTopLeftFragPosRead_FragPosKey; |
| 67 } else { | 68 } else { |
| 68 return kBottomLeftFragPosRead_FragPosKey; | 69 return kBottomLeftFragPosRead_FragPosKey; |
| 69 } | 70 } |
| 70 } | 71 } |
| 71 | 72 |
| 72 GrGLFragmentShaderBuilder::GrGLFragmentShaderBuilder(GrGLProgramBuilder* program
, | 73 GrGLFragmentShaderBuilder::GrGLFragmentShaderBuilder(GrGLProgramBuilder* program
, |
| 73 const GrGLProgramDesc& desc
) | 74 const GrGLProgramDesc& desc
) |
| 74 : INHERITED(program) | 75 : INHERITED(program) |
| 75 , fHasCustomColorOutput(false) | 76 , fHasCustomColorOutput(false) |
| 76 , fHasSecondaryOutput(false) | 77 , fHasSecondaryOutput(false) |
| 77 , fSetupFragPosition(false) | 78 , fSetupFragPosition(false) |
| 78 , fTopLeftFragPosRead(kTopLeftFragPosRead_FragPosKey == desc.getHeader().fFr
agPosKey){ | 79 , fTopLeftFragPosRead(kTopLeftFragPosRead_FragPosKey == desc.getHeader().fFr
agPosKey) |
| 79 } | 80 , fHasReadDstColor(false) |
| 80 | 81 , fHasReadFragmentPosition(false) { |
| 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 } | |
| 105 } | 82 } |
| 106 | 83 |
| 107 bool GrGLFragmentShaderBuilder::enableFeature(GLSLFeature feature) { | 84 bool GrGLFragmentShaderBuilder::enableFeature(GLSLFeature feature) { |
| 108 switch (feature) { | 85 switch (feature) { |
| 109 case kStandardDerivatives_GLSLFeature: { | 86 case kStandardDerivatives_GLSLFeature: { |
| 110 GrGpuGL* gpu = fProgramBuilder->gpu(); | 87 GrGpuGL* gpu = fProgramBuilder->gpu(); |
| 111 if (!gpu->glCaps().shaderDerivativeSupport()) { | 88 if (!gpu->glCaps().shaderDerivativeSupport()) { |
| 112 return false; | 89 return false; |
| 113 } | 90 } |
| 114 if (kGLES_GrGLStandard == gpu->glStandard()) { | 91 if (kGLES_GrGLStandard == gpu->glStandard()) { |
| (...skipping 18 matching lines...) Expand all Loading... |
| 133 SkString coords2D("coords2D"); | 110 SkString coords2D("coords2D"); |
| 134 if (0 != index) { | 111 if (0 != index) { |
| 135 coords2D.appendf("_%i", index); | 112 coords2D.appendf("_%i", index); |
| 136 } | 113 } |
| 137 this->codeAppendf("\tvec2 %s = %s.xy / %s.z;", | 114 this->codeAppendf("\tvec2 %s = %s.xy / %s.z;", |
| 138 coords2D.c_str(), coords[index].c_str(), coords[index].c_s
tr()); | 115 coords2D.c_str(), coords[index].c_str(), coords[index].c_s
tr()); |
| 139 return coords2D; | 116 return coords2D; |
| 140 } | 117 } |
| 141 | 118 |
| 142 const char* GrGLFragmentShaderBuilder::fragmentPosition() { | 119 const char* GrGLFragmentShaderBuilder::fragmentPosition() { |
| 143 GrGLProgramBuilder::CodeStage* cs = &fProgramBuilder->fCodeStage; | 120 fHasReadFragmentPosition = true; |
| 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 } | |
| 152 | 121 |
| 153 GrGpuGL* gpu = fProgramBuilder->gpu(); | 122 GrGpuGL* gpu = fProgramBuilder->gpu(); |
| 154 // We only declare "gl_FragCoord" when we're in the case where we want to us
e layout qualifiers | 123 // 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 | 124 // 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. | 125 // declaration varies in earlier GLSL specs. So it is simpler to omit it. |
| 157 if (fTopLeftFragPosRead) { | 126 if (fTopLeftFragPosRead) { |
| 158 fSetupFragPosition = true; | 127 fSetupFragPosition = true; |
| 159 return "gl_FragCoord"; | 128 return "gl_FragCoord"; |
| 160 } else if (gpu->glCaps().fragCoordConventionsSupport()) { | 129 } else if (gpu->glCaps().fragCoordConventionsSupport()) { |
| 161 if (!fSetupFragPosition) { | 130 if (!fSetupFragPosition) { |
| 162 if (gpu->glslGeneration() < k150_GrGLSLGeneration) { | 131 if (gpu->glslGeneration() < k150_GrGLSLGeneration) { |
| 163 this->addFeature(1 << kFragCoordConventions_GLSLPrivateFeature, | 132 this->addFeature(1 << kFragCoordConventions_GLSLPrivateFeature, |
| 164 "GL_ARB_fragment_coord_conventions"); | 133 "GL_ARB_fragment_coord_conventions"); |
| 165 } | 134 } |
| 166 fInputs.push_back().set(kVec4f_GrSLType, | 135 fInputs.push_back().set(kVec4f_GrSLType, |
| 167 GrGLShaderVar::kIn_TypeModifier, | 136 GrGLShaderVar::kIn_TypeModifier, |
| 168 "gl_FragCoord", | 137 "gl_FragCoord", |
| 169 GrGLShaderVar::kDefault_Precision, | 138 GrGLShaderVar::kDefault_Precision, |
| 170 GrGLShaderVar::kUpperLeft_Origin); | 139 GrGLShaderVar::kUpperLeft_Origin); |
| 171 fSetupFragPosition = true; | 140 fSetupFragPosition = true; |
| 172 } | 141 } |
| 173 return "gl_FragCoord"; | 142 return "gl_FragCoord"; |
| 174 } else { | 143 } else { |
| 175 static const char* kCoordName = "fragCoordYDown"; | 144 static const char* kCoordName = "fragCoordYDown"; |
| 176 if (!fSetupFragPosition) { | 145 if (!fSetupFragPosition) { |
| 177 // temporarily change the stage index because we're inserting non-st
age code. | 146 // temporarily change the stage index because we're inserting non-st
age code. |
| 178 GrGLProgramBuilder::CodeStage::AutoStageRestore csar(cs, NULL); | 147 GrGLProgramBuilder::AutoStageRestore asr(fProgramBuilder); |
| 179 | |
| 180 SkASSERT(!fProgramBuilder->fUniformHandles.fRTHeightUni.isValid()); | 148 SkASSERT(!fProgramBuilder->fUniformHandles.fRTHeightUni.isValid()); |
| 181 const char* rtHeightName; | 149 const char* rtHeightName; |
| 182 | 150 |
| 183 fProgramBuilder->fUniformHandles.fRTHeightUni = | 151 fProgramBuilder->fUniformHandles.fRTHeightUni = |
| 184 fProgramBuilder->addUniform(GrGLProgramBuilder::kFragment_Vi
sibility, | 152 fProgramBuilder->addUniform(GrGLProgramBuilder::kFragment_Vi
sibility, |
| 185 kFloat_GrSLType, | 153 kFloat_GrSLType, |
| 186 "RTHeight", | 154 "RTHeight", |
| 187 &rtHeightName); | 155 &rtHeightName); |
| 188 | 156 |
| 189 // Using glFragCoord.zw for the last two components tickles an Adren
o driver bug that | 157 // 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 | 158 // 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. | 159 // 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, " | 160 this->codePrependf("\tvec4 %s = vec4(gl_FragCoord.x, %s - gl_FragCoo
rd.y, 1.0, " |
| 193 "1.0);\n", kCoordName, rtHeightName); | 161 "1.0);\n", kCoordName, rtHeightName); |
| 194 fSetupFragPosition = true; | 162 fSetupFragPosition = true; |
| 195 } | 163 } |
| 196 SkASSERT(fProgramBuilder->fUniformHandles.fRTHeightUni.isValid()); | 164 SkASSERT(fProgramBuilder->fUniformHandles.fRTHeightUni.isValid()); |
| 197 return kCoordName; | 165 return kCoordName; |
| 198 } | 166 } |
| 199 } | 167 } |
| 200 | 168 |
| 201 void GrGLFragmentShaderBuilder::addVarying(GrSLType type, | 169 const char* GrGLFragmentShaderBuilder::dstColor() { |
| 202 const char* name, | 170 fHasReadDstColor = true; |
| 203 const char** fsInName, | 171 |
| 204 GrGLShaderVar::Precision fsPrecision) { | 172 GrGpuGL* gpu = fProgramBuilder->gpu(); |
| 205 fInputs.push_back().set(type, GrGLShaderVar::kVaryingIn_TypeModifier, name,
fsPrecision); | 173 if (gpu->glCaps().fbFetchSupport()) { |
| 206 if (fsInName) { | 174 this->addFeature(1 << (GrGLFragmentShaderBuilder::kLastGLSLPrivateFeatur
e + 1), |
| 207 *fsInName = name; | 175 gpu->glCaps().fbFetchExtensionString()); |
| 176 return gpu->glCaps().fbFetchColorName(); |
| 177 } else if (fProgramBuilder->fUniformHandles.fDstCopySamplerUni.isValid()) { |
| 178 return kDstCopyColorName; |
| 179 } else { |
| 180 return ""; |
| 208 } | 181 } |
| 209 } | 182 } |
| 210 | 183 |
| 211 void GrGLFragmentShaderBuilder::bindProgramLocations(GrGLuint programId) { | 184 void GrGLFragmentShaderBuilder::emitCodeToReadDstTexture() { |
| 212 GrGpuGL* gpu = fProgramBuilder->gpu(); | 185 bool topDown = SkToBool(kTopLeftOrigin_DstReadKeyBit & fProgramBuilder->head
er().fDstReadKey); |
| 213 if (fHasCustomColorOutput) { | 186 const char* dstCopyTopLeftName; |
| 214 GL_CALL(BindFragDataLocation(programId, 0, declared_color_output_name())
); | 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; |
| 215 } | 194 } |
| 216 if (fHasSecondaryOutput) { | 195 fProgramBuilder->fUniformHandles.fDstCopySamplerUni = |
| 217 GL_CALL(BindFragDataLocationIndexed(programId, 0, 1, dual_source_output_
name())); | 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;"); |
| 218 } | 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()); |
| 219 } | 296 } |
| 220 | 297 |
| 221 bool GrGLFragmentShaderBuilder::compileAndAttachShaders(GrGLuint programId, | 298 bool GrGLFragmentShaderBuilder::compileAndAttachShaders(GrGLuint programId, |
| 222 SkTDArray<GrGLuint>* sha
derIds) const { | 299 SkTDArray<GrGLuint>* sha
derIds) const { |
| 223 GrGpuGL* gpu = fProgramBuilder->gpu(); | 300 GrGpuGL* gpu = fProgramBuilder->gpu(); |
| 224 SkString fragShaderSrc(GrGetGLSLVersionDecl(gpu->ctxInfo())); | 301 SkString fragShaderSrc(GrGetGLSLVersionDecl(gpu->ctxInfo())); |
| 225 fragShaderSrc.append(fExtensions); | 302 fragShaderSrc.append(fExtensions); |
| 226 append_default_precision_qualifier(kDefaultFragmentPrecision, | 303 append_default_precision_qualifier(kDefaultFragmentPrecision, |
| 227 gpu->glStandard(), | 304 gpu->glStandard(), |
| 228 &fragShaderSrc); | 305 &fragShaderSrc); |
| 229 fProgramBuilder->appendUniformDecls(GrGLProgramBuilder::kFragment_Visibility
, &fragShaderSrc); | 306 fProgramBuilder->appendUniformDecls(GrGLProgramBuilder::kFragment_Visibility
, &fragShaderSrc); |
| 230 fProgramBuilder->appendDecls(fInputs, &fragShaderSrc); | 307 this->appendDecls(fInputs, &fragShaderSrc); |
| 231 // We shouldn't have declared outputs on 1.10 | 308 // We shouldn't have declared outputs on 1.10 |
| 232 SkASSERT(k110_GrGLSLGeneration != gpu->glslGeneration() || fOutputs.empty())
; | 309 SkASSERT(k110_GrGLSLGeneration != gpu->glslGeneration() || fOutputs.empty())
; |
| 233 fProgramBuilder->appendDecls(fOutputs, &fragShaderSrc); | 310 this->appendDecls(fOutputs, &fragShaderSrc); |
| 234 fragShaderSrc.append(fFunctions); | 311 fragShaderSrc.append(fFunctions); |
| 235 fragShaderSrc.append("void main() {\n"); | 312 fragShaderSrc.append("void main() {\n"); |
| 236 fragShaderSrc.append(fCode); | 313 fragShaderSrc.append(fCode); |
| 237 fragShaderSrc.append("}\n"); | 314 fragShaderSrc.append("}\n"); |
| 238 | 315 |
| 239 GrGLuint fragShaderId = GrGLCompileAndAttachShader(gpu->glContext(), program
Id, | 316 GrGLuint fragShaderId = GrGLCompileAndAttachShader(gpu->glContext(), program
Id, |
| 240 GR_GL_FRAGMENT_SHADER, fr
agShaderSrc, | 317 GR_GL_FRAGMENT_SHADER, fr
agShaderSrc, |
| 241 gpu->gpuStats()); | 318 gpu->gpuStats()); |
| 242 if (!fragShaderId) { | 319 if (!fragShaderId) { |
| 243 return false; | 320 return false; |
| 244 } | 321 } |
| 245 | 322 |
| 246 *shaderIds->append() = fragShaderId; | 323 *shaderIds->append() = fragShaderId; |
| 247 | 324 |
| 248 return true; | 325 return true; |
| 249 } | 326 } |
| 250 | 327 |
| 251 void GrGLFragmentShaderBuilder::emitCodeBeforeEffects() { | 328 void GrGLFragmentShaderBuilder::bindFragmentShaderLocations(GrGLuint programID)
{ |
| 252 const GrGLProgramDesc::KeyHeader& header = fProgramBuilder->desc().getHeader
(); | 329 if (fHasCustomColorOutput) { |
| 253 GrGpuGL* gpu = fProgramBuilder->gpu(); | 330 GL_CALL(BindFragDataLocation(programID, 0, declared_color_output_name())
); |
| 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 } | 331 } |
| 298 | 332 if (fHasSecondaryOutput) { |
| 299 if (k110_GrGLSLGeneration != gpu->glslGeneration()) { | 333 GL_CALL(BindFragDataLocationIndexed(programID, 0, 1, dual_source_output_
name())); |
| 300 fOutputs.push_back().set(kVec4f_GrSLType, | |
| 301 GrGLShaderVar::kOut_TypeModifier, | |
| 302 declared_color_output_name()); | |
| 303 fHasCustomColorOutput = true; | |
| 304 } | 334 } |
| 305 } | 335 } |
| 306 | 336 |
| 307 void GrGLFragmentShaderBuilder::emitCodeAfterEffects(const GrGLSLExpr4& inputCol
or, const GrGLSLExpr4& inputCoverage) { | 337 void GrGLFragmentShaderBuilder::addVarying(GrSLType type, |
| 308 const GrGLProgramDesc::KeyHeader& header = fProgramBuilder->desc().getHeader
(); | 338 const char* name, |
| 309 | 339 const char** fsInName, |
| 310 /////////////////////////////////////////////////////////////////////////// | 340 GrGLShaderVar::Precision fsPrecision) { |
| 311 // write the secondary color output if necessary | 341 fInputs.push_back().set(type, GrGLShaderVar::kVaryingIn_TypeModifier, name,
fsPrecision); |
| 312 if (GrOptDrawState::kNone_SecondaryOutputType != header.fSecondaryOutputType
) { | 342 if (fsInName) { |
| 313 const char* secondaryOutputName = this->enableSecondaryOutput(); | 343 *fsInName = name; |
| 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 } | 344 } |
| 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 } | 345 } |
| 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 |