| 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 "GrRenderTarget.h" | |
| 10 #include "glsl/GrGLSL.h" | |
| 11 #include "glsl/GrGLSLCaps.h" | |
| 12 #include "glsl/GrGLSLProgramBuilder.h" | |
| 13 | |
| 14 const char* GrGLFragmentShaderBuilder::kDstTextureColorName = "_dstColor"; | |
| 15 | |
| 16 static const char* specific_layout_qualifier_name(GrBlendEquation equation) { | |
| 17 SkASSERT(GrBlendEquationIsAdvanced(equation)); | |
| 18 | |
| 19 static const char* kLayoutQualifierNames[] = { | |
| 20 "blend_support_screen", | |
| 21 "blend_support_overlay", | |
| 22 "blend_support_darken", | |
| 23 "blend_support_lighten", | |
| 24 "blend_support_colordodge", | |
| 25 "blend_support_colorburn", | |
| 26 "blend_support_hardlight", | |
| 27 "blend_support_softlight", | |
| 28 "blend_support_difference", | |
| 29 "blend_support_exclusion", | |
| 30 "blend_support_multiply", | |
| 31 "blend_support_hsl_hue", | |
| 32 "blend_support_hsl_saturation", | |
| 33 "blend_support_hsl_color", | |
| 34 "blend_support_hsl_luminosity" | |
| 35 }; | |
| 36 return kLayoutQualifierNames[equation - kFirstAdvancedGrBlendEquation]; | |
| 37 | |
| 38 GR_STATIC_ASSERT(0 == kScreen_GrBlendEquation - kFirstAdvancedGrBlendEquatio
n); | |
| 39 GR_STATIC_ASSERT(1 == kOverlay_GrBlendEquation - kFirstAdvancedGrBlendEquati
on); | |
| 40 GR_STATIC_ASSERT(2 == kDarken_GrBlendEquation - kFirstAdvancedGrBlendEquatio
n); | |
| 41 GR_STATIC_ASSERT(3 == kLighten_GrBlendEquation - kFirstAdvancedGrBlendEquati
on); | |
| 42 GR_STATIC_ASSERT(4 == kColorDodge_GrBlendEquation - kFirstAdvancedGrBlendEqu
ation); | |
| 43 GR_STATIC_ASSERT(5 == kColorBurn_GrBlendEquation - kFirstAdvancedGrBlendEqua
tion); | |
| 44 GR_STATIC_ASSERT(6 == kHardLight_GrBlendEquation - kFirstAdvancedGrBlendEqua
tion); | |
| 45 GR_STATIC_ASSERT(7 == kSoftLight_GrBlendEquation - kFirstAdvancedGrBlendEqua
tion); | |
| 46 GR_STATIC_ASSERT(8 == kDifference_GrBlendEquation - kFirstAdvancedGrBlendEqu
ation); | |
| 47 GR_STATIC_ASSERT(9 == kExclusion_GrBlendEquation - kFirstAdvancedGrBlendEqua
tion); | |
| 48 GR_STATIC_ASSERT(10 == kMultiply_GrBlendEquation - kFirstAdvancedGrBlendEqua
tion); | |
| 49 GR_STATIC_ASSERT(11 == kHSLHue_GrBlendEquation - kFirstAdvancedGrBlendEquati
on); | |
| 50 GR_STATIC_ASSERT(12 == kHSLSaturation_GrBlendEquation - kFirstAdvancedGrBlen
dEquation); | |
| 51 GR_STATIC_ASSERT(13 == kHSLColor_GrBlendEquation - kFirstAdvancedGrBlendEqua
tion); | |
| 52 GR_STATIC_ASSERT(14 == kHSLLuminosity_GrBlendEquation - kFirstAdvancedGrBlen
dEquation); | |
| 53 GR_STATIC_ASSERT(SK_ARRAY_COUNT(kLayoutQualifierNames) == | |
| 54 kGrBlendEquationCnt - kFirstAdvancedGrBlendEquation); | |
| 55 } | |
| 56 | |
| 57 GrGLFragmentShaderBuilder::FragPosKey | |
| 58 GrGLFragmentShaderBuilder::KeyForFragmentPosition(const GrRenderTarget* dst) { | |
| 59 if (kTopLeft_GrSurfaceOrigin == dst->origin()) { | |
| 60 return kTopLeftFragPosRead_FragPosKey; | |
| 61 } else { | |
| 62 return kBottomLeftFragPosRead_FragPosKey; | |
| 63 } | |
| 64 } | |
| 65 | |
| 66 GrGLFragmentShaderBuilder::GrGLFragmentShaderBuilder(GrGLSLProgramBuilder* progr
am, | |
| 67 uint8_t fragPosKey) | |
| 68 : INHERITED(program) | |
| 69 , fSetupFragPosition(false) | |
| 70 , fTopLeftFragPosRead(kTopLeftFragPosRead_FragPosKey == fragPosKey) | |
| 71 , fCustomColorOutputIndex(-1) | |
| 72 , fHasReadDstColor(false) | |
| 73 , fHasReadFragmentPosition(false) { | |
| 74 } | |
| 75 | |
| 76 bool GrGLFragmentShaderBuilder::enableFeature(GLSLFeature feature) { | |
| 77 switch (feature) { | |
| 78 case kStandardDerivatives_GLSLFeature: { | |
| 79 if (!fProgramBuilder->glslCaps()->shaderDerivativeSupport()) { | |
| 80 return false; | |
| 81 } | |
| 82 const char* extension = fProgramBuilder->glslCaps()->shaderDerivativ
eExtensionString(); | |
| 83 if (extension) { | |
| 84 this->addFeature(1 << kStandardDerivatives_GLSLFeature, extensio
n); | |
| 85 } | |
| 86 return true; | |
| 87 } | |
| 88 default: | |
| 89 SkFAIL("Unexpected GLSLFeature requested."); | |
| 90 return false; | |
| 91 } | |
| 92 } | |
| 93 | |
| 94 SkString GrGLFragmentShaderBuilder::ensureFSCoords2D(const GrGLSLTransformedCoor
dsArray& coords, | |
| 95 int index) { | |
| 96 if (kVec3f_GrSLType != coords[index].getType()) { | |
| 97 SkASSERT(kVec2f_GrSLType == coords[index].getType()); | |
| 98 return coords[index].getName(); | |
| 99 } | |
| 100 | |
| 101 SkString coords2D("coords2D"); | |
| 102 if (0 != index) { | |
| 103 coords2D.appendf("_%i", index); | |
| 104 } | |
| 105 this->codeAppendf("\tvec2 %s = %s.xy / %s.z;", | |
| 106 coords2D.c_str(), coords[index].c_str(), coords[index].c_s
tr()); | |
| 107 return coords2D; | |
| 108 } | |
| 109 | |
| 110 const char* GrGLFragmentShaderBuilder::fragmentPosition() { | |
| 111 fHasReadFragmentPosition = true; | |
| 112 | |
| 113 const GrGLSLCaps* glslCaps = fProgramBuilder->glslCaps(); | |
| 114 // We only declare "gl_FragCoord" when we're in the case where we want to us
e layout qualifiers | |
| 115 // to reverse y. Otherwise it isn't necessary and whether the "in" qualifier
appears in the | |
| 116 // declaration varies in earlier GLSL specs. So it is simpler to omit it. | |
| 117 if (fTopLeftFragPosRead) { | |
| 118 fSetupFragPosition = true; | |
| 119 return "gl_FragCoord"; | |
| 120 } else if (const char* extension = glslCaps->fragCoordConventionsExtensionSt
ring()) { | |
| 121 if (!fSetupFragPosition) { | |
| 122 if (glslCaps->generation() < k150_GrGLSLGeneration) { | |
| 123 this->addFeature(1 << kFragCoordConventions_GLSLPrivateFeature, | |
| 124 extension); | |
| 125 } | |
| 126 fInputs.push_back().set(kVec4f_GrSLType, | |
| 127 GrGLSLShaderVar::kIn_TypeModifier, | |
| 128 "gl_FragCoord", | |
| 129 kDefault_GrSLPrecision, | |
| 130 GrGLSLShaderVar::kUpperLeft_Origin); | |
| 131 fSetupFragPosition = true; | |
| 132 } | |
| 133 return "gl_FragCoord"; | |
| 134 } else { | |
| 135 static const char* kTempName = "tmpXYFragCoord"; | |
| 136 static const char* kCoordName = "fragCoordYDown"; | |
| 137 if (!fSetupFragPosition) { | |
| 138 SkASSERT(!fProgramBuilder->fUniformHandles.fRTHeightUni.isValid()); | |
| 139 const char* rtHeightName; | |
| 140 | |
| 141 fProgramBuilder->fUniformHandles.fRTHeightUni = | |
| 142 fProgramBuilder->addFragPosUniform(GrGLSLProgramBuilder::kFr
agment_Visibility, | |
| 143 kFloat_GrSLType, | |
| 144 kDefault_GrSLPrecision, | |
| 145 "RTHeight", | |
| 146 &rtHeightName); | |
| 147 | |
| 148 // The Adreno compiler seems to be very touchy about access to "gl_F
ragCoord". | |
| 149 // Accessing glFragCoord.zw can cause a program to fail to link. Add
itionally, | |
| 150 // depending on the surrounding code, accessing .xy with a uniform i
nvolved can | |
| 151 // do the same thing. Copying gl_FragCoord.xy into a temp vec2 befor
ehand | |
| 152 // (and only accessing .xy) seems to "fix" things. | |
| 153 this->codePrependf("\tvec4 %s = vec4(%s.x, %s - %s.y, 1.0, 1.0);\n", | |
| 154 kCoordName, kTempName, rtHeightName, kTempName); | |
| 155 this->codePrependf("vec2 %s = gl_FragCoord.xy;", kTempName); | |
| 156 fSetupFragPosition = true; | |
| 157 } | |
| 158 SkASSERT(fProgramBuilder->fUniformHandles.fRTHeightUni.isValid()); | |
| 159 return kCoordName; | |
| 160 } | |
| 161 } | |
| 162 | |
| 163 const char* GrGLFragmentShaderBuilder::dstColor() { | |
| 164 fHasReadDstColor = true; | |
| 165 | |
| 166 const GrGLSLCaps* glslCaps = fProgramBuilder->glslCaps(); | |
| 167 if (glslCaps->fbFetchSupport()) { | |
| 168 this->addFeature(1 << (GrGLFragmentShaderBuilder::kLastGLSLPrivateFeatur
e + 1), | |
| 169 glslCaps->fbFetchExtensionString()); | |
| 170 | |
| 171 // Some versions of this extension string require declaring custom color
output on ES 3.0+ | |
| 172 const char* fbFetchColorName = glslCaps->fbFetchColorName(); | |
| 173 if (glslCaps->fbFetchNeedsCustomOutput()) { | |
| 174 this->enableCustomOutput(); | |
| 175 fOutputs[fCustomColorOutputIndex].setTypeModifier(GrShaderVar::kInOu
t_TypeModifier); | |
| 176 fbFetchColorName = DeclaredColorOutputName(); | |
| 177 } | |
| 178 return fbFetchColorName; | |
| 179 } else { | |
| 180 return kDstTextureColorName; | |
| 181 } | |
| 182 } | |
| 183 | |
| 184 void GrGLFragmentShaderBuilder::enableAdvancedBlendEquationIfNeeded(GrBlendEquat
ion equation) { | |
| 185 SkASSERT(GrBlendEquationIsAdvanced(equation)); | |
| 186 | |
| 187 const GrGLSLCaps& caps = *fProgramBuilder->glslCaps(); | |
| 188 if (!caps.mustEnableAdvBlendEqs()) { | |
| 189 return; | |
| 190 } | |
| 191 | |
| 192 this->addFeature(1 << kBlendEquationAdvanced_GLSLPrivateFeature, | |
| 193 "GL_KHR_blend_equation_advanced"); | |
| 194 if (caps.mustEnableSpecificAdvBlendEqs()) { | |
| 195 this->addLayoutQualifier(specific_layout_qualifier_name(equation), kOut_
InterfaceQualifier); | |
| 196 } else { | |
| 197 this->addLayoutQualifier("blend_support_all_equations", kOut_InterfaceQu
alifier); | |
| 198 } | |
| 199 } | |
| 200 | |
| 201 void GrGLFragmentShaderBuilder::enableCustomOutput() { | |
| 202 if (!fHasCustomColorOutput) { | |
| 203 fHasCustomColorOutput = true; | |
| 204 fCustomColorOutputIndex = fOutputs.count(); | |
| 205 fOutputs.push_back().set(kVec4f_GrSLType, | |
| 206 GrGLSLShaderVar::kOut_TypeModifier, | |
| 207 DeclaredColorOutputName()); | |
| 208 } | |
| 209 } | |
| 210 | |
| 211 void GrGLFragmentShaderBuilder::enableSecondaryOutput() { | |
| 212 SkASSERT(!fHasSecondaryOutput); | |
| 213 fHasSecondaryOutput = true; | |
| 214 const GrGLSLCaps& caps = *fProgramBuilder->glslCaps(); | |
| 215 if (const char* extension = caps.secondaryOutputExtensionString()) { | |
| 216 this->addFeature(1 << kBlendFuncExtended_GLSLPrivateFeature, extension); | |
| 217 } | |
| 218 | |
| 219 // If the primary output is declared, we must declare also the secondary out
put | |
| 220 // and vice versa, since it is not allowed to use a built-in gl_FragColor an
d a custom | |
| 221 // output. The condition also co-incides with the condition in whici GLES SL
2.0 | |
| 222 // requires the built-in gl_SecondaryFragColorEXT, where as 3.0 requires a c
ustom output. | |
| 223 if (caps.mustDeclareFragmentShaderOutput()) { | |
| 224 fOutputs.push_back().set(kVec4f_GrSLType, GrGLSLShaderVar::kOut_TypeModi
fier, | |
| 225 DeclaredSecondaryColorOutputName()); | |
| 226 } | |
| 227 } | |
| 228 | |
| 229 const char* GrGLFragmentShaderBuilder::getPrimaryColorOutputName() const { | |
| 230 return fHasCustomColorOutput ? DeclaredColorOutputName() : "gl_FragColor"; | |
| 231 } | |
| 232 | |
| 233 const char* GrGLFragmentShaderBuilder::getSecondaryColorOutputName() const { | |
| 234 const GrGLSLCaps& caps = *fProgramBuilder->glslCaps(); | |
| 235 return caps.mustDeclareFragmentShaderOutput() ? DeclaredSecondaryColorOutput
Name() | |
| 236 : "gl_SecondaryFragColorEXT"; | |
| 237 } | |
| 238 | |
| 239 void GrGLFragmentShaderBuilder::onFinalize() { | |
| 240 GrGLSLAppendDefaultFloatPrecisionDeclaration(kDefault_GrSLPrecision, | |
| 241 *fProgramBuilder->glslCaps(), | |
| 242 &this->precisionQualifier()); | |
| 243 } | |
| 244 | |
| 245 void GrGLFragmentShaderBuilder::addVarying(GrGLSLVarying* v, GrSLPrecision fsPre
c) { | |
| 246 v->fFsIn = v->fVsOut; | |
| 247 if (v->fGsOut) { | |
| 248 v->fFsIn = v->fGsOut; | |
| 249 } | |
| 250 fInputs.push_back().set(v->fType, GrGLSLShaderVar::kVaryingIn_TypeModifier,
v->fFsIn, fsPrec); | |
| 251 } | |
| 252 | |
| 253 void GrGLFragmentBuilder::onBeforeChildProcEmitCode() { | |
| 254 SkASSERT(fSubstageIndices.count() >= 1); | |
| 255 fSubstageIndices.push_back(0); | |
| 256 // second-to-last value in the fSubstageIndices stack is the index of the ch
ild proc | |
| 257 // at that level which is currently emitting code. | |
| 258 fMangleString.appendf("_c%d", fSubstageIndices[fSubstageIndices.count() - 2]
); | |
| 259 } | |
| 260 | |
| 261 void GrGLFragmentBuilder::onAfterChildProcEmitCode() { | |
| 262 SkASSERT(fSubstageIndices.count() >= 2); | |
| 263 fSubstageIndices.pop_back(); | |
| 264 fSubstageIndices.back()++; | |
| 265 int removeAt = fMangleString.findLastOf('_'); | |
| 266 fMangleString.remove(removeAt, fMangleString.size() - removeAt); | |
| 267 } | |
| 268 | |
| OLD | NEW |