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 "gl/GrGLProgram.h"
      9 #include "gl/GrGLSLPrettyPrint.h"
     10 #include "gl/GrGLUniformHandle.h"
     11 #include "GrCoordTransform.h"
     12 #include "../GrGpuGL.h"
     13 #include "GrGLFragmentShaderBuilder.h"
     14 #include "GrGLProgramBuilder.h"
     15 #include "GrTexture.h"
     16 #include "GrGLVertexShaderBuilder.h"
     17 #include "SkRTConf.h"
     18 #include "SkTraceEvent.h"
     19 
     20 namespace {
     21 #define GL_CALL(X) GR_GL_CALL(this->gpu()->glInterface(), X)
     22 #define GL_CALL_RET(R, X) GR_GL_CALL_RET(this->gpu()->glInterface(), R, X)
     23 
     24 // number of each input/output type in a single allocation block
     25 static const int kVarsPerBlock = 8;
     26 
     27 // ES2 FS only guarantees mediump and lowp support
     28 static const GrGLShaderVar::Precision kDefaultFragmentPrecision = GrGLShaderVar::kMedium_Precision;
     29 }
     30 
     31 ///////////////////////////////////////////////////////////////////////////////////////////////////
     32 
     33 bool GrGLProgramBuilder::genProgram(const GrGeometryStage* geometryProcessor,
     34                                     const GrFragmentStage* colorStages[],
     35                                     const GrFragmentStage* coverageStages[]) {
     36     const GrGLProgramDesc::KeyHeader& header = this->desc().getHeader();
     37 
     38     fFS.emitCodeBeforeEffects();
     39 
     40     ///////////////////////////////////////////////////////////////////////////
     41     // get the initial color and coverage to feed into the first effect in each effect chain
     42 
     43     GrGLSLExpr4 inputColor;
     44     GrGLSLExpr4 inputCoverage;
     45 
     46     if (GrGLProgramDesc::kUniform_ColorInput == header.fColorInput) {
     47         const char* name;
     48         fUniformHandles.fColorUni =
     49             this->addUniform(GrGLProgramBuilder::kFragment_Visibility,
     50                              kVec4f_GrSLType,
     51                              "Color",
     52                              &name);
     53         inputColor = GrGLSLExpr4(name);
     54     } else if (GrGLProgramDesc::kAllOnes_ColorInput == header.fColorInput) {
     55         inputColor = GrGLSLExpr4(1);
     56     }
     57 
     58     if (GrGLProgramDesc::kUniform_ColorInput == header.fCoverageInput) {
     59         const char* name;
     60         fUniformHandles.fCoverageUni =
     61             this->addUniform(GrGLProgramBuilder::kFragment_Visibility,
     62                              kVec4f_GrSLType,
     63                              "Coverage",
     64                              &name);
     65         inputCoverage = GrGLSLExpr4(name);
     66     } else if (GrGLProgramDesc::kAllOnes_ColorInput == header.fCoverageInput) {
     67         inputCoverage = GrGLSLExpr4(1);
     68     }
     69 
     70     // Subclasses drive effect emitting
     71     this->createAndEmitEffects(geometryProcessor, colorStages, coverageStages, &inputColor,
     72                                &inputCoverage);
     73 
     74     fFS.emitCodeAfterEffects(inputColor, inputCoverage);
     75 
     76     if (!this->finish()) {
     77         return false;
     78     }
     79 
     80     return true;
     81 }
     82 
     83 //////////////////////////////////////////////////////////////////////////////
     84 
     85 GrGLProgramBuilder::GrGLProgramBuilder(GrGpuGL* gpu,
     86                                        const GrGLProgramDesc& desc)
     87     : fEffectEmitter(NULL)
     88     , fFragOnly(SkToBool(desc.getHeader().fUseFragShaderOnly))
     89     , fTexCoordSetCnt(0)
     90     , fProgramID(0)
     91     , fFS(this, desc)
     92     , fSeparableVaryingInfos(kVarsPerBlock)
     93     , fGrProcessorEmitter(this)
     94     , fDesc(desc)
     95     , fGpu(gpu)
     96     , fUniforms(kVarsPerBlock) {
     97 }
     98 
     99 void GrGLProgramBuilder::nameVariable(SkString* out, char prefix, const char* name) {
    100     if ('\0' == prefix) {
    101         *out = name;
    102     } else {
    103         out->printf("%c%s", prefix, name);
    104     }
    105     if (fCodeStage.inStageCode()) {
    106         if (out->endsWith('_')) {
    107             // Names containing "__" are reserved.
    108             out->append("x");
    109         }
    110         out->appendf("_Stage%d", fCodeStage.stageIndex());
    111     }
    112 }
    113 
    114 GrGLProgramDataManager::UniformHandle GrGLProgramBuilder::addUniformArray(uint32_t visibility,
    115                                                                           GrSLType type,
    116                                                                           const char* name,
    117                                                                           int count,
    118                                                                           const char** outName) {
    119     SkASSERT(name && strlen(name));
    120     SkDEBUGCODE(static const uint32_t kVisibilityMask = kVertex_Visibility | kFragment_Visibility);
    121     SkASSERT(0 == (~kVisibilityMask & visibility));
    122     SkASSERT(0 != visibility);
    123 
    124     UniformInfo& uni = fUniforms.push_back();
    125     uni.fVariable.setType(type);
    126     uni.fVariable.setTypeModifier(GrGLShaderVar::kUniform_TypeModifier);
    127     this->nameVariable(uni.fVariable.accessName(), 'u', name);
    128     uni.fVariable.setArrayCount(count);
    129     uni.fVisibility = visibility;
    130 
    131     // If it is visible in both the VS and FS, the precision must match.
    132     // We declare a default FS precision, but not a default VS. So set the var
    133     // to use the default FS precision.
    134     if ((kVertex_Visibility | kFragment_Visibility) == visibility) {
    135         // the fragment and vertex precisions must match
    136         uni.fVariable.setPrecision(kDefaultFragmentPrecision);
    137     }
    138 
    139     if (outName) {
    140         *outName = uni.fVariable.c_str();
    141     }
    142     return GrGLProgramDataManager::UniformHandle::CreateFromUniformIndex(fUniforms.count() - 1);
    143 }
    144 
    145 void GrGLProgramBuilder::appendDecls(const VarArray& vars, SkString* out) const {
    146     for (int i = 0; i < vars.count(); ++i) {
    147         vars[i].appendDecl(this->ctxInfo(), out);
    148         out->append(";\n");
    149     }
    150 }
    151 
    152 void GrGLProgramBuilder::appendUniformDecls(ShaderVisibility visibility,
    153                                             SkString* out) const {
    154     for (int i = 0; i < fUniforms.count(); ++i) {
    155         if (fUniforms[i].fVisibility & visibility) {
    156             fUniforms[i].fVariable.appendDecl(this->ctxInfo(), out);
    157             out->append(";\n");
    158         }
    159     }
    160 }
    161 
    162 void GrGLProgramBuilder::createAndEmitEffects(const GrFragmentStage* effectStages[],
    163                                               int effectCnt,
    164                                               const GrGLProgramDesc::EffectKeyProvider& keyProvider,
    165                                               GrGLSLExpr4* fsInOutColor) {
    166     bool effectEmitted = false;
    167 
    168     GrGLSLExpr4 inColor = *fsInOutColor;
    169     GrGLSLExpr4 outColor;
    170 
    171     for (int e = 0; e < effectCnt; ++e) {
    172         fGrProcessorEmitter.set(effectStages[e]->getFragmentProcessor());
    173         fEffectEmitter = &fGrProcessorEmitter;
    174         // calls into the subclass to emit the actual effect into the program effect object
    175         this->emitEffect(*effectStages[e], e, keyProvider, &inColor, &outColor);
    176         effectEmitted = true;
    177     }
    178 
    179     if (effectEmitted) {
    180         *fsInOutColor = outColor;
    181     }
    182 }
    183 
    184 void GrGLProgramBuilder::emitEffect(const GrProcessorStage& effectStage,
    185                                     int effectIndex,
    186                                     const GrGLProgramDesc::EffectKeyProvider& keyProvider,
    187                                     GrGLSLExpr4* inColor,
    188                                     GrGLSLExpr4* outColor) {
    189     SkASSERT(effectStage.getProcessor());
    190     CodeStage::AutoStageRestore csar(&fCodeStage, &effectStage);
    191 
    192     if (inColor->isZeros()) {
    193         SkString inColorName;
    194 
    195         // Effects have no way to communicate zeros, they treat an empty string as ones.
    196         this->nameVariable(&inColorName, '\0', "input");
    197         fFS.codeAppendf("\tvec4 %s = %s;\n", inColorName.c_str(), inColor->c_str());
    198         *inColor = inColorName;
    199     }
    200 
    201     // create var to hold stage result
    202     SkString outColorName;
    203     this->nameVariable(&outColorName, '\0', "output");
    204     fFS.codeAppendf("\tvec4 %s;\n", outColorName.c_str());
    205     *outColor = outColorName;
    206 
    207     this->emitEffect(effectStage, keyProvider.get(effectIndex), outColor->c_str(),
    208                      inColor->isOnes() ? NULL : inColor->c_str(), fCodeStage.stageIndex());
    209 
    210     *inColor = *outColor;
    211 }
    212 
    213 void GrGLProgramBuilder::emitSamplers(const GrProcessor& effect,
    214                                       GrGLProcessor::TextureSamplerArray* outSamplers) {
    215     SkTArray<GrGLProgramEffects::Sampler, true>& samplers =
    216             this->getProgramEffects()->addSamplers();
    217     int numTextures = effect.numTextures();
    218     samplers.push_back_n(numTextures);
    219     SkString name;
    220     for (int t = 0; t < numTextures; ++t) {
    221         name.printf("Sampler%d", t);
    222         samplers[t].fUniform = this->addUniform(GrGLProgramBuilder::kFragment_Visibility,
    223                                                 kSampler2D_GrSLType,
    224                                                 name.c_str());
    225         SkNEW_APPEND_TO_TARRAY(outSamplers, GrGLProcessor::TextureSampler,
    226                                (samplers[t].fUniform, effect.textureAccess(t)));
    227     }
    228 }
    229 
    230 bool GrGLProgramBuilder::finish() {
    231     SkASSERT(0 == fProgramID);
    232     GL_CALL_RET(fProgramID, CreateProgram());
    233     if (!fProgramID) {
    234         return false;
    235     }
    236 
    237     SkTDArray<GrGLuint> shadersToDelete;
    238 
    239     if (!this->compileAndAttachShaders(fProgramID, &shadersToDelete)) {
    240         GL_CALL(DeleteProgram(fProgramID));
    241         return false;
    242     }
    243 
    244     this->bindProgramLocations(fProgramID);
    245 
    246     GL_CALL(LinkProgram(fProgramID));
    247 
    248     // Calling GetProgramiv is expensive in Chromium. Assume success in release builds.
    249     bool checkLinked = !fGpu->ctxInfo().isChromium();
    250 #ifdef SK_DEBUG
    251     checkLinked = true;
    252 #endif
    253     if (checkLinked) {
    254         GrGLint linked = GR_GL_INIT_ZERO;
    255         GL_CALL(GetProgramiv(fProgramID, GR_GL_LINK_STATUS, &linked));
    256         if (!linked) {
    257             GrGLint infoLen = GR_GL_INIT_ZERO;
    258             GL_CALL(GetProgramiv(fProgramID, GR_GL_INFO_LOG_LENGTH, &infoLen));
    259             SkAutoMalloc log(sizeof(char)*(infoLen+1));  // outside if for debugger
    260             if (infoLen > 0) {
    261                 // retrieve length even though we don't need it to workaround
    262                 // bug in chrome cmd buffer param validation.
    263                 GrGLsizei length = GR_GL_INIT_ZERO;
    264                 GL_CALL(GetProgramInfoLog(fProgramID,
    265                                           infoLen+1,
    266                                           &length,
    267                                           (char*)log.get()));
    268                 GrPrintf((char*)log.get());
    269             }
    270             SkDEBUGFAIL("Error linking program");
    271             GL_CALL(DeleteProgram(fProgramID));
    272             fProgramID = 0;
    273             return false;
    274         }
    275     }
    276 
    277     this->resolveProgramLocations(fProgramID);
    278 
    279     for (int i = 0; i < shadersToDelete.count(); ++i) {
    280       GL_CALL(DeleteShader(shadersToDelete[i]));
    281     }
    282 
    283     return true;
    284 }
    285 
    286 bool GrGLProgramBuilder::compileAndAttachShaders(GrGLuint programId,
    287                                                  SkTDArray<GrGLuint>* shaderIds) const {
    288     return fFS.compileAndAttachShaders(programId, shaderIds);
    289 }
    290 
    291 void GrGLProgramBuilder::bindProgramLocations(GrGLuint programId) {
    292     fFS.bindProgramLocations(programId);
    293 
    294     // skbug.com/2056
    295     bool usingBindUniform = fGpu->glInterface()->fFunctions.fBindUniformLocation != NULL;
    296     if (usingBindUniform) {
    297         int count = fUniforms.count();
    298         for (int i = 0; i < count; ++i) {
    299             GL_CALL(BindUniformLocation(programId, i, fUniforms[i].fVariable.c_str()));
    300             fUniforms[i].fLocation = i;
    301         }
    302     }
    303 }
    304 
    305 void GrGLProgramBuilder::resolveProgramLocations(GrGLuint programId) {
    306     bool usingBindUniform = fGpu->glInterface()->fFunctions.fBindUniformLocation != NULL;
    307     if (!usingBindUniform) {
    308         int count = fUniforms.count();
    309         for (int i = 0; i < count; ++i) {
    310             GrGLint location;
    311             GL_CALL_RET(location,
    312                         GetUniformLocation(programId, fUniforms[i].fVariable.c_str()));
    313             fUniforms[i].fLocation = location;
    314         }
    315     }
    316 
    317     int count = fSeparableVaryingInfos.count();
    318     for (int i = 0; i < count; ++i) {
    319         GrGLint location;
    320         GL_CALL_RET(location,
    321                     GetProgramResourceLocation(programId,
    322                                                GR_GL_FRAGMENT_INPUT,
    323                                                fSeparableVaryingInfos[i].fVariable.c_str()));
    324         fSeparableVaryingInfos[i].fLocation = location;
    325     }
    326 }
    327 
    328 const GrGLContextInfo& GrGLProgramBuilder::ctxInfo() const {
    329     return fGpu->ctxInfo();
    330 }
    331