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 "GrGLShaderStringBuilder.h"
     10 #include "GrGLProgramBuilder.h"
     11 #include "../GrGpuGL.h"
     12 
     13 namespace {
     14 #define GL_CALL(X) GR_GL_CALL(gpu->glInterface(), X)
     15 #define GL_CALL_RET(R, X) GR_GL_CALL_RET(gpu->glInterface(), R, X)
     16 // ES2 FS only guarantees mediump and lowp support
     17 static const GrGLShaderVar::Precision kDefaultFragmentPrecision = GrGLShaderVar::kMedium_Precision;
     18 static const char kDstCopyColorName[] = "_dstColor";
     19 inline const char* declared_color_output_name() { return "fsColorOut"; }
     20 inline const char* dual_source_output_name() { return "dualSourceOut"; }
     21 inline void append_default_precision_qualifier(GrGLShaderVar::Precision p,
     22                                                GrGLStandard standard,
     23                                                SkString* str) {
     24     // Desktop GLSL has added precision qualifiers but they don't do anything.
     25     if (kGLES_GrGLStandard == standard) {
     26         switch (p) {
     27             case GrGLShaderVar::kHigh_Precision:
     28                 str->append("precision highp float;\n");
     29                 break;
     30             case GrGLShaderVar::kMedium_Precision:
     31                 str->append("precision mediump float;\n");
     32                 break;
     33             case GrGLShaderVar::kLow_Precision:
     34                 str->append("precision lowp float;\n");
     35                 break;
     36             case GrGLShaderVar::kDefault_Precision:
     37                 SkFAIL("Default precision now allowed.");
     38             default:
     39                 SkFAIL("Unknown precision value.");
     40         }
     41     }
     42 }
     43 }
     44 
     45 GrGLFragmentShaderBuilder::DstReadKey GrGLFragmentShaderBuilder::KeyForDstRead(
     46         const GrTexture* dstCopy, const GrGLCaps& caps) {
     47     uint32_t key = kYesDstRead_DstReadKeyBit;
     48     if (caps.fbFetchSupport()) {
     49         return key;
     50     }
     51     SkASSERT(dstCopy);
     52     if (!caps.textureSwizzleSupport() && GrPixelConfigIsAlphaOnly(dstCopy->config())) {
     53         // The fact that the config is alpha-only must be considered when generating code.
     54         key |= kUseAlphaConfig_DstReadKeyBit;
     55     }
     56     if (kTopLeft_GrSurfaceOrigin == dstCopy->origin()) {
     57         key |= kTopLeftOrigin_DstReadKeyBit;
     58     }
     59     SkASSERT(static_cast<DstReadKey>(key) == key);
     60     return static_cast<DstReadKey>(key);
     61 }
     62 
     63 GrGLFragmentShaderBuilder::FragPosKey GrGLFragmentShaderBuilder::KeyForFragmentPosition(
     64         const GrRenderTarget* dst, const GrGLCaps&) {
     65     if (kTopLeft_GrSurfaceOrigin == dst->origin()) {
     66         return kTopLeftFragPosRead_FragPosKey;
     67     } else {
     68         return kBottomLeftFragPosRead_FragPosKey;
     69     }
     70 }
     71 
     72 GrGLFragmentShaderBuilder::GrGLFragmentShaderBuilder(GrGLProgramBuilder* program,
     73                                                      const GrGLProgramDesc& desc)
     74     : INHERITED(program)
     75     , fHasCustomColorOutput(false)
     76     , fHasSecondaryOutput(false)
     77     , fSetupFragPosition(false)
     78     , fTopLeftFragPosRead(kTopLeftFragPosRead_FragPosKey == desc.getHeader().fFragPosKey){
     79 }
     80 
     81 const char* GrGLFragmentShaderBuilder::dstColor() {
     82     if (fProgramBuilder->fCodeStage.inStageCode()) {
     83         const GrProcessor* effect = fProgramBuilder->fCodeStage.effectStage()->getProcessor();
     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.  Unfortunately,
     86         // the code stage class only has a GrProcessor pointer so this is required for the time
     87         // being
     88         if (!static_cast<const GrFragmentProcessor*>(effect)->willReadDstColor()) {
     89             SkDEBUGFAIL("GrGLProcessor asked for dst color but its generating GrProcessor "
     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::kLastGLSLPrivateFeature + 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 }
    106 
    107 bool GrGLFragmentShaderBuilder::enableFeature(GLSLFeature feature) {
    108     switch (feature) {
    109         case kStandardDerivatives_GLSLFeature: {
    110             GrGpuGL* gpu = fProgramBuilder->gpu();
    111             if (!gpu->glCaps().shaderDerivativeSupport()) {
    112                 return false;
    113             }
    114             if (kGLES_GrGLStandard == gpu->glStandard()) {
    115                 this->addFeature(1 << kStandardDerivatives_GLSLFeature,
    116                                  "GL_OES_standard_derivatives");
    117             }
    118             return true;
    119         }
    120         default:
    121             SkFAIL("Unexpected GLSLFeature requested.");
    122             return false;
    123     }
    124 }
    125 
    126 SkString GrGLFragmentShaderBuilder::ensureFSCoords2D(
    127         const GrGLProcessor::TransformedCoordsArray& coords, int index) {
    128     if (kVec3f_GrSLType != coords[index].getType()) {
    129         SkASSERT(kVec2f_GrSLType == coords[index].getType());
    130         return coords[index].getName();
    131     }
    132 
    133     SkString coords2D("coords2D");
    134     if (0 != index) {
    135         coords2D.appendf("_%i", index);
    136     }
    137     this->codeAppendf("\tvec2 %s = %s.xy / %s.z;",
    138                       coords2D.c_str(), coords[index].c_str(), coords[index].c_str());
    139     return coords2D;
    140 }
    141 
    142 const char* GrGLFragmentShaderBuilder::fragmentPosition() {
    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 generating GrProcessor "
    148                         "did not request access.");
    149             return "";
    150         }
    151     }
    152 
    153     GrGpuGL* gpu = fProgramBuilder->gpu();
    154     // We only declare "gl_FragCoord" when we're in the case where we want to use layout qualifiers
    155     // 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.
    157     if (fTopLeftFragPosRead) {
    158         fSetupFragPosition = true;
    159         return "gl_FragCoord";
    160     } else if (gpu->glCaps().fragCoordConventionsSupport()) {
    161         if (!fSetupFragPosition) {
    162             if (gpu->glslGeneration() < k150_GrGLSLGeneration) {
    163                 this->addFeature(1 << kFragCoordConventions_GLSLPrivateFeature,
    164                                  "GL_ARB_fragment_coord_conventions");
    165             }
    166             fInputs.push_back().set(kVec4f_GrSLType,
    167                                     GrGLShaderVar::kIn_TypeModifier,
    168                                     "gl_FragCoord",
    169                                     GrGLShaderVar::kDefault_Precision,
    170                                     GrGLShaderVar::kUpperLeft_Origin);
    171             fSetupFragPosition = true;
    172         }
    173         return "gl_FragCoord";
    174     } else {
    175         static const char* kCoordName = "fragCoordYDown";
    176         if (!fSetupFragPosition) {
    177             // temporarily change the stage index because we're inserting non-stage code.
    178             GrGLProgramBuilder::CodeStage::AutoStageRestore csar(cs, NULL);
    179 
    180             SkASSERT(!fProgramBuilder->fUniformHandles.fRTHeightUni.isValid());
    181             const char* rtHeightName;
    182 
    183             fProgramBuilder->fUniformHandles.fRTHeightUni =
    184                     fProgramBuilder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
    185                                          kFloat_GrSLType,
    186                                          "RTHeight",
    187                                          &rtHeightName);
    188 
    189             // Using glFragCoord.zw for the last two components tickles an Adreno driver bug that
    190             // causes programs to fail to link. Making this function return a vec2() didn't fix the
    191             // problem but using 1.0 for the last two components does.
    192             this->codePrependf("\tvec4 %s = vec4(gl_FragCoord.x, %s - gl_FragCoord.y, 1.0, "
    193                                "1.0);\n", kCoordName, rtHeightName);
    194             fSetupFragPosition = true;
    195         }
    196         SkASSERT(fProgramBuilder->fUniformHandles.fRTHeightUni.isValid());
    197         return kCoordName;
    198     }
    199 }
    200 
    201 void GrGLFragmentShaderBuilder::addVarying(GrSLType type,
    202                const char* name,
    203                const char** fsInName,
    204                GrGLShaderVar::Precision fsPrecision) {
    205     fInputs.push_back().set(type, GrGLShaderVar::kVaryingIn_TypeModifier, name, fsPrecision);
    206     if (fsInName) {
    207         *fsInName = name;
    208     }
    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>* shaderIds) 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(), programId,
    240                                                        GR_GL_FRAGMENT_SHADER, fragShaderSrc,
    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().fbFetchSupport()) {
    258         bool topDown = SkToBool(kTopLeftOrigin_DstReadKeyBit & header.fDstReadKey);
    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& inputColor, 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 source 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 
    369