Home | History | Annotate | Download | only in gl
      1 /*
      2  * Copyright 2012 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 "gl/GrGLShaderBuilder.h"
      9 #include "gl/GrGLProgram.h"
     10 #include "gl/GrGLUniformHandle.h"
     11 #include "GrTexture.h"
     12 
     13 // number of each input/output type in a single allocation block
     14 static const int kVarsPerBlock = 8;
     15 
     16 // except FS outputs where we expect 2 at most.
     17 static const int kMaxFSOutputs = 2;
     18 
     19 // ES2 FS only guarantees mediump and lowp support
     20 static const GrGLShaderVar::Precision kDefaultFragmentPrecision = GrGLShaderVar::kMedium_Precision;
     21 
     22 typedef GrGLUniformManager::UniformHandle UniformHandle;
     23 ///////////////////////////////////////////////////////////////////////////////
     24 
     25 namespace {
     26 
     27 inline const char* sample_function_name(GrSLType type) {
     28     if (kVec2f_GrSLType == type) {
     29         return "texture2D";
     30     } else {
     31         GrAssert(kVec3f_GrSLType == type);
     32         return "texture2DProj";
     33     }
     34 }
     35 
     36 /**
     37  * Do we need to either map r,g,b->a or a->r.
     38  */
     39 inline bool swizzle_requires_alpha_remapping(const GrGLCaps& caps,
     40                                              const GrTextureAccess& access) {
     41     if (GrPixelConfigIsAlphaOnly(access.getTexture()->config())) {
     42         if (caps.textureRedSupport() && (GrTextureAccess::kA_SwizzleFlag & access.swizzleMask())) {
     43             return true;
     44         }
     45         if (GrTextureAccess::kRGB_SwizzleMask & access.swizzleMask()) {
     46             return true;
     47         }
     48     }
     49     return false;
     50 }
     51 
     52 void append_swizzle(SkString* outAppend,
     53                     const GrTextureAccess& access,
     54                     const GrGLCaps& caps) {
     55     const char* swizzle = access.getSwizzle();
     56     char mangledSwizzle[5];
     57 
     58     // The swizzling occurs using texture params instead of shader-mangling if ARB_texture_swizzle
     59     // is available.
     60     if (!caps.textureSwizzleSupport() && GrPixelConfigIsAlphaOnly(access.getTexture()->config())) {
     61         char alphaChar = caps.textureRedSupport() ? 'r' : 'a';
     62         int i;
     63         for (i = 0; '\0' != swizzle[i]; ++i) {
     64             mangledSwizzle[i] = alphaChar;
     65         }
     66         mangledSwizzle[i] ='\0';
     67         swizzle = mangledSwizzle;
     68     }
     69     // For shader prettiness we omit the swizzle rather than appending ".rgba".
     70     if (memcmp(swizzle, "rgba", 4)) {
     71         outAppend->appendf(".%s", swizzle);
     72     }
     73 }
     74 
     75 }
     76 
     77 ///////////////////////////////////////////////////////////////////////////////
     78 
     79 // Architectural assumption: always 2-d input coords.
     80 // Likely to become non-constant and non-static, perhaps even
     81 // varying by stage, if we use 1D textures for gradients!
     82 //const int GrGLShaderBuilder::fCoordDims = 2;
     83 
     84 GrGLShaderBuilder::GrGLShaderBuilder(const GrGLContextInfo& ctx, GrGLUniformManager& uniformManager)
     85     : fUniforms(kVarsPerBlock)
     86     , fVSAttrs(kVarsPerBlock)
     87     , fVSOutputs(kVarsPerBlock)
     88     , fGSInputs(kVarsPerBlock)
     89     , fGSOutputs(kVarsPerBlock)
     90     , fFSInputs(kVarsPerBlock)
     91     , fFSOutputs(kMaxFSOutputs)
     92     , fUsesGS(false)
     93     , fContext(ctx)
     94     , fUniformManager(uniformManager)
     95     , fCurrentStageIdx(kNonStageIdx)
     96     , fSetupFragPosition(false)
     97     , fRTHeightUniform(GrGLUniformManager::kInvalidUniformHandle) {
     98 
     99     fPositionVar = &fVSAttrs.push_back();
    100     fPositionVar->set(kVec2f_GrSLType, GrGLShaderVar::kAttribute_TypeModifier, "aPosition");
    101 }
    102 
    103 void GrGLShaderBuilder::appendTextureLookup(SkString* out,
    104                                             const GrGLShaderBuilder::TextureSampler& sampler,
    105                                             const char* coordName,
    106                                             GrSLType varyingType) const {
    107     GrAssert(NULL != sampler.textureAccess());
    108     GrAssert(NULL != coordName);
    109 
    110     out->appendf("%s(%s, %s)",
    111                  sample_function_name(varyingType),
    112                  this->getUniformCStr(sampler.fSamplerUniform),
    113                  coordName);
    114     append_swizzle(out, *sampler.textureAccess(), fContext.caps());
    115 }
    116 
    117 void GrGLShaderBuilder::appendTextureLookupAndModulate(
    118                                             SkString* out,
    119                                             const char* modulation,
    120                                             const GrGLShaderBuilder::TextureSampler& sampler,
    121                                             const char* coordName,
    122                                             GrSLType varyingType) const {
    123     GrAssert(NULL != out);
    124     SkString lookup;
    125     this->appendTextureLookup(&lookup, sampler, coordName, varyingType);
    126     GrGLSLModulate4f(out, modulation, lookup.c_str());
    127 }
    128 
    129 GrBackendEffectFactory::EffectKey GrGLShaderBuilder::KeyForTextureAccess(
    130                                                             const GrTextureAccess& access,
    131                                                             const GrGLCaps& caps) {
    132     GrBackendEffectFactory::EffectKey key = 0;
    133 
    134     // Assume that swizzle support implies that we never have to modify a shader to adjust
    135     // for texture format/swizzle settings.
    136     if (!caps.textureSwizzleSupport() && swizzle_requires_alpha_remapping(caps, access)) {
    137         key = 1;
    138     }
    139 #if GR_DEBUG
    140     // Assert that key is set iff the swizzle will be modified.
    141     SkString origString(access.getSwizzle());
    142     origString.prepend(".");
    143     SkString modifiedString;
    144     append_swizzle(&modifiedString, access, caps);
    145     if (!modifiedString.size()) {
    146         modifiedString = ".rgba";
    147     }
    148     GrAssert(SkToBool(key) == (modifiedString != origString));
    149 #endif
    150     return key;
    151 }
    152 
    153 const GrGLenum* GrGLShaderBuilder::GetTexParamSwizzle(GrPixelConfig config, const GrGLCaps& caps) {
    154     if (caps.textureSwizzleSupport() && GrPixelConfigIsAlphaOnly(config)) {
    155         if (caps.textureRedSupport()) {
    156             static const GrGLenum gRedSmear[] = { GR_GL_RED, GR_GL_RED, GR_GL_RED, GR_GL_RED };
    157             return gRedSmear;
    158         } else {
    159             static const GrGLenum gAlphaSmear[] = { GR_GL_ALPHA, GR_GL_ALPHA,
    160                                                     GR_GL_ALPHA, GR_GL_ALPHA };
    161             return gAlphaSmear;
    162         }
    163     } else {
    164         static const GrGLenum gStraight[] = { GR_GL_RED, GR_GL_GREEN, GR_GL_BLUE, GR_GL_ALPHA };
    165         return gStraight;
    166     }
    167 }
    168 
    169 GrGLUniformManager::UniformHandle GrGLShaderBuilder::addUniformArray(uint32_t visibility,
    170                                                                      GrSLType type,
    171                                                                      const char* name,
    172                                                                      int count,
    173                                                                      const char** outName) {
    174     GrAssert(name && strlen(name));
    175     SkDEBUGCODE(static const uint32_t kVisibilityMask = kVertex_ShaderType | kFragment_ShaderType);
    176     GrAssert(0 == (~kVisibilityMask & visibility));
    177     GrAssert(0 != visibility);
    178 
    179     BuilderUniform& uni = fUniforms.push_back();
    180     UniformHandle h = index_to_handle(fUniforms.count() - 1);
    181     GR_DEBUGCODE(UniformHandle h2 =)
    182     fUniformManager.appendUniform(type, count);
    183     // We expect the uniform manager to initially have no uniforms and that all uniforms are added
    184     // by this function. Therefore, the handles should match.
    185     GrAssert(h2 == h);
    186     uni.fVariable.setType(type);
    187     uni.fVariable.setTypeModifier(GrGLShaderVar::kUniform_TypeModifier);
    188     SkString* uniName = uni.fVariable.accessName();
    189     if (kNonStageIdx == fCurrentStageIdx) {
    190         uniName->printf("u%s", name);
    191     } else {
    192         uniName->printf("u%s%d", name, fCurrentStageIdx);
    193     }
    194     uni.fVariable.setArrayCount(count);
    195     uni.fVisibility = visibility;
    196 
    197     // If it is visible in both the VS and FS, the precision must match.
    198     // We declare a default FS precision, but not a default VS. So set the var
    199     // to use the default FS precision.
    200     if ((kVertex_ShaderType | kFragment_ShaderType) == visibility) {
    201         // the fragment and vertex precisions must match
    202         uni.fVariable.setPrecision(kDefaultFragmentPrecision);
    203     }
    204 
    205     if (NULL != outName) {
    206         *outName = uni.fVariable.c_str();
    207     }
    208 
    209     return h;
    210 }
    211 
    212 const GrGLShaderVar& GrGLShaderBuilder::getUniformVariable(UniformHandle u) const {
    213     return fUniforms[handle_to_index(u)].fVariable;
    214 }
    215 
    216 void GrGLShaderBuilder::addVarying(GrSLType type,
    217                                    const char* name,
    218                                    const char** vsOutName,
    219                                    const char** fsInName) {
    220     fVSOutputs.push_back();
    221     fVSOutputs.back().setType(type);
    222     fVSOutputs.back().setTypeModifier(GrGLShaderVar::kOut_TypeModifier);
    223     if (kNonStageIdx == fCurrentStageIdx) {
    224         fVSOutputs.back().accessName()->printf("v%s", name);
    225     } else {
    226         fVSOutputs.back().accessName()->printf("v%s%d", name, fCurrentStageIdx);
    227     }
    228     if (vsOutName) {
    229         *vsOutName = fVSOutputs.back().getName().c_str();
    230     }
    231     // input to FS comes either from VS or GS
    232     const SkString* fsName;
    233     if (fUsesGS) {
    234         // if we have a GS take each varying in as an array
    235         // and output as non-array.
    236         fGSInputs.push_back();
    237         fGSInputs.back().setType(type);
    238         fGSInputs.back().setTypeModifier(GrGLShaderVar::kIn_TypeModifier);
    239         fGSInputs.back().setUnsizedArray();
    240         *fGSInputs.back().accessName() = fVSOutputs.back().getName();
    241         fGSOutputs.push_back();
    242         fGSOutputs.back().setType(type);
    243         fGSOutputs.back().setTypeModifier(GrGLShaderVar::kOut_TypeModifier);
    244         if (kNonStageIdx == fCurrentStageIdx) {
    245             fGSOutputs.back().accessName()->printf("g%s", name);
    246         } else {
    247             fGSOutputs.back().accessName()->printf("g%s%d", name, fCurrentStageIdx);
    248         }
    249         fsName = fGSOutputs.back().accessName();
    250     } else {
    251         fsName = fVSOutputs.back().accessName();
    252     }
    253     fFSInputs.push_back();
    254     fFSInputs.back().setType(type);
    255     fFSInputs.back().setTypeModifier(GrGLShaderVar::kIn_TypeModifier);
    256     fFSInputs.back().setName(*fsName);
    257     if (fsInName) {
    258         *fsInName = fsName->c_str();
    259     }
    260 }
    261 
    262 const char* GrGLShaderBuilder::fragmentPosition() {
    263     if (fContext.caps().fragCoordConventionsSupport()) {
    264         if (!fSetupFragPosition) {
    265             fFSHeader.append("#extension GL_ARB_fragment_coord_conventions: require\n");
    266             fFSInputs.push_back().set(kVec4f_GrSLType,
    267                                       GrGLShaderVar::kIn_TypeModifier,
    268                                       "gl_FragCoord",
    269                                       GrGLShaderVar::kDefault_Precision,
    270                                       GrGLShaderVar::kUpperLeft_Origin);
    271             fSetupFragPosition = true;
    272         }
    273         return "gl_FragCoord";
    274     } else {
    275         static const char* kCoordName = "fragCoordYDown";
    276         if (!fSetupFragPosition) {
    277             GrAssert(GrGLUniformManager::kInvalidUniformHandle == fRTHeightUniform);
    278             const char* rtHeightName;
    279 
    280             // temporarily change the stage index because we're inserting a uniform whose name
    281             // shouldn't be mangled to be stage-specific.
    282             int oldStageIdx = fCurrentStageIdx;
    283             fCurrentStageIdx = kNonStageIdx;
    284             fRTHeightUniform = this->addUniform(kFragment_ShaderType,
    285                                                 kFloat_GrSLType,
    286                                                 "RTHeight",
    287                                                 &rtHeightName);
    288             fCurrentStageIdx = oldStageIdx;
    289 
    290             this->fFSCode.prependf("\tvec4 %s = vec4(gl_FragCoord.x, %s - gl_FragCoord.y, gl_FragCoord.zw);\n",
    291                                    kCoordName, rtHeightName);
    292             fSetupFragPosition = true;
    293         }
    294         GrAssert(GrGLUniformManager::kInvalidUniformHandle != fRTHeightUniform);
    295         return kCoordName;
    296     }
    297 }
    298 
    299 
    300 void GrGLShaderBuilder::emitFunction(ShaderType shader,
    301                                      GrSLType returnType,
    302                                      const char* name,
    303                                      int argCnt,
    304                                      const GrGLShaderVar* args,
    305                                      const char* body,
    306                                      SkString* outName) {
    307     GrAssert(kFragment_ShaderType == shader);
    308     fFSFunctions.append(GrGLShaderVar::TypeString(returnType));
    309     if (kNonStageIdx != fCurrentStageIdx) {
    310         outName->printf(" %s_%d", name, fCurrentStageIdx);
    311     } else {
    312         *outName = name;
    313     }
    314     fFSFunctions.append(*outName);
    315     fFSFunctions.append("(");
    316     for (int i = 0; i < argCnt; ++i) {
    317         args[i].appendDecl(fContext, &fFSFunctions);
    318         if (i < argCnt - 1) {
    319             fFSFunctions.append(", ");
    320         }
    321     }
    322     fFSFunctions.append(") {\n");
    323     fFSFunctions.append(body);
    324     fFSFunctions.append("}\n\n");
    325 }
    326 
    327 namespace {
    328 
    329 inline void append_default_precision_qualifier(GrGLShaderVar::Precision p,
    330                                                GrGLBinding binding,
    331                                                SkString* str) {
    332     // Desktop GLSL has added precision qualifiers but they don't do anything.
    333     if (kES2_GrGLBinding == binding) {
    334         switch (p) {
    335             case GrGLShaderVar::kHigh_Precision:
    336                 str->append("precision highp float;\n");
    337                 break;
    338             case GrGLShaderVar::kMedium_Precision:
    339                 str->append("precision mediump float;\n");
    340                 break;
    341             case GrGLShaderVar::kLow_Precision:
    342                 str->append("precision lowp float;\n");
    343                 break;
    344             case GrGLShaderVar::kDefault_Precision:
    345                 GrCrash("Default precision now allowed.");
    346             default:
    347                 GrCrash("Unknown precision value.");
    348         }
    349     }
    350 }
    351 }
    352 
    353 void GrGLShaderBuilder::appendDecls(const VarArray& vars, SkString* out) const {
    354     for (int i = 0; i < vars.count(); ++i) {
    355         vars[i].appendDecl(fContext, out);
    356         out->append(";\n");
    357     }
    358 }
    359 
    360 void GrGLShaderBuilder::appendUniformDecls(ShaderType stype, SkString* out) const {
    361     for (int i = 0; i < fUniforms.count(); ++i) {
    362         if (fUniforms[i].fVisibility & stype) {
    363             fUniforms[i].fVariable.appendDecl(fContext, out);
    364             out->append(";\n");
    365         }
    366     }
    367 }
    368 
    369 void GrGLShaderBuilder::getShader(ShaderType type, SkString* shaderStr) const {
    370     switch (type) {
    371         case kVertex_ShaderType:
    372             *shaderStr = fHeader;
    373             this->appendUniformDecls(kVertex_ShaderType, shaderStr);
    374             this->appendDecls(fVSAttrs, shaderStr);
    375             this->appendDecls(fVSOutputs, shaderStr);
    376             shaderStr->append("void main() {\n");
    377             shaderStr->append(fVSCode);
    378             shaderStr->append("}\n");
    379             break;
    380         case kGeometry_ShaderType:
    381             if (fUsesGS) {
    382                 *shaderStr = fHeader;
    383                 shaderStr->append(fGSHeader);
    384                 this->appendDecls(fGSInputs, shaderStr);
    385                 this->appendDecls(fGSOutputs, shaderStr);
    386                 shaderStr->append("void main() {\n");
    387                 shaderStr->append(fGSCode);
    388                 shaderStr->append("}\n");
    389             } else {
    390                 shaderStr->reset();
    391             }
    392             break;
    393         case kFragment_ShaderType:
    394             *shaderStr = fHeader;
    395             append_default_precision_qualifier(kDefaultFragmentPrecision,
    396                                                fContext.binding(),
    397                                                shaderStr);
    398             shaderStr->append(fFSHeader);
    399             this->appendUniformDecls(kFragment_ShaderType, shaderStr);
    400             this->appendDecls(fFSInputs, shaderStr);
    401             // We shouldn't have declared outputs on 1.10
    402             GrAssert(k110_GrGLSLGeneration != fContext.glslGeneration() || fFSOutputs.empty());
    403             this->appendDecls(fFSOutputs, shaderStr);
    404             shaderStr->append(fFSFunctions);
    405             shaderStr->append("void main() {\n");
    406             shaderStr->append(fFSCode);
    407             shaderStr->append("}\n");
    408             break;
    409     }
    410  }
    411 
    412 void GrGLShaderBuilder::finished(GrGLuint programID) {
    413     fUniformManager.getUniformLocations(programID, fUniforms);
    414 }
    415 
    416 GrGLEffect* GrGLShaderBuilder::createAndEmitGLEffect(
    417                                 const GrEffectStage& stage,
    418                                 GrGLEffect::EffectKey key,
    419                                 const char* fsInColor,
    420                                 const char* fsOutColor,
    421                                 const char* vsInCoord,
    422                                 SkTArray<GrGLUniformManager::UniformHandle, true>* samplerHandles) {
    423     GrAssert(NULL != stage.getEffect());
    424 
    425     const GrEffectRef& effect = *stage.getEffect();
    426     int numTextures = effect->numTextures();
    427     SkSTArray<8, GrGLShaderBuilder::TextureSampler> textureSamplers;
    428     textureSamplers.push_back_n(numTextures);
    429     for (int i = 0; i < numTextures; ++i) {
    430         textureSamplers[i].init(this, &effect->textureAccess(i), i);
    431         samplerHandles->push_back(textureSamplers[i].fSamplerUniform);
    432     }
    433 
    434     GrGLEffect* glEffect = effect->getFactory().createGLInstance(effect);
    435 
    436     // Enclose custom code in a block to avoid namespace conflicts
    437     this->fVSCode.appendf("\t{ // %s\n", glEffect->name());
    438     this->fFSCode.appendf("\t{ // %s \n", glEffect->name());
    439     glEffect->emitCode(this,
    440                        stage,
    441                        key,
    442                        vsInCoord,
    443                        fsOutColor,
    444                        fsInColor,
    445                        textureSamplers);
    446     this->fVSCode.appendf("\t}\n");
    447     this->fFSCode.appendf("\t}\n");
    448 
    449     return glEffect;
    450 }
    451