Home | History | Annotate | Download | only in builders
      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 "GrGLProgramBuilder.h"
     10 #include "../GrGLGpu.h"
     11 
     12 #define GL_CALL(X) GR_GL_CALL(fProgramBuilder->gpu()->glInterface(), X)
     13 #define GL_CALL_RET(R, X) GR_GL_CALL_RET(fProgramBuilder->gpu()->glInterface(), R, X)
     14 
     15 const char* GrGLFragmentShaderBuilder::kDstCopyColorName = "_dstColor";
     16 static const char* declared_color_output_name() { return "fsColorOut"; }
     17 static const char* dual_source_output_name() { return "dualSourceOut"; }
     18 static void append_default_precision_qualifier(GrSLPrecision p,
     19                                                GrGLStandard standard,
     20                                                SkString* str) {
     21     // Desktop GLSL has added precision qualifiers but they don't do anything.
     22     if (kGLES_GrGLStandard == standard) {
     23         switch (p) {
     24             case kHigh_GrSLPrecision:
     25                 str->append("precision highp float;\n");
     26                 break;
     27             case kMedium_GrSLPrecision:
     28                 str->append("precision mediump float;\n");
     29                 break;
     30             case kLow_GrSLPrecision:
     31                 str->append("precision lowp float;\n");
     32                 break;
     33             default:
     34                 SkFAIL("Unknown precision value.");
     35         }
     36     }
     37 }
     38 
     39 static const char* specific_layout_qualifier_name(GrBlendEquation equation) {
     40     SkASSERT(GrBlendEquationIsAdvanced(equation));
     41 
     42     static const char* kLayoutQualifierNames[] = {
     43         "blend_support_screen",
     44         "blend_support_overlay",
     45         "blend_support_darken",
     46         "blend_support_lighten",
     47         "blend_support_colordodge",
     48         "blend_support_colorburn",
     49         "blend_support_hardlight",
     50         "blend_support_softlight",
     51         "blend_support_difference",
     52         "blend_support_exclusion",
     53         "blend_support_multiply",
     54         "blend_support_hsl_hue",
     55         "blend_support_hsl_saturation",
     56         "blend_support_hsl_color",
     57         "blend_support_hsl_luminosity"
     58     };
     59     return kLayoutQualifierNames[equation - kFirstAdvancedGrBlendEquation];
     60 
     61     GR_STATIC_ASSERT(0 == kScreen_GrBlendEquation - kFirstAdvancedGrBlendEquation);
     62     GR_STATIC_ASSERT(1 == kOverlay_GrBlendEquation - kFirstAdvancedGrBlendEquation);
     63     GR_STATIC_ASSERT(2 == kDarken_GrBlendEquation - kFirstAdvancedGrBlendEquation);
     64     GR_STATIC_ASSERT(3 == kLighten_GrBlendEquation - kFirstAdvancedGrBlendEquation);
     65     GR_STATIC_ASSERT(4 == kColorDodge_GrBlendEquation - kFirstAdvancedGrBlendEquation);
     66     GR_STATIC_ASSERT(5 == kColorBurn_GrBlendEquation - kFirstAdvancedGrBlendEquation);
     67     GR_STATIC_ASSERT(6 == kHardLight_GrBlendEquation - kFirstAdvancedGrBlendEquation);
     68     GR_STATIC_ASSERT(7 == kSoftLight_GrBlendEquation - kFirstAdvancedGrBlendEquation);
     69     GR_STATIC_ASSERT(8 == kDifference_GrBlendEquation - kFirstAdvancedGrBlendEquation);
     70     GR_STATIC_ASSERT(9 == kExclusion_GrBlendEquation - kFirstAdvancedGrBlendEquation);
     71     GR_STATIC_ASSERT(10 == kMultiply_GrBlendEquation - kFirstAdvancedGrBlendEquation);
     72     GR_STATIC_ASSERT(11 == kHSLHue_GrBlendEquation - kFirstAdvancedGrBlendEquation);
     73     GR_STATIC_ASSERT(12 == kHSLSaturation_GrBlendEquation - kFirstAdvancedGrBlendEquation);
     74     GR_STATIC_ASSERT(13 == kHSLColor_GrBlendEquation - kFirstAdvancedGrBlendEquation);
     75     GR_STATIC_ASSERT(14 == kHSLLuminosity_GrBlendEquation - kFirstAdvancedGrBlendEquation);
     76     GR_STATIC_ASSERT(SK_ARRAY_COUNT(kLayoutQualifierNames) ==
     77                      kGrBlendEquationCnt - kFirstAdvancedGrBlendEquation);
     78 }
     79 
     80 GrGLFragmentShaderBuilder::DstReadKey
     81 GrGLFragmentShaderBuilder::KeyForDstRead(const GrTexture* dstCopy, const GrGLCaps& caps) {
     82     uint32_t key = kYesDstRead_DstReadKeyBit;
     83     if (caps.glslCaps()->fbFetchSupport()) {
     84         return key;
     85     }
     86     SkASSERT(dstCopy);
     87     if (!caps.textureSwizzleSupport() && GrPixelConfigIsAlphaOnly(dstCopy->config())) {
     88         // The fact that the config is alpha-only must be considered when generating code.
     89         key |= kUseAlphaConfig_DstReadKeyBit;
     90     }
     91     if (kTopLeft_GrSurfaceOrigin == dstCopy->origin()) {
     92         key |= kTopLeftOrigin_DstReadKeyBit;
     93     }
     94     SkASSERT(static_cast<DstReadKey>(key) == key);
     95     return static_cast<DstReadKey>(key);
     96 }
     97 
     98 GrGLFragmentShaderBuilder::FragPosKey
     99 GrGLFragmentShaderBuilder::KeyForFragmentPosition(const GrRenderTarget* dst, const GrGLCaps&) {
    100     if (kTopLeft_GrSurfaceOrigin == dst->origin()) {
    101         return kTopLeftFragPosRead_FragPosKey;
    102     } else {
    103         return kBottomLeftFragPosRead_FragPosKey;
    104     }
    105 }
    106 
    107 GrGLFragmentShaderBuilder::GrGLFragmentShaderBuilder(GrGLProgramBuilder* program,
    108                                                      uint8_t fragPosKey)
    109     : INHERITED(program)
    110     , fHasCustomColorOutput(false)
    111     , fHasSecondaryOutput(false)
    112     , fSetupFragPosition(false)
    113     , fTopLeftFragPosRead(kTopLeftFragPosRead_FragPosKey == fragPosKey)
    114     , fCustomColorOutputIndex(-1)
    115     , fHasReadDstColor(false)
    116     , fHasReadFragmentPosition(false) {
    117 }
    118 
    119 bool GrGLFragmentShaderBuilder::enableFeature(GLSLFeature feature) {
    120     switch (feature) {
    121         case kStandardDerivatives_GLSLFeature: {
    122             GrGLGpu* gpu = fProgramBuilder->gpu();
    123             if (!gpu->glCaps().shaderCaps()->shaderDerivativeSupport()) {
    124                 return false;
    125             }
    126             if (kGLES_GrGLStandard == gpu->glStandard() &&
    127                 k110_GrGLSLGeneration == gpu->glslGeneration()) {
    128                 this->addFeature(1 << kStandardDerivatives_GLSLFeature,
    129                                  "GL_OES_standard_derivatives");
    130             }
    131             return true;
    132         }
    133         default:
    134             SkFAIL("Unexpected GLSLFeature requested.");
    135             return false;
    136     }
    137 }
    138 
    139 SkString GrGLFragmentShaderBuilder::ensureFSCoords2D(
    140         const GrGLProcessor::TransformedCoordsArray& coords, int index) {
    141     if (kVec3f_GrSLType != coords[index].getType()) {
    142         SkASSERT(kVec2f_GrSLType == coords[index].getType());
    143         return coords[index].getName();
    144     }
    145 
    146     SkString coords2D("coords2D");
    147     if (0 != index) {
    148         coords2D.appendf("_%i", index);
    149     }
    150     this->codeAppendf("\tvec2 %s = %s.xy / %s.z;",
    151                       coords2D.c_str(), coords[index].c_str(), coords[index].c_str());
    152     return coords2D;
    153 }
    154 
    155 const char* GrGLFragmentShaderBuilder::fragmentPosition() {
    156     fHasReadFragmentPosition = true;
    157 
    158     GrGLGpu* gpu = fProgramBuilder->gpu();
    159     // We only declare "gl_FragCoord" when we're in the case where we want to use layout qualifiers
    160     // to reverse y. Otherwise it isn't necessary and whether the "in" qualifier appears in the
    161     // declaration varies in earlier GLSL specs. So it is simpler to omit it.
    162     if (fTopLeftFragPosRead) {
    163         fSetupFragPosition = true;
    164         return "gl_FragCoord";
    165     } else if (gpu->glCaps().fragCoordConventionsSupport()) {
    166         if (!fSetupFragPosition) {
    167             if (gpu->glslGeneration() < k150_GrGLSLGeneration) {
    168                 this->addFeature(1 << kFragCoordConventions_GLSLPrivateFeature,
    169                                  "GL_ARB_fragment_coord_conventions");
    170             }
    171             fInputs.push_back().set(kVec4f_GrSLType,
    172                                     GrGLShaderVar::kIn_TypeModifier,
    173                                     "gl_FragCoord",
    174                                     kDefault_GrSLPrecision,
    175                                     GrGLShaderVar::kUpperLeft_Origin);
    176             fSetupFragPosition = true;
    177         }
    178         return "gl_FragCoord";
    179     } else {
    180         static const char* kCoordName = "fragCoordYDown";
    181         if (!fSetupFragPosition) {
    182             // temporarily change the stage index because we're inserting non-stage code.
    183             GrGLProgramBuilder::AutoStageRestore asr(fProgramBuilder);
    184             SkASSERT(!fProgramBuilder->fUniformHandles.fRTHeightUni.isValid());
    185             const char* rtHeightName;
    186 
    187             fProgramBuilder->fUniformHandles.fRTHeightUni =
    188                     fProgramBuilder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
    189                                                 kFloat_GrSLType,
    190                                                 kDefault_GrSLPrecision,
    191                                                 "RTHeight",
    192                                                 &rtHeightName);
    193 
    194             // Using glFragCoord.zw for the last two components tickles an Adreno driver bug that
    195             // causes programs to fail to link. Making this function return a vec2() didn't fix the
    196             // problem but using 1.0 for the last two components does.
    197             this->codePrependf("\tvec4 %s = vec4(gl_FragCoord.x, %s - gl_FragCoord.y, 1.0, "
    198                                "1.0);\n", kCoordName, rtHeightName);
    199             fSetupFragPosition = true;
    200         }
    201         SkASSERT(fProgramBuilder->fUniformHandles.fRTHeightUni.isValid());
    202         return kCoordName;
    203     }
    204 }
    205 
    206 const char* GrGLFragmentShaderBuilder::dstColor() {
    207     fHasReadDstColor = true;
    208 
    209     GrGLGpu* gpu = fProgramBuilder->gpu();
    210     if (gpu->glCaps().glslCaps()->fbFetchSupport()) {
    211         this->addFeature(1 << (GrGLFragmentShaderBuilder::kLastGLSLPrivateFeature + 1),
    212                          gpu->glCaps().glslCaps()->fbFetchExtensionString());
    213 
    214         // Some versions of this extension string require declaring custom color output on ES 3.0+
    215         const char* fbFetchColorName = gpu->glCaps().glslCaps()->fbFetchColorName();
    216         if (gpu->glCaps().glslCaps()->fbFetchNeedsCustomOutput()) {
    217             this->enableCustomOutput();
    218             fOutputs[fCustomColorOutputIndex].setTypeModifier(GrShaderVar::kInOut_TypeModifier);
    219             fbFetchColorName = declared_color_output_name();
    220         }
    221         return fbFetchColorName;
    222     } else {
    223         return kDstCopyColorName;
    224     }
    225 }
    226 
    227 void GrGLFragmentShaderBuilder::enableAdvancedBlendEquationIfNeeded(GrBlendEquation equation) {
    228     SkASSERT(GrBlendEquationIsAdvanced(equation));
    229 
    230     const GrGLSLCaps& caps = *fProgramBuilder->gpu()->glCaps().glslCaps();
    231     if (!caps.mustEnableAdvBlendEqs()) {
    232         return;
    233     }
    234 
    235     this->addFeature(1 << kBlendEquationAdvanced_GLSLPrivateFeature,
    236                      "GL_KHR_blend_equation_advanced");
    237     if (caps.mustEnableSpecificAdvBlendEqs()) {
    238         this->addLayoutQualifier(specific_layout_qualifier_name(equation), kOut_InterfaceQualifier);
    239     } else {
    240         this->addLayoutQualifier("blend_support_all_equations", kOut_InterfaceQualifier);
    241     }
    242 }
    243 
    244 void GrGLFragmentShaderBuilder::enableCustomOutput() {
    245     if (!fHasCustomColorOutput) {
    246         fHasCustomColorOutput = true;
    247         fCustomColorOutputIndex = fOutputs.count();
    248         fOutputs.push_back().set(kVec4f_GrSLType,
    249                                  GrGLShaderVar::kOut_TypeModifier,
    250                                  declared_color_output_name());
    251     }
    252 }
    253 
    254 void GrGLFragmentShaderBuilder::enableSecondaryOutput() {
    255     SkASSERT(!fHasSecondaryOutput);
    256     fHasSecondaryOutput = true;
    257     fOutputs.push_back().set(kVec4f_GrSLType, GrGLShaderVar::kOut_TypeModifier,
    258                              dual_source_output_name());
    259 }
    260 
    261 const char* GrGLFragmentShaderBuilder::getPrimaryColorOutputName() const {
    262     return fHasCustomColorOutput ? declared_color_output_name() : "gl_FragColor";
    263 }
    264 
    265 const char* GrGLFragmentShaderBuilder::getSecondaryColorOutputName() const {
    266     return dual_source_output_name();
    267 }
    268 
    269 bool GrGLFragmentShaderBuilder::compileAndAttachShaders(GrGLuint programId,
    270                                                         SkTDArray<GrGLuint>* shaderIds) {
    271     GrGLGpu* gpu = fProgramBuilder->gpu();
    272     this->versionDecl() = GrGetGLSLVersionDecl(gpu->ctxInfo());
    273     append_default_precision_qualifier(kDefault_GrSLPrecision,
    274                                        gpu->glStandard(),
    275                                        &this->precisionQualifier());
    276     this->compileAndAppendLayoutQualifiers();
    277     fProgramBuilder->appendUniformDecls(GrGLProgramBuilder::kFragment_Visibility,
    278                                         &this->uniforms());
    279     this->appendDecls(fInputs, &this->inputs());
    280     // We shouldn't have declared outputs on 1.10
    281     SkASSERT(k110_GrGLSLGeneration != gpu->glslGeneration() || fOutputs.empty());
    282     this->appendDecls(fOutputs, &this->outputs());
    283     return this->finalize(programId, GR_GL_FRAGMENT_SHADER, shaderIds);
    284 }
    285 
    286 void GrGLFragmentShaderBuilder::bindFragmentShaderLocations(GrGLuint programID) {
    287     // ES 3.00 requires custom color output but doesn't support bindFragDataLocation
    288     if (fHasCustomColorOutput &&
    289         kGLES_GrGLStandard != fProgramBuilder->gpu()->ctxInfo().standard()) {
    290         GL_CALL(BindFragDataLocation(programID, 0, declared_color_output_name()));
    291     }
    292     if (fHasSecondaryOutput) {
    293         GL_CALL(BindFragDataLocationIndexed(programID, 0, 1, dual_source_output_name()));
    294     }
    295 }
    296 
    297 void GrGLFragmentShaderBuilder::addVarying(GrGLVarying* v, GrSLPrecision fsPrec) {
    298     v->fFsIn = v->fVsOut;
    299     if (v->fGsOut) {
    300         v->fFsIn = v->fGsOut;
    301     }
    302     fInputs.push_back().set(v->fType, GrGLShaderVar::kVaryingIn_TypeModifier, v->fFsIn, fsPrec);
    303 }
    304