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 "GrOptDrawState.h"
9
10#include "GrDrawState.h"
11#include "GrDrawTargetCaps.h"
12#include "GrGpu.h"
13
14GrOptDrawState::GrOptDrawState(const GrDrawState& drawState,
15                               BlendOptFlags blendOptFlags,
16                               GrBlendCoeff optSrcCoeff,
17                               GrBlendCoeff optDstCoeff,
18                               const GrDrawTargetCaps& caps) : INHERITED(drawState) {
19    fColor = drawState.getColor();
20    fCoverage = drawState.getCoverage();
21    fViewMatrix = drawState.getViewMatrix();
22    fBlendConstant = drawState.getBlendConstant();
23    fFlagBits = drawState.getFlagBits();
24    fVAPtr = drawState.getVertexAttribs();
25    fVACount = drawState.getVertexAttribCount();
26    fVAStride = drawState.getVertexStride();
27    fStencilSettings = drawState.getStencil();
28    fDrawFace = drawState.getDrawFace();
29    fBlendOptFlags = blendOptFlags;
30    fSrcBlend = optSrcCoeff;
31    fDstBlend = optDstCoeff;
32
33    memcpy(fFixedFunctionVertexAttribIndices,
34            drawState.getFixedFunctionVertexAttribIndices(),
35            sizeof(fFixedFunctionVertexAttribIndices));
36
37
38    fInputColorIsUsed = true;
39    fInputCoverageIsUsed = true;
40
41    if (drawState.hasGeometryProcessor()) {
42        fGeometryProcessor.reset(SkNEW_ARGS(GrGeometryStage, (*drawState.getGeometryProcessor())));
43    } else {
44        fGeometryProcessor.reset(NULL);
45    }
46
47    this->copyEffectiveColorStages(drawState);
48    this->copyEffectiveCoverageStages(drawState);
49    this->adjustFromBlendOpts();
50    this->getStageStats();
51    this->setOutputStateInfo(caps);
52};
53
54void GrOptDrawState::setOutputStateInfo(const GrDrawTargetCaps& caps) {
55    // Set this default and then possibly change our mind if there is coverage.
56    fPrimaryOutputType = kModulate_PrimaryOutputType;
57    fSecondaryOutputType = kNone_SecondaryOutputType;
58
59    // If we do have coverage determine whether it matters.
60    bool separateCoverageFromColor = this->hasGeometryProcessor();
61    if (!this->isCoverageDrawing() &&
62        (this->numCoverageStages() > 0 ||
63         this->hasGeometryProcessor() ||
64         this->hasCoverageVertexAttribute())) {
65
66        if (caps.dualSourceBlendingSupport()) {
67            if (kZero_GrBlendCoeff == fDstBlend) {
68                // write the coverage value to second color
69                fSecondaryOutputType =  kCoverage_SecondaryOutputType;
70                separateCoverageFromColor = true;
71                fDstBlend = (GrBlendCoeff)GrGpu::kIS2C_GrBlendCoeff;
72            } else if (kSA_GrBlendCoeff == fDstBlend) {
73                // SA dst coeff becomes 1-(1-SA)*coverage when dst is partially covered.
74                fSecondaryOutputType = kCoverageISA_SecondaryOutputType;
75                separateCoverageFromColor = true;
76                fDstBlend = (GrBlendCoeff)GrGpu::kIS2C_GrBlendCoeff;
77            } else if (kSC_GrBlendCoeff == fDstBlend) {
78                // SA dst coeff becomes 1-(1-SA)*coverage when dst is partially covered.
79                fSecondaryOutputType = kCoverageISC_SecondaryOutputType;
80                separateCoverageFromColor = true;
81                fDstBlend = (GrBlendCoeff)GrGpu::kIS2C_GrBlendCoeff;
82            }
83        } else if (fReadsDst &&
84                   kOne_GrBlendCoeff == fSrcBlend &&
85                   kZero_GrBlendCoeff == fDstBlend) {
86            fPrimaryOutputType = kCombineWithDst_PrimaryOutputType;
87            separateCoverageFromColor = true;
88        }
89    }
90
91    // TODO: Once we have flag to know if we only multiply on stages, only push coverage into color
92    // stages if everything is multipy
93    if (!separateCoverageFromColor) {
94        for (int s = 0; s < this->numCoverageStages(); ++s) {
95            fColorStages.push_back(this->getCoverageStage(s));
96        }
97        fCoverageStages.reset();
98    }
99}
100
101void GrOptDrawState::adjustFromBlendOpts() {
102
103    switch (fBlendOptFlags) {
104        case kNone_BlendOpt:
105        case kSkipDraw_BlendOptFlag:
106            break;
107        case kCoverageAsAlpha_BlendOptFlag:
108            fFlagBits |= kCoverageDrawing_StateBit;
109            break;
110        case kEmitCoverage_BlendOptFlag:
111            fColor = 0xffffffff;
112            fInputColorIsUsed = true;
113            fColorStages.reset();
114            this->removeFixedFunctionVertexAttribs(0x1 << kColor_GrVertexAttribBinding);
115            break;
116        case kEmitTransBlack_BlendOptFlag:
117            fColor = 0;
118            fCoverage = 0xff;
119            fInputColorIsUsed = true;
120            fInputCoverageIsUsed = true;
121            fColorStages.reset();
122            fCoverageStages.reset();
123            this->removeFixedFunctionVertexAttribs(0x1 << kColor_GrVertexAttribBinding |
124                                                   0x1 << kCoverage_GrVertexAttribBinding);
125            break;
126        default:
127            SkFAIL("Unknown BlendOptFlag");
128
129    }
130}
131
132void GrOptDrawState::removeFixedFunctionVertexAttribs(uint8_t removeVAFlag) {
133    int numToRemove = 0;
134    uint8_t maskCheck = 0x1;
135    // Count the number of vertex attributes that we will actually remove
136    for (int i = 0; i < kGrFixedFunctionVertexAttribBindingCnt; ++i) {
137        if ((maskCheck & removeVAFlag) && -1 != fFixedFunctionVertexAttribIndices[i]) {
138            ++numToRemove;
139        }
140        maskCheck <<= 1;
141    }
142
143    fOptVA.reset(fVACount - numToRemove);
144
145    GrVertexAttrib* dst = fOptVA.get();
146    const GrVertexAttrib* src = fVAPtr;
147
148    for (int i = 0, newIdx = 0; i < fVACount; ++i, ++src) {
149        const GrVertexAttrib& currAttrib = *src;
150        if (currAttrib.fBinding < kGrFixedFunctionVertexAttribBindingCnt) {
151            uint8_t maskCheck = 0x1 << currAttrib.fBinding;
152            if (maskCheck & removeVAFlag) {
153                SkASSERT(-1 != fFixedFunctionVertexAttribIndices[currAttrib.fBinding]);
154                fFixedFunctionVertexAttribIndices[currAttrib.fBinding] = -1;
155                continue;
156            }
157            fFixedFunctionVertexAttribIndices[currAttrib.fBinding] = newIdx;
158        }
159        memcpy(dst, src, sizeof(GrVertexAttrib));
160        ++newIdx;
161        ++dst;
162    }
163    fVACount -= numToRemove;
164    fVAPtr = fOptVA.get();
165}
166
167void GrOptDrawState::copyEffectiveColorStages(const GrDrawState& ds) {
168    int firstColorStage = 0;
169
170    // Set up color and flags for ConstantColorComponent checks
171    GrColor color;
172    uint32_t validComponentFlags;
173    if (!this->hasColorVertexAttribute()) {
174        color = ds.getColor();
175        validComponentFlags = kRGBA_GrColorComponentFlags;
176    } else {
177        if (ds.vertexColorsAreOpaque()) {
178            color = 0xFF << GrColor_SHIFT_A;
179            validComponentFlags = kA_GrColorComponentFlag;
180        } else {
181            validComponentFlags = 0;
182            color = 0; // not strictly necessary but we get false alarms from tools about uninit.
183        }
184    }
185
186    for (int i = 0; i < ds.numColorStages(); ++i) {
187        const GrFragmentProcessor* fp = ds.getColorStage(i).getFragmentProcessor();
188        if (!fp->willUseInputColor()) {
189            firstColorStage = i;
190            fInputColorIsUsed = false;
191        }
192        fp->getConstantColorComponents(&color, &validComponentFlags);
193        if (kRGBA_GrColorComponentFlags == validComponentFlags) {
194            firstColorStage = i + 1;
195            fColor = color;
196            fInputColorIsUsed = true;
197            this->removeFixedFunctionVertexAttribs(0x1 << kColor_GrVertexAttribBinding);
198        }
199    }
200    if (firstColorStage < ds.numColorStages()) {
201        fColorStages.reset(&ds.getColorStage(firstColorStage),
202                           ds.numColorStages() - firstColorStage);
203    } else {
204        fColorStages.reset();
205    }
206}
207
208void GrOptDrawState::copyEffectiveCoverageStages(const GrDrawState& ds) {
209    int firstCoverageStage = 0;
210
211    // We do not try to optimize out constantColor coverage effects here. It is extremely rare
212    // to have a coverage effect that returns a constant value for all four channels. Thus we
213    // save having to make extra virtual calls by not checking for it.
214
215    // Don't do any optimizations on coverage stages. It should not be the case where we do not use
216    // input coverage in an effect
217#ifdef OptCoverageStages
218    for (int i = 0; i < ds.numCoverageStages(); ++i) {
219        const GrProcessor* processor = ds.getCoverageStage(i).getProcessor();
220        if (!processor->willUseInputColor()) {
221            firstCoverageStage = i;
222            fInputCoverageIsUsed = false;
223        }
224    }
225#endif
226    if (ds.numCoverageStages() > 0) {
227        fCoverageStages.reset(&ds.getCoverageStage(firstCoverageStage),
228                              ds.numCoverageStages() - firstCoverageStage);
229    } else {
230        fCoverageStages.reset();
231    }
232}
233
234static void get_stage_stats(const GrFragmentStage& stage, bool* readsDst, bool* readsFragPosition) {
235    if (stage.getFragmentProcessor()->willReadDstColor()) {
236        *readsDst = true;
237    }
238    if (stage.getFragmentProcessor()->willReadFragmentPosition()) {
239        *readsFragPosition = true;
240    }
241}
242
243void GrOptDrawState::getStageStats() {
244    // We will need a local coord attrib if there is one currently set on the optState and we are
245    // actually generating some effect code
246    fRequiresLocalCoordAttrib = this->hasLocalCoordAttribute() && this->numTotalStages() > 0;
247
248    fReadsDst = false;
249    fReadsFragPosition = false;
250
251    for (int s = 0; s < this->numColorStages(); ++s) {
252        const GrFragmentStage& stage = this->getColorStage(s);
253        get_stage_stats(stage, &fReadsDst, &fReadsFragPosition);
254    }
255    for (int s = 0; s < this->numCoverageStages(); ++s) {
256        const GrFragmentStage& stage = this->getCoverageStage(s);
257        get_stage_stats(stage, &fReadsDst, &fReadsFragPosition);
258    }
259    if (this->hasGeometryProcessor()) {
260        const GrGeometryStage& stage = *this->getGeometryProcessor();
261        fReadsFragPosition = fReadsFragPosition || stage.getProcessor()->willReadFragmentPosition();
262    }
263}
264
265bool GrOptDrawState::operator== (const GrOptDrawState& that) const {
266    return this->isEqual(that);
267}
268
269