Home | History | Annotate | Download | only in glsl
      1 /*
      2  * Copyright 2015 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 "glsl/GrGLSLProgramBuilder.h"
      9 
     10 #include "GrPipeline.h"
     11 #include "glsl/GrGLSLFragmentProcessor.h"
     12 #include "glsl/GrGLSLGeometryProcessor.h"
     13 #include "glsl/GrGLSLVarying.h"
     14 #include "glsl/GrGLSLXferProcessor.h"
     15 
     16 const int GrGLSLProgramBuilder::kVarsPerBlock = 8;
     17 
     18 GrGLSLProgramBuilder::GrGLSLProgramBuilder(const DrawArgs& args)
     19     : fVS(this)
     20     , fGS(this)
     21     , fFS(this, args.fDesc->header().fFragPosKey)
     22     , fStageIndex(-1)
     23     , fArgs(args)
     24     , fGeometryProcessor(nullptr)
     25     , fXferProcessor(nullptr) {
     26 }
     27 
     28 bool GrGLSLProgramBuilder::emitAndInstallProcs(GrGLSLExpr4* inputColor,
     29                                                GrGLSLExpr4* inputCoverage,
     30                                                int maxTextures) {
     31     // First we loop over all of the installed processors and collect coord transforms.  These will
     32     // be sent to the GrGLSLPrimitiveProcessor in its emitCode function
     33     const GrPrimitiveProcessor& primProc = this->primitiveProcessor();
     34     int totalTextures = primProc.numTextures();
     35 
     36     for (int i = 0; i < this->pipeline().numFragmentProcessors(); i++) {
     37         const GrFragmentProcessor& processor = this->pipeline().getFragmentProcessor(i);
     38 
     39         if (!primProc.hasTransformedLocalCoords()) {
     40             SkTArray<const GrCoordTransform*, true>& procCoords = fCoordTransforms.push_back();
     41             processor.gatherCoordTransforms(&procCoords);
     42         }
     43 
     44         totalTextures += processor.numTextures();
     45         if (totalTextures >= maxTextures) {
     46             GrCapsDebugf(this->caps(), "Program would use too many texture units\n");
     47             return false;
     48         }
     49     }
     50 
     51     this->emitAndInstallPrimProc(primProc, inputColor, inputCoverage);
     52 
     53     int numProcs = this->pipeline().numFragmentProcessors();
     54     this->emitAndInstallFragProcs(0, this->pipeline().numColorFragmentProcessors(), inputColor);
     55     this->emitAndInstallFragProcs(this->pipeline().numColorFragmentProcessors(), numProcs,
     56                                   inputCoverage);
     57     if (primProc.getPixelLocalStorageState() !=
     58         GrPixelLocalStorageState::kDraw_GrPixelLocalStorageState) {
     59         this->emitAndInstallXferProc(this->pipeline().getXferProcessor(), *inputColor,
     60                                      *inputCoverage, this->pipeline().ignoresCoverage(),
     61                                      primProc.getPixelLocalStorageState());
     62         this->emitFSOutputSwizzle(this->pipeline().getXferProcessor().hasSecondaryOutput());
     63     }
     64     return true;
     65 }
     66 
     67 void GrGLSLProgramBuilder::emitAndInstallPrimProc(const GrPrimitiveProcessor& proc,
     68                                                   GrGLSLExpr4* outputColor,
     69                                                   GrGLSLExpr4* outputCoverage) {
     70     // Program builders have a bit of state we need to clear with each effect
     71     AutoStageAdvance adv(this);
     72     this->nameExpression(outputColor, "outputColor");
     73     this->nameExpression(outputCoverage, "outputCoverage");
     74 
     75     // Enclose custom code in a block to avoid namespace conflicts
     76     SkString openBrace;
     77     openBrace.printf("{ // Stage %d, %s\n", fStageIndex, proc.name());
     78     fFS.codeAppend(openBrace.c_str());
     79     fVS.codeAppendf("// Primitive Processor %s\n", proc.name());
     80 
     81     SkASSERT(!fGeometryProcessor);
     82     fGeometryProcessor = proc.createGLSLInstance(*this->glslCaps());
     83 
     84     SkSTArray<4, GrGLSLTextureSampler> samplers(proc.numTextures());
     85     this->emitSamplers(proc, &samplers);
     86 
     87     GrGLSLGeometryProcessor::EmitArgs args(&fVS,
     88                                            &fFS,
     89                                            this->varyingHandler(),
     90                                            this->uniformHandler(),
     91                                            this->glslCaps(),
     92                                            proc,
     93                                            outputColor->c_str(),
     94                                            outputCoverage->c_str(),
     95                                            samplers,
     96                                            fCoordTransforms,
     97                                            &fOutCoords);
     98     fGeometryProcessor->emitCode(args);
     99 
    100     // We have to check that effects and the code they emit are consistent, ie if an effect
    101     // asks for dst color, then the emit code needs to follow suit
    102     verify(proc);
    103 
    104     fFS.codeAppend("}");
    105 }
    106 
    107 void GrGLSLProgramBuilder::emitAndInstallFragProcs(int procOffset,
    108                                                    int numProcs,
    109                                                    GrGLSLExpr4* inOut) {
    110     for (int i = procOffset; i < numProcs; ++i) {
    111         GrGLSLExpr4 output;
    112         const GrFragmentProcessor& fp = this->pipeline().getFragmentProcessor(i);
    113         this->emitAndInstallFragProc(fp, i, *inOut, &output);
    114         *inOut = output;
    115     }
    116 }
    117 
    118 // TODO Processors cannot output zeros because an empty string is all 1s
    119 // the fix is to allow effects to take the GrGLSLExpr4 directly
    120 void GrGLSLProgramBuilder::emitAndInstallFragProc(const GrFragmentProcessor& fp,
    121                                                   int index,
    122                                                   const GrGLSLExpr4& input,
    123                                                   GrGLSLExpr4* output) {
    124     // Program builders have a bit of state we need to clear with each effect
    125     AutoStageAdvance adv(this);
    126     this->nameExpression(output, "output");
    127 
    128     // Enclose custom code in a block to avoid namespace conflicts
    129     SkString openBrace;
    130     openBrace.printf("{ // Stage %d, %s\n", fStageIndex, fp.name());
    131     fFS.codeAppend(openBrace.c_str());
    132 
    133     GrGLSLFragmentProcessor* fragProc = fp.createGLSLInstance();
    134 
    135     SkSTArray<4, GrGLSLTextureSampler> samplers(fp.numTextures());
    136     this->emitSamplers(fp, &samplers);
    137 
    138     GrGLSLFragmentProcessor::EmitArgs args(&fFS,
    139                                            this->uniformHandler(),
    140                                            this->glslCaps(),
    141                                            fp,
    142                                            output->c_str(),
    143                                            input.isOnes() ? nullptr : input.c_str(),
    144                                            fOutCoords[index],
    145                                            samplers);
    146     fragProc->emitCode(args);
    147 
    148     // We have to check that effects and the code they emit are consistent, ie if an effect
    149     // asks for dst color, then the emit code needs to follow suit
    150     verify(fp);
    151     fFragmentProcessors.push_back(fragProc);
    152 
    153     fFS.codeAppend("}");
    154 }
    155 
    156 void GrGLSLProgramBuilder::emitAndInstallXferProc(const GrXferProcessor& xp,
    157                                                   const GrGLSLExpr4& colorIn,
    158                                                   const GrGLSLExpr4& coverageIn,
    159                                                   bool ignoresCoverage,
    160                                                   GrPixelLocalStorageState plsState) {
    161     // Program builders have a bit of state we need to clear with each effect
    162     AutoStageAdvance adv(this);
    163 
    164     SkASSERT(!fXferProcessor);
    165     fXferProcessor = xp.createGLSLInstance();
    166 
    167     // Enable dual source secondary output if we have one
    168     if (xp.hasSecondaryOutput()) {
    169         fFS.enableSecondaryOutput();
    170     }
    171 
    172     if (this->glslCaps()->mustDeclareFragmentShaderOutput()) {
    173         fFS.enableCustomOutput();
    174     }
    175 
    176     SkString openBrace;
    177     openBrace.printf("{ // Xfer Processor: %s\n", xp.name());
    178     fFS.codeAppend(openBrace.c_str());
    179 
    180     SkSTArray<4, GrGLSLTextureSampler> samplers(xp.numTextures());
    181     this->emitSamplers(xp, &samplers);
    182 
    183     bool usePLSDstRead = (plsState == GrPixelLocalStorageState::kFinish_GrPixelLocalStorageState);
    184     GrGLSLXferProcessor::EmitArgs args(&fFS,
    185                                        this->uniformHandler(),
    186                                        this->glslCaps(),
    187                                        xp, colorIn.c_str(),
    188                                        ignoresCoverage ? nullptr : coverageIn.c_str(),
    189                                        fFS.getPrimaryColorOutputName(),
    190                                        fFS.getSecondaryColorOutputName(),
    191                                        samplers,
    192                                        usePLSDstRead);
    193     fXferProcessor->emitCode(args);
    194 
    195     // We have to check that effects and the code they emit are consistent, ie if an effect
    196     // asks for dst color, then the emit code needs to follow suit
    197     verify(xp);
    198     fFS.codeAppend("}");
    199 }
    200 
    201 void GrGLSLProgramBuilder::emitFSOutputSwizzle(bool hasSecondaryOutput) {
    202     // Swizzle the fragment shader outputs if necessary.
    203     GrSwizzle swizzle;
    204     swizzle.setFromKey(this->desc().header().fOutputSwizzle);
    205     if (swizzle != GrSwizzle::RGBA()) {
    206         fFS.codeAppendf("%s = %s.%s;", fFS.getPrimaryColorOutputName(),
    207                         fFS.getPrimaryColorOutputName(),
    208                         swizzle.c_str());
    209         if (hasSecondaryOutput) {
    210             fFS.codeAppendf("%s = %s.%s;", fFS.getSecondaryColorOutputName(),
    211                             fFS.getSecondaryColorOutputName(),
    212                             swizzle.c_str());
    213         }
    214     }
    215 }
    216 
    217 void GrGLSLProgramBuilder::verify(const GrPrimitiveProcessor& gp) {
    218     SkASSERT(fFS.hasReadFragmentPosition() == gp.willReadFragmentPosition());
    219 }
    220 
    221 void GrGLSLProgramBuilder::verify(const GrXferProcessor& xp) {
    222     SkASSERT(fFS.hasReadDstColor() == xp.willReadDstColor());
    223 }
    224 
    225 void GrGLSLProgramBuilder::verify(const GrFragmentProcessor& fp) {
    226     SkASSERT(fFS.hasReadFragmentPosition() == fp.willReadFragmentPosition());
    227 }
    228 
    229 void GrGLSLProgramBuilder::nameVariable(SkString* out, char prefix, const char* name, bool mangle) {
    230     if ('\0' == prefix) {
    231         *out = name;
    232     } else {
    233         out->printf("%c%s", prefix, name);
    234     }
    235     if (mangle) {
    236         if (out->endsWith('_')) {
    237             // Names containing "__" are reserved.
    238             out->append("x");
    239         }
    240         out->appendf("_Stage%d%s", fStageIndex, fFS.getMangleString().c_str());
    241     }
    242 }
    243 
    244 void GrGLSLProgramBuilder::nameExpression(GrGLSLExpr4* output, const char* baseName) {
    245     // create var to hold stage result.  If we already have a valid output name, just use that
    246     // otherwise create a new mangled one.  This name is only valid if we are reordering stages
    247     // and have to tell stage exactly where to put its output.
    248     SkString outName;
    249     if (output->isValid()) {
    250         outName = output->c_str();
    251     } else {
    252         this->nameVariable(&outName, '\0', baseName);
    253     }
    254     fFS.codeAppendf("vec4 %s;", outName.c_str());
    255     *output = outName;
    256 }
    257 
    258 void GrGLSLProgramBuilder::appendUniformDecls(GrShaderFlags visibility, SkString* out) const {
    259     this->uniformHandler()->appendUniformDecls(visibility, out);
    260 }
    261 
    262 void GrGLSLProgramBuilder::addRTAdjustmentUniform(GrSLPrecision precision,
    263                                                   const char* name,
    264                                                   const char** outName) {
    265         SkASSERT(!fUniformHandles.fRTAdjustmentUni.isValid());
    266         fUniformHandles.fRTAdjustmentUni =
    267             this->uniformHandler()->addUniform(kVertex_GrShaderFlag,
    268                                                kVec4f_GrSLType,
    269                                                precision,
    270                                                name,
    271                                                outName);
    272 }
    273 
    274 void GrGLSLProgramBuilder::addRTHeightUniform(const char* name, const char** outName) {
    275         SkASSERT(!fUniformHandles.fRTHeightUni.isValid());
    276         GrGLSLUniformHandler* uniformHandler = this->uniformHandler();
    277         fUniformHandles.fRTHeightUni =
    278             uniformHandler->internalAddUniformArray(kFragment_GrShaderFlag,
    279                                                     kFloat_GrSLType, kDefault_GrSLPrecision,
    280                                                     name, false, 0, outName);
    281 }
    282 
    283 void GrGLSLProgramBuilder::cleanupFragmentProcessors() {
    284     for (int i = 0; i < fFragmentProcessors.count(); ++i) {
    285         delete fFragmentProcessors[i];
    286     }
    287 }
    288 
    289 void GrGLSLProgramBuilder::finalizeShaders() {
    290     this->varyingHandler()->finalize();
    291     fVS.finalize(kVertex_GrShaderFlag);
    292     fFS.finalize(kFragment_GrShaderFlag);
    293 
    294 }
    295