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