Home | History | Annotate | Download | only in gl
      1 /*
      2  * Copyright 2013 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 "GrGLProgramDesc.h"
      9 #include "GrBackendEffectFactory.h"
     10 #include "GrDrawEffect.h"
     11 #include "GrEffect.h"
     12 #include "GrGLShaderBuilder.h"
     13 #include "GrGpuGL.h"
     14 
     15 #include "SkChecksum.h"
     16 
     17 namespace {
     18 inline GrGLEffect::EffectKey get_key_and_update_stats(const GrEffectStage& stage,
     19                                                       const GrGLCaps& caps,
     20                                                       bool useExplicitLocalCoords,
     21                                                       bool* setTrueIfReadsDst,
     22                                                       bool* setTrueIfReadsPos,
     23                                                       bool* setTrueIfHasVertexCode) {
     24     const GrEffectRef& effect = *stage.getEffect();
     25     const GrBackendEffectFactory& factory = effect->getFactory();
     26     GrDrawEffect drawEffect(stage, useExplicitLocalCoords);
     27     if (effect->willReadDstColor()) {
     28         *setTrueIfReadsDst = true;
     29     }
     30     if (effect->willReadFragmentPosition()) {
     31         *setTrueIfReadsPos = true;
     32     }
     33     if (effect->hasVertexCode()) {
     34         *setTrueIfHasVertexCode = true;
     35     }
     36     return factory.glEffectKey(drawEffect, caps);
     37 }
     38 }
     39 void GrGLProgramDesc::Build(const GrDrawState& drawState,
     40                             bool isPoints,
     41                             GrDrawState::BlendOptFlags blendOpts,
     42                             GrBlendCoeff srcCoeff,
     43                             GrBlendCoeff dstCoeff,
     44                             const GrGpuGL* gpu,
     45                             const GrDeviceCoordTexture* dstCopy,
     46                             SkTArray<const GrEffectStage*, true>* colorStages,
     47                             SkTArray<const GrEffectStage*, true>* coverageStages,
     48                             GrGLProgramDesc* desc) {
     49     colorStages->reset();
     50     coverageStages->reset();
     51 
     52     // This should already have been caught
     53     SkASSERT(!(GrDrawState::kSkipDraw_BlendOptFlag & blendOpts));
     54 
     55     bool skipCoverage = SkToBool(blendOpts & GrDrawState::kEmitTransBlack_BlendOptFlag);
     56 
     57     bool skipColor = SkToBool(blendOpts & (GrDrawState::kEmitTransBlack_BlendOptFlag |
     58                                            GrDrawState::kEmitCoverage_BlendOptFlag));
     59     int firstEffectiveColorStage = 0;
     60     bool inputColorIsUsed = true;
     61     if (!skipColor) {
     62         firstEffectiveColorStage = drawState.numColorStages();
     63         while (firstEffectiveColorStage > 0 && inputColorIsUsed) {
     64             --firstEffectiveColorStage;
     65             const GrEffect* effect = drawState.getColorStage(firstEffectiveColorStage).getEffect()->get();
     66             inputColorIsUsed = effect->willUseInputColor();
     67         }
     68     }
     69 
     70     int firstEffectiveCoverageStage = 0;
     71     bool inputCoverageIsUsed = true;
     72     if (!skipCoverage) {
     73         firstEffectiveCoverageStage = drawState.numCoverageStages();
     74         while (firstEffectiveCoverageStage > 0 && inputCoverageIsUsed) {
     75             --firstEffectiveCoverageStage;
     76             const GrEffect* effect = drawState.getCoverageStage(firstEffectiveCoverageStage).getEffect()->get();
     77             inputCoverageIsUsed = effect->willUseInputColor();
     78         }
     79     }
     80 
     81     // The descriptor is used as a cache key. Thus when a field of the
     82     // descriptor will not affect program generation (because of the attribute
     83     // bindings in use or other descriptor field settings) it should be set
     84     // to a canonical value to avoid duplicate programs with different keys.
     85 
     86     bool requiresColorAttrib = !skipColor && drawState.hasColorVertexAttribute();
     87     bool requiresCoverageAttrib = !skipCoverage && drawState.hasCoverageVertexAttribute();
     88     // we only need the local coords if we're actually going to generate effect code
     89     bool requiresLocalCoordAttrib = !(skipCoverage  && skipColor) &&
     90                                     drawState.hasLocalCoordAttribute();
     91 
     92     bool colorIsTransBlack = SkToBool(blendOpts & GrDrawState::kEmitTransBlack_BlendOptFlag);
     93     bool colorIsSolidWhite = (blendOpts & GrDrawState::kEmitCoverage_BlendOptFlag) ||
     94                              (!requiresColorAttrib && 0xffffffff == drawState.getColor()) ||
     95                              (!inputColorIsUsed);
     96 
     97     int numEffects = (skipColor ? 0 : (drawState.numColorStages() - firstEffectiveColorStage)) +
     98                      (skipCoverage ? 0 : (drawState.numCoverageStages() - firstEffectiveCoverageStage));
     99 
    100     size_t newKeyLength = KeyLength(numEffects);
    101     bool allocChanged;
    102     desc->fKey.reset(newKeyLength, SkAutoMalloc::kAlloc_OnShrink, &allocChanged);
    103     if (allocChanged || !desc->fInitialized) {
    104         // make sure any padding in the header is zero if we we haven't used this allocation before.
    105         memset(desc->header(), 0, kHeaderSize);
    106     }
    107     // write the key length
    108     *desc->atOffset<uint32_t, kLengthOffset>() = SkToU32(newKeyLength);
    109 
    110     KeyHeader* header = desc->header();
    111     EffectKey* effectKeys = desc->effectKeys();
    112 
    113     int currEffectKey = 0;
    114     bool readsDst = false;
    115     bool readFragPosition = false;
    116     bool hasVertexCode = false;
    117     if (!skipColor) {
    118         for (int s = firstEffectiveColorStage; s < drawState.numColorStages(); ++s) {
    119             effectKeys[currEffectKey++] =
    120                 get_key_and_update_stats(drawState.getColorStage(s), gpu->glCaps(),
    121                                          requiresLocalCoordAttrib, &readsDst, &readFragPosition,
    122                                          &hasVertexCode);
    123         }
    124     }
    125     if (!skipCoverage) {
    126         for (int s = firstEffectiveCoverageStage; s < drawState.numCoverageStages(); ++s) {
    127             effectKeys[currEffectKey++] =
    128                 get_key_and_update_stats(drawState.getCoverageStage(s), gpu->glCaps(),
    129                                          requiresLocalCoordAttrib, &readsDst, &readFragPosition,
    130                                          &hasVertexCode);
    131         }
    132     }
    133 
    134     header->fHasVertexCode = hasVertexCode || requiresLocalCoordAttrib;
    135     header->fEmitsPointSize = isPoints;
    136 
    137     // Currently the experimental GS will only work with triangle prims (and it doesn't do anything
    138     // other than pass through values from the VS to the FS anyway).
    139 #if GR_GL_EXPERIMENTAL_GS
    140 #if 0
    141     header->fExperimentalGS = gpu->caps().geometryShaderSupport();
    142 #else
    143     header->fExperimentalGS = false;
    144 #endif
    145 #endif
    146     bool defaultToUniformInputs = GR_GL_NO_CONSTANT_ATTRIBUTES || gpu->caps()->pathRenderingSupport();
    147 
    148     if (colorIsTransBlack) {
    149         header->fColorInput = kTransBlack_ColorInput;
    150     } else if (colorIsSolidWhite) {
    151         header->fColorInput = kSolidWhite_ColorInput;
    152     } else if (defaultToUniformInputs && !requiresColorAttrib) {
    153         header->fColorInput = kUniform_ColorInput;
    154     } else {
    155         header->fColorInput = kAttribute_ColorInput;
    156         header->fHasVertexCode = true;
    157     }
    158 
    159     bool covIsSolidWhite = !requiresCoverageAttrib && 0xffffffff == drawState.getCoverageColor();
    160 
    161     if (skipCoverage) {
    162         header->fCoverageInput = kTransBlack_ColorInput;
    163     } else if (covIsSolidWhite || !inputCoverageIsUsed) {
    164         header->fCoverageInput = kSolidWhite_ColorInput;
    165     } else if (defaultToUniformInputs && !requiresCoverageAttrib) {
    166         header->fCoverageInput = kUniform_ColorInput;
    167     } else {
    168         header->fCoverageInput = kAttribute_ColorInput;
    169         header->fHasVertexCode = true;
    170     }
    171 
    172     if (readsDst) {
    173         SkASSERT(NULL != dstCopy || gpu->caps()->dstReadInShaderSupport());
    174         const GrTexture* dstCopyTexture = NULL;
    175         if (NULL != dstCopy) {
    176             dstCopyTexture = dstCopy->texture();
    177         }
    178         header->fDstReadKey = GrGLShaderBuilder::KeyForDstRead(dstCopyTexture, gpu->glCaps());
    179         SkASSERT(0 != header->fDstReadKey);
    180     } else {
    181         header->fDstReadKey = 0;
    182     }
    183 
    184     if (readFragPosition) {
    185         header->fFragPosKey = GrGLShaderBuilder::KeyForFragmentPosition(drawState.getRenderTarget(),
    186                                                                       gpu->glCaps());
    187     } else {
    188         header->fFragPosKey = 0;
    189     }
    190 
    191     // Record attribute indices
    192     header->fPositionAttributeIndex = drawState.positionAttributeIndex();
    193     header->fLocalCoordAttributeIndex = drawState.localCoordAttributeIndex();
    194 
    195     // For constant color and coverage we need an attribute with an index beyond those already set
    196     int availableAttributeIndex = drawState.getVertexAttribCount();
    197     if (requiresColorAttrib) {
    198         header->fColorAttributeIndex = drawState.colorVertexAttributeIndex();
    199     } else if (GrGLProgramDesc::kAttribute_ColorInput == header->fColorInput) {
    200         SkASSERT(availableAttributeIndex < GrDrawState::kMaxVertexAttribCnt);
    201         header->fColorAttributeIndex = availableAttributeIndex;
    202         availableAttributeIndex++;
    203     } else {
    204         header->fColorAttributeIndex = -1;
    205     }
    206 
    207     if (requiresCoverageAttrib) {
    208         header->fCoverageAttributeIndex = drawState.coverageVertexAttributeIndex();
    209     } else if (GrGLProgramDesc::kAttribute_ColorInput == header->fCoverageInput) {
    210         SkASSERT(availableAttributeIndex < GrDrawState::kMaxVertexAttribCnt);
    211         header->fCoverageAttributeIndex = availableAttributeIndex;
    212     } else {
    213         header->fCoverageAttributeIndex = -1;
    214     }
    215 
    216     // Here we deal with whether/how we handle color and coverage separately.
    217 
    218     // Set these defaults and then possibly change our mind if there is coverage.
    219     header->fDiscardIfZeroCoverage = false;
    220     header->fCoverageOutput = kModulate_CoverageOutput;
    221 
    222     // If we do have coverage determine whether it matters.
    223     bool separateCoverageFromColor = false;
    224     if (!drawState.isCoverageDrawing() && !skipCoverage &&
    225         (drawState.numCoverageStages() > 0 || requiresCoverageAttrib)) {
    226 
    227         // If we're stenciling then we want to discard samples that have zero coverage
    228         if (drawState.getStencil().doesWrite()) {
    229             header->fDiscardIfZeroCoverage = true;
    230             separateCoverageFromColor = true;
    231         }
    232 
    233         if (gpu->caps()->dualSourceBlendingSupport() &&
    234             !(blendOpts & (GrDrawState::kEmitCoverage_BlendOptFlag |
    235                            GrDrawState::kCoverageAsAlpha_BlendOptFlag))) {
    236             if (kZero_GrBlendCoeff == dstCoeff) {
    237                 // write the coverage value to second color
    238                 header->fCoverageOutput =  kSecondaryCoverage_CoverageOutput;
    239                 separateCoverageFromColor = true;
    240             } else if (kSA_GrBlendCoeff == dstCoeff) {
    241                 // SA dst coeff becomes 1-(1-SA)*coverage when dst is partially covered.
    242                 header->fCoverageOutput = kSecondaryCoverageISA_CoverageOutput;
    243                 separateCoverageFromColor = true;
    244             } else if (kSC_GrBlendCoeff == dstCoeff) {
    245                 // SA dst coeff becomes 1-(1-SA)*coverage when dst is partially covered.
    246                 header->fCoverageOutput = kSecondaryCoverageISC_CoverageOutput;
    247                 separateCoverageFromColor = true;
    248             }
    249         } else if (readsDst &&
    250                    kOne_GrBlendCoeff == srcCoeff &&
    251                    kZero_GrBlendCoeff == dstCoeff) {
    252             header->fCoverageOutput = kCombineWithDst_CoverageOutput;
    253             separateCoverageFromColor = true;
    254         }
    255     }
    256     if (!skipColor) {
    257         for (int s = firstEffectiveColorStage; s < drawState.numColorStages(); ++s) {
    258             colorStages->push_back(&drawState.getColorStage(s));
    259         }
    260     }
    261     if (!skipCoverage) {
    262         SkTArray<const GrEffectStage*, true>* array;
    263         if (separateCoverageFromColor) {
    264             array = coverageStages;
    265         } else {
    266             array = colorStages;
    267         }
    268         for (int s = firstEffectiveCoverageStage; s < drawState.numCoverageStages(); ++s) {
    269             array->push_back(&drawState.getCoverageStage(s));
    270         }
    271     }
    272     header->fColorEffectCnt = colorStages->count();
    273     header->fCoverageEffectCnt = coverageStages->count();
    274 
    275     *desc->checksum() = 0;
    276     *desc->checksum() = SkChecksum::Compute(reinterpret_cast<uint32_t*>(desc->fKey.get()),
    277                                             newKeyLength);
    278     desc->fInitialized = true;
    279 }
    280 
    281 GrGLProgramDesc& GrGLProgramDesc::operator= (const GrGLProgramDesc& other) {
    282     fInitialized = other.fInitialized;
    283     if (fInitialized) {
    284         size_t keyLength = other.keyLength();
    285         fKey.reset(keyLength);
    286         memcpy(fKey.get(), other.fKey.get(), keyLength);
    287     }
    288     return *this;
    289 }
    290