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 "GrGLProgramBuilder.h"
      9 
     10 #include "GrAutoLocaleSetter.h"
     11 #include "GrContext.h"
     12 #include "GrCoordTransform.h"
     13 #include "GrGLProgramBuilder.h"
     14 #include "GrProgramDesc.h"
     15 #include "GrShaderCaps.h"
     16 #include "GrSwizzle.h"
     17 #include "SkAutoMalloc.h"
     18 #include "SkATrace.h"
     19 #include "SkTraceEvent.h"
     20 #include "gl/GrGLGpu.h"
     21 #include "gl/GrGLProgram.h"
     22 #include "gl/builders/GrGLShaderStringBuilder.h"
     23 #include "glsl/GrGLSLFragmentProcessor.h"
     24 #include "glsl/GrGLSLGeometryProcessor.h"
     25 #include "glsl/GrGLSLProgramDataManager.h"
     26 #include "glsl/GrGLSLXferProcessor.h"
     27 
     28 #define GL_CALL(X) GR_GL_CALL(this->gpu()->glInterface(), X)
     29 #define GL_CALL_RET(R, X) GR_GL_CALL_RET(this->gpu()->glInterface(), R, X)
     30 
     31 GrGLProgram* GrGLProgramBuilder::CreateProgram(const GrPipeline& pipeline,
     32                                                const GrPrimitiveProcessor& primProc,
     33                                                GrProgramDesc* desc,
     34                                                GrGLGpu* gpu) {
     35     SkASSERT(!pipeline.isBad() && primProc.instantiate(gpu->getContext()->resourceProvider()));
     36 
     37     ATRACE_ANDROID_FRAMEWORK("Shader Compile");
     38     GrAutoLocaleSetter als("C");
     39 
     40     // create a builder.  This will be handed off to effects so they can use it to add
     41     // uniforms, varyings, textures, etc
     42     GrGLProgramBuilder builder(gpu, pipeline, primProc, desc);
     43 
     44     if (!builder.emitAndInstallProcs()) {
     45         builder.cleanupFragmentProcessors();
     46         return nullptr;
     47     }
     48 
     49     return builder.finalize();
     50 }
     51 
     52 /////////////////////////////////////////////////////////////////////////////
     53 
     54 GrGLProgramBuilder::GrGLProgramBuilder(GrGLGpu* gpu,
     55                                        const GrPipeline& pipeline,
     56                                        const GrPrimitiveProcessor& primProc,
     57                                        GrProgramDesc* desc)
     58     : INHERITED(pipeline, primProc, desc)
     59     , fGpu(gpu)
     60     , fVaryingHandler(this)
     61     , fUniformHandler(this) {
     62 }
     63 
     64 const GrCaps* GrGLProgramBuilder::caps() const {
     65     return fGpu->caps();
     66 }
     67 
     68 bool GrGLProgramBuilder::compileAndAttachShaders(GrGLSLShaderBuilder& shader,
     69                                                  GrGLuint programId,
     70                                                  GrGLenum type,
     71                                                  SkTDArray<GrGLuint>* shaderIds,
     72                                                  const SkSL::Program::Settings& settings,
     73                                                  SkSL::Program::Inputs* outInputs) {
     74     GrGLGpu* gpu = this->gpu();
     75     GrGLuint shaderId = GrGLCompileAndAttachShader(gpu->glContext(),
     76                                                    programId,
     77                                                    type,
     78                                                    shader.fCompilerStrings.begin(),
     79                                                    shader.fCompilerStringLengths.begin(),
     80                                                    shader.fCompilerStrings.count(),
     81                                                    gpu->stats(),
     82                                                    settings,
     83                                                    outInputs);
     84 
     85     if (!shaderId) {
     86         return false;
     87     }
     88 
     89     *shaderIds->append() = shaderId;
     90     if (outInputs->fFlipY) {
     91         GrProgramDesc* d = this->desc();
     92         d->setSurfaceOriginKey(GrGLSLFragmentShaderBuilder::KeyForSurfaceOrigin(
     93                                                      this->pipeline().getRenderTarget()->origin()));
     94         d->finalize();
     95     }
     96 
     97     return true;
     98 }
     99 
    100 GrGLProgram* GrGLProgramBuilder::finalize() {
    101     TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("skia"), "GrGLProgramBuilder::finalize()");
    102 
    103     // verify we can get a program id
    104     GrGLuint programID;
    105     GL_CALL_RET(programID, CreateProgram());
    106     if (0 == programID) {
    107         this->cleanupFragmentProcessors();
    108         return nullptr;
    109     }
    110 
    111     this->finalizeShaders();
    112 
    113     // compile shaders and bind attributes / uniforms
    114     SkSL::Program::Settings settings;
    115     settings.fCaps = this->gpu()->glCaps().shaderCaps();
    116     settings.fFlipY = this->pipeline().getRenderTarget()->origin() != kTopLeft_GrSurfaceOrigin;
    117     SkSL::Program::Inputs inputs;
    118     SkTDArray<GrGLuint> shadersToDelete;
    119     if (!this->compileAndAttachShaders(fVS, programID, GR_GL_VERTEX_SHADER, &shadersToDelete,
    120                                        settings, &inputs)) {
    121         this->cleanupProgram(programID, shadersToDelete);
    122         return nullptr;
    123     }
    124 
    125     // NVPR actually requires a vertex shader to compile
    126     const GrPrimitiveProcessor& primProc = this->primitiveProcessor();
    127     bool useNvpr = primProc.isPathRendering();
    128     if (!useNvpr) {
    129         int vaCount = primProc.numAttribs();
    130         for (int i = 0; i < vaCount; i++) {
    131             GL_CALL(BindAttribLocation(programID, i, primProc.getAttrib(i).fName));
    132         }
    133     }
    134 
    135     if (primProc.willUseGeoShader() &&
    136         !this->compileAndAttachShaders(fGS, programID, GR_GL_GEOMETRY_SHADER, &shadersToDelete,
    137                                        settings, &inputs)) {
    138         this->cleanupProgram(programID, shadersToDelete);
    139         return nullptr;
    140     }
    141 
    142     if (!this->compileAndAttachShaders(fFS, programID, GR_GL_FRAGMENT_SHADER, &shadersToDelete,
    143                                        settings, &inputs)) {
    144         this->cleanupProgram(programID, shadersToDelete);
    145         return nullptr;
    146     }
    147 
    148     if (inputs.fRTHeight) {
    149         this->addRTHeightUniform(SKSL_RTHEIGHT_NAME);
    150     }
    151 
    152     this->bindProgramResourceLocations(programID);
    153 
    154     GL_CALL(LinkProgram(programID));
    155 
    156     // Calling GetProgramiv is expensive in Chromium. Assume success in release builds.
    157     bool checkLinked = kChromium_GrGLDriver != fGpu->ctxInfo().driver();
    158 #ifdef SK_DEBUG
    159     checkLinked = true;
    160 #endif
    161     if (checkLinked) {
    162         if (!this->checkLinkStatus(programID)) {
    163             SkDebugf("VS:\n");
    164             GrGLPrintShader(fGpu->glContext(), GR_GL_VERTEX_SHADER, fVS.fCompilerStrings.begin(),
    165                             fVS.fCompilerStringLengths.begin(), fVS.fCompilerStrings.count(),
    166                             settings);
    167             if (primProc.willUseGeoShader()) {
    168                 SkDebugf("\nGS:\n");
    169                 GrGLPrintShader(fGpu->glContext(), GR_GL_GEOMETRY_SHADER,
    170                                 fGS.fCompilerStrings.begin(), fGS.fCompilerStringLengths.begin(),
    171                                 fGS.fCompilerStrings.count(), settings);
    172             }
    173             SkDebugf("\nFS:\n");
    174             GrGLPrintShader(fGpu->glContext(), GR_GL_FRAGMENT_SHADER, fFS.fCompilerStrings.begin(),
    175                             fFS.fCompilerStringLengths.begin(), fFS.fCompilerStrings.count(),
    176                             settings);
    177             SkDEBUGFAIL("");
    178             return nullptr;
    179         }
    180     }
    181     this->resolveProgramResourceLocations(programID);
    182 
    183     this->cleanupShaders(shadersToDelete);
    184 
    185     return this->createProgram(programID);
    186 }
    187 
    188 void GrGLProgramBuilder::bindProgramResourceLocations(GrGLuint programID) {
    189     fUniformHandler.bindUniformLocations(programID, fGpu->glCaps());
    190 
    191     const GrGLCaps& caps = this->gpu()->glCaps();
    192     if (fFS.hasCustomColorOutput() && caps.bindFragDataLocationSupport()) {
    193         GL_CALL(BindFragDataLocation(programID, 0,
    194                                      GrGLSLFragmentShaderBuilder::DeclaredColorOutputName()));
    195     }
    196     if (fFS.hasSecondaryOutput() && caps.shaderCaps()->mustDeclareFragmentShaderOutput()) {
    197         GL_CALL(BindFragDataLocationIndexed(programID, 0, 1,
    198                                   GrGLSLFragmentShaderBuilder::DeclaredSecondaryColorOutputName()));
    199     }
    200 
    201     // handle NVPR separable varyings
    202     if (!fGpu->glCaps().shaderCaps()->pathRenderingSupport() ||
    203         !fGpu->glPathRendering()->shouldBindFragmentInputs()) {
    204         return;
    205     }
    206     int count = fVaryingHandler.fPathProcVaryingInfos.count();
    207     for (int i = 0; i < count; ++i) {
    208         GL_CALL(BindFragmentInputLocation(programID, i,
    209                                        fVaryingHandler.fPathProcVaryingInfos[i].fVariable.c_str()));
    210         fVaryingHandler.fPathProcVaryingInfos[i].fLocation = i;
    211     }
    212 }
    213 
    214 bool GrGLProgramBuilder::checkLinkStatus(GrGLuint programID) {
    215     GrGLint linked = GR_GL_INIT_ZERO;
    216     GL_CALL(GetProgramiv(programID, GR_GL_LINK_STATUS, &linked));
    217     if (!linked) {
    218         SkDebugf("Program linking failed.\n");
    219         GrGLint infoLen = GR_GL_INIT_ZERO;
    220         GL_CALL(GetProgramiv(programID, GR_GL_INFO_LOG_LENGTH, &infoLen));
    221         SkAutoMalloc log(sizeof(char)*(infoLen+1));  // outside if for debugger
    222         if (infoLen > 0) {
    223             // retrieve length even though we don't need it to workaround
    224             // bug in chrome cmd buffer param validation.
    225             GrGLsizei length = GR_GL_INIT_ZERO;
    226             GL_CALL(GetProgramInfoLog(programID,
    227                                       infoLen+1,
    228                                       &length,
    229                                       (char*)log.get()));
    230             SkDebugf("%s", (char*)log.get());
    231         }
    232         GL_CALL(DeleteProgram(programID));
    233         programID = 0;
    234     }
    235     return SkToBool(linked);
    236 }
    237 
    238 void GrGLProgramBuilder::resolveProgramResourceLocations(GrGLuint programID) {
    239     fUniformHandler.getUniformLocations(programID, fGpu->glCaps());
    240 
    241     // handle NVPR separable varyings
    242     if (!fGpu->glCaps().shaderCaps()->pathRenderingSupport() ||
    243         fGpu->glPathRendering()->shouldBindFragmentInputs()) {
    244         return;
    245     }
    246     int count = fVaryingHandler.fPathProcVaryingInfos.count();
    247     for (int i = 0; i < count; ++i) {
    248         GrGLint location;
    249         GL_CALL_RET(location, GetProgramResourceLocation(
    250                                        programID,
    251                                        GR_GL_FRAGMENT_INPUT,
    252                                        fVaryingHandler.fPathProcVaryingInfos[i].fVariable.c_str()));
    253         fVaryingHandler.fPathProcVaryingInfos[i].fLocation = location;
    254     }
    255 }
    256 
    257 void GrGLProgramBuilder::cleanupProgram(GrGLuint programID, const SkTDArray<GrGLuint>& shaderIDs) {
    258     GL_CALL(DeleteProgram(programID));
    259     this->cleanupShaders(shaderIDs);
    260     this->cleanupFragmentProcessors();
    261 }
    262 void GrGLProgramBuilder::cleanupShaders(const SkTDArray<GrGLuint>& shaderIDs) {
    263     for (int i = 0; i < shaderIDs.count(); ++i) {
    264       GL_CALL(DeleteShader(shaderIDs[i]));
    265     }
    266 }
    267 
    268 GrGLProgram* GrGLProgramBuilder::createProgram(GrGLuint programID) {
    269     return new GrGLProgram(fGpu,
    270                            *this->desc(),
    271                            fUniformHandles,
    272                            programID,
    273                            fUniformHandler.fUniforms,
    274                            fUniformHandler.fSamplers,
    275                            fUniformHandler.fTexelBuffers,
    276                            fUniformHandler.fImageStorages,
    277                            fVaryingHandler.fPathProcVaryingInfos,
    278                            fGeometryProcessor,
    279                            fXferProcessor,
    280                            fFragmentProcessors);
    281 }
    282