1/*
2 * Copyright 2012 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 "GrDrawState.h"
9
10#include "GrOptDrawState.h"
11#include "GrPaint.h"
12
13//////////////////////////////////////////////////////////////////////////////s
14
15GrOptDrawState* GrDrawState::createOptState(const GrDrawTargetCaps& caps) const {
16    if (NULL == fCachedOptState || caps.getUniqueID() != fCachedCapsID) {
17        GrBlendCoeff srcCoeff;
18        GrBlendCoeff dstCoeff;
19        BlendOptFlags blendFlags = this->getBlendOpts(false, &srcCoeff, &dstCoeff);
20        fCachedOptState = SkNEW_ARGS(GrOptDrawState, (*this, blendFlags, srcCoeff, dstCoeff, caps));
21        fCachedCapsID = caps.getUniqueID();
22    } else {
23#ifdef SK_DEBUG
24        GrBlendCoeff srcCoeff;
25        GrBlendCoeff dstCoeff;
26        BlendOptFlags blendFlags = this->getBlendOpts(false, &srcCoeff, &dstCoeff);
27        SkASSERT(GrOptDrawState(*this, blendFlags, srcCoeff, dstCoeff, caps) == *fCachedOptState);
28#endif
29    }
30    fCachedOptState->ref();
31    return fCachedOptState;
32}
33
34//////////////////////////////////////////////////////////////////////////////s
35
36GrDrawState::CombinedState GrDrawState::CombineIfPossible(
37    const GrDrawState& a, const GrDrawState& b, const GrDrawTargetCaps& caps) {
38
39    if (!a.isEqual(b)) {
40        return kIncompatible_CombinedState;
41    }
42
43    // If the general draw states are equal (from check above) we know hasColorVertexAttribute()
44    // is equivalent for both a and b
45    if (a.hasColorVertexAttribute()) {
46        // If one is opaque and the other is not then the combined state is not opaque. Moreover,
47        // if the opaqueness affects the ability to get color/coverage blending correct then we
48        // don't combine the draw states.
49        bool aIsOpaque = (kVertexColorsAreOpaque_Hint & a.fHints);
50        bool bIsOpaque = (kVertexColorsAreOpaque_Hint & b.fHints);
51        if (aIsOpaque != bIsOpaque) {
52            const GrDrawState* opaque;
53            const GrDrawState* nonOpaque;
54            if (aIsOpaque) {
55                opaque = &a;
56                nonOpaque = &b;
57            } else {
58                opaque = &b;
59                nonOpaque = &a;
60            }
61            if (!opaque->hasSolidCoverage() && opaque->couldApplyCoverage(caps)) {
62                SkASSERT(!nonOpaque->hasSolidCoverage());
63                if (!nonOpaque->couldApplyCoverage(caps)) {
64                    return kIncompatible_CombinedState;
65                }
66            }
67            return aIsOpaque ? kB_CombinedState : kA_CombinedState;
68        }
69    }
70    return kAOrB_CombinedState;
71}
72
73//////////////////////////////////////////////////////////////////////////////s
74
75GrDrawState::GrDrawState(const GrDrawState& state, const SkMatrix& preConcatMatrix)
76    : fCachedOptState(NULL) {
77    SkDEBUGCODE(fBlockEffectRemovalCnt = 0;)
78    *this = state;
79    if (!preConcatMatrix.isIdentity()) {
80        if (this->hasGeometryProcessor()) {
81            fGeometryProcessor->localCoordChange(preConcatMatrix);
82        }
83        for (int i = 0; i < this->numColorStages(); ++i) {
84            fColorStages[i].localCoordChange(preConcatMatrix);
85        }
86        for (int i = 0; i < this->numCoverageStages(); ++i) {
87            fCoverageStages[i].localCoordChange(preConcatMatrix);
88        }
89        this->invalidateOptState();
90    }
91}
92
93GrDrawState& GrDrawState::operator=(const GrDrawState& that) {
94    SkASSERT(0 == fBlockEffectRemovalCnt || 0 == this->numTotalStages());
95    SkASSERT(!that.fRenderTarget.ownsPendingIO());
96    SkASSERT(!this->fRenderTarget.ownsPendingIO());
97    this->setRenderTarget(that.getRenderTarget());
98    fColor = that.fColor;
99    fViewMatrix = that.fViewMatrix;
100    fSrcBlend = that.fSrcBlend;
101    fDstBlend = that.fDstBlend;
102    fBlendConstant = that.fBlendConstant;
103    fFlagBits = that.fFlagBits;
104    fVACount = that.fVACount;
105    fVAPtr = that.fVAPtr;
106    fVAStride = that.fVAStride;
107    fStencilSettings = that.fStencilSettings;
108    fCoverage = that.fCoverage;
109    fDrawFace = that.fDrawFace;
110    if (that.hasGeometryProcessor()) {
111        fGeometryProcessor.reset(SkNEW_ARGS(GrGeometryStage, (*that.fGeometryProcessor.get())));
112    } else {
113        fGeometryProcessor.reset(NULL);
114    }
115    fColorStages = that.fColorStages;
116    fCoverageStages = that.fCoverageStages;
117
118    fHints = that.fHints;
119
120    SkRefCnt_SafeAssign(fCachedOptState, that.fCachedOptState);
121
122    memcpy(fFixedFunctionVertexAttribIndices,
123            that.fFixedFunctionVertexAttribIndices,
124            sizeof(fFixedFunctionVertexAttribIndices));
125    return *this;
126}
127
128void GrDrawState::onReset(const SkMatrix* initialViewMatrix) {
129    SkASSERT(0 == fBlockEffectRemovalCnt || 0 == this->numTotalStages());
130    SkASSERT(!fRenderTarget.ownsPendingIO());
131
132    fGeometryProcessor.reset(NULL);
133    fColorStages.reset();
134    fCoverageStages.reset();
135
136    fRenderTarget.reset();
137
138    this->setDefaultVertexAttribs();
139
140    fColor = 0xffffffff;
141    if (NULL == initialViewMatrix) {
142        fViewMatrix.reset();
143    } else {
144        fViewMatrix = *initialViewMatrix;
145    }
146    fSrcBlend = kOne_GrBlendCoeff;
147    fDstBlend = kZero_GrBlendCoeff;
148    fBlendConstant = 0x0;
149    fFlagBits = 0x0;
150    fStencilSettings.setDisabled();
151    fCoverage = 0xff;
152    fDrawFace = kBoth_DrawFace;
153
154    fHints = 0;
155
156    this->invalidateOptState();
157}
158
159bool GrDrawState::setIdentityViewMatrix()  {
160    if (this->numTotalStages()) {
161        SkMatrix invVM;
162        if (!fViewMatrix.invert(&invVM)) {
163            // sad trombone sound
164            return false;
165        }
166        if (this->hasGeometryProcessor()) {
167            fGeometryProcessor->localCoordChange(invVM);
168        }
169        for (int s = 0; s < this->numColorStages(); ++s) {
170            fColorStages[s].localCoordChange(invVM);
171        }
172        for (int s = 0; s < this->numCoverageStages(); ++s) {
173            fCoverageStages[s].localCoordChange(invVM);
174        }
175    }
176    this->invalidateOptState();
177    fViewMatrix.reset();
178    return true;
179}
180
181void GrDrawState::setFromPaint(const GrPaint& paint, const SkMatrix& vm, GrRenderTarget* rt) {
182    SkASSERT(0 == fBlockEffectRemovalCnt || 0 == this->numTotalStages());
183
184    fGeometryProcessor.reset(NULL);
185    fColorStages.reset();
186    fCoverageStages.reset();
187
188    for (int i = 0; i < paint.numColorStages(); ++i) {
189        fColorStages.push_back(paint.getColorStage(i));
190    }
191
192    for (int i = 0; i < paint.numCoverageStages(); ++i) {
193        fCoverageStages.push_back(paint.getCoverageStage(i));
194    }
195
196    this->setRenderTarget(rt);
197
198    fViewMatrix = vm;
199
200    // These have no equivalent in GrPaint, set them to defaults
201    fBlendConstant = 0x0;
202    fDrawFace = kBoth_DrawFace;
203    fStencilSettings.setDisabled();
204    this->resetStateFlags();
205    fHints = 0;
206
207    // Enable the clip bit
208    this->enableState(GrDrawState::kClip_StateBit);
209
210    this->setColor(paint.getColor());
211    this->setState(GrDrawState::kDither_StateBit, paint.isDither());
212    this->setState(GrDrawState::kHWAntialias_StateBit, paint.isAntiAlias());
213
214    this->setBlendFunc(paint.getSrcBlendCoeff(), paint.getDstBlendCoeff());
215    this->setCoverage(paint.getCoverage());
216    this->invalidateOptState();
217}
218
219////////////////////////////////////////////////////////////////////////////////
220
221static void validate_vertex_attribs(const GrVertexAttrib* attribs, int count, size_t stride) {
222    // this works as long as we're 4 byte-aligned
223#ifdef SK_DEBUG
224    uint32_t overlapCheck = 0;
225    SkASSERT(count <= GrRODrawState::kMaxVertexAttribCnt);
226    for (int index = 0; index < count; ++index) {
227        size_t attribSize = GrVertexAttribTypeSize(attribs[index].fType);
228        size_t attribOffset = attribs[index].fOffset;
229        SkASSERT(attribOffset + attribSize <= stride);
230        size_t dwordCount = attribSize >> 2;
231        uint32_t mask = (1 << dwordCount)-1;
232        size_t offsetShift = attribOffset >> 2;
233        SkASSERT(!(overlapCheck & (mask << offsetShift)));
234        overlapCheck |= (mask << offsetShift);
235    }
236#endif
237}
238
239////////////////////////////////////////////////////////////////////////////////
240
241void GrDrawState::internalSetVertexAttribs(const GrVertexAttrib* attribs, int count,
242                                           size_t stride) {
243    SkASSERT(count <= kMaxVertexAttribCnt);
244
245    fVAPtr = attribs;
246    fVACount = count;
247    fVAStride = stride;
248    validate_vertex_attribs(fVAPtr, fVACount, fVAStride);
249
250    // Set all the indices to -1
251    memset(fFixedFunctionVertexAttribIndices,
252           0xff,
253           sizeof(fFixedFunctionVertexAttribIndices));
254#ifdef SK_DEBUG
255    uint32_t overlapCheck = 0;
256#endif
257    for (int i = 0; i < count; ++i) {
258        if (attribs[i].fBinding < kGrFixedFunctionVertexAttribBindingCnt) {
259            // The fixed function attribs can only be specified once
260            SkASSERT(-1 == fFixedFunctionVertexAttribIndices[attribs[i].fBinding]);
261            SkASSERT(GrFixedFunctionVertexAttribVectorCount(attribs[i].fBinding) ==
262                     GrVertexAttribTypeVectorCount(attribs[i].fType));
263            fFixedFunctionVertexAttribIndices[attribs[i].fBinding] = i;
264        }
265#ifdef SK_DEBUG
266        size_t dwordCount = GrVertexAttribTypeSize(attribs[i].fType) >> 2;
267        uint32_t mask = (1 << dwordCount)-1;
268        size_t offsetShift = attribs[i].fOffset >> 2;
269        SkASSERT(!(overlapCheck & (mask << offsetShift)));
270        overlapCheck |= (mask << offsetShift);
271#endif
272    }
273    this->invalidateOptState();
274    // Positions must be specified.
275    SkASSERT(-1 != fFixedFunctionVertexAttribIndices[kPosition_GrVertexAttribBinding]);
276}
277
278////////////////////////////////////////////////////////////////////////////////
279
280void GrDrawState::setDefaultVertexAttribs() {
281    static const GrVertexAttrib kPositionAttrib =
282        {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding};
283
284    fVAPtr = &kPositionAttrib;
285    fVACount = 1;
286    fVAStride = GrVertexAttribTypeSize(kVec2f_GrVertexAttribType);
287
288    // set all the fixed function indices to -1 except position.
289    memset(fFixedFunctionVertexAttribIndices,
290           0xff,
291           sizeof(fFixedFunctionVertexAttribIndices));
292    fFixedFunctionVertexAttribIndices[kPosition_GrVertexAttribBinding] = 0;
293    this->invalidateOptState();
294}
295
296////////////////////////////////////////////////////////////////////////////////
297
298bool GrDrawState::couldApplyCoverage(const GrDrawTargetCaps& caps) const {
299    if (caps.dualSourceBlendingSupport()) {
300        return true;
301    }
302    // we can correctly apply coverage if a) we have dual source blending
303    // or b) one of our blend optimizations applies
304    // or c) the src, dst blend coeffs are 1,0 and we will read Dst Color
305    GrBlendCoeff srcCoeff;
306    GrBlendCoeff dstCoeff;
307    BlendOptFlags flag = this->getBlendOpts(true, &srcCoeff, &dstCoeff);
308    return GrRODrawState::kNone_BlendOpt != flag ||
309           (this->willEffectReadDstColor() &&
310            kOne_GrBlendCoeff == srcCoeff && kZero_GrBlendCoeff == dstCoeff);
311}
312
313//////////////////////////////////////////////////////////////////////////////
314
315GrDrawState::AutoVertexAttribRestore::AutoVertexAttribRestore(GrDrawState* drawState) {
316    SkASSERT(drawState);
317    fDrawState = drawState;
318    fVAPtr = drawState->fVAPtr;
319    fVACount = drawState->fVACount;
320    fVAStride = drawState->fVAStride;
321    fDrawState->setDefaultVertexAttribs();
322}
323
324//////////////////////////////////////////////////////////////////////////////s
325
326void GrDrawState::AutoRestoreEffects::set(GrDrawState* ds) {
327    if (fDrawState) {
328        // See the big comment on the class definition about GPs.
329        if (SK_InvalidUniqueID == fOriginalGPID) {
330            fDrawState->fGeometryProcessor.reset(NULL);
331        } else {
332            SkASSERT(fDrawState->getGeometryProcessor()->getProcessor()->getUniqueID() ==
333                     fOriginalGPID);
334            fOriginalGPID = SK_InvalidUniqueID;
335        }
336
337        int m = fDrawState->numColorStages() - fColorEffectCnt;
338        SkASSERT(m >= 0);
339        fDrawState->fColorStages.pop_back_n(m);
340
341        int n = fDrawState->numCoverageStages() - fCoverageEffectCnt;
342        SkASSERT(n >= 0);
343        fDrawState->fCoverageStages.pop_back_n(n);
344        if (m + n > 0) {
345            fDrawState->invalidateOptState();
346        }
347        SkDEBUGCODE(--fDrawState->fBlockEffectRemovalCnt;)
348    }
349    fDrawState = ds;
350    if (NULL != ds) {
351        SkASSERT(SK_InvalidUniqueID == fOriginalGPID);
352        if (NULL != ds->getGeometryProcessor()) {
353            fOriginalGPID = ds->getGeometryProcessor()->getProcessor()->getUniqueID();
354        }
355        fColorEffectCnt = ds->numColorStages();
356        fCoverageEffectCnt = ds->numCoverageStages();
357        SkDEBUGCODE(++ds->fBlockEffectRemovalCnt;)
358    }
359}
360
361////////////////////////////////////////////////////////////////////////////////
362
363void GrDrawState::AutoViewMatrixRestore::restore() {
364    if (fDrawState) {
365        SkDEBUGCODE(--fDrawState->fBlockEffectRemovalCnt;)
366        fDrawState->fViewMatrix = fViewMatrix;
367        SkASSERT(fDrawState->numColorStages() >= fNumColorStages);
368        int numCoverageStages = fSavedCoordChanges.count() - fNumColorStages;
369        SkASSERT(fDrawState->numCoverageStages() >= numCoverageStages);
370
371        int i = 0;
372        if (fHasGeometryProcessor) {
373            SkASSERT(fDrawState->hasGeometryProcessor());
374            fDrawState->fGeometryProcessor->restoreCoordChange(fSavedCoordChanges[i++]);
375        }
376        for (int s = 0; s < fNumColorStages; ++s, ++i) {
377            fDrawState->fColorStages[s].restoreCoordChange(fSavedCoordChanges[i]);
378        }
379        for (int s = 0; s < numCoverageStages; ++s, ++i) {
380            fDrawState->fCoverageStages[s].restoreCoordChange(fSavedCoordChanges[i]);
381        }
382        fDrawState->invalidateOptState();
383        fDrawState = NULL;
384    }
385}
386
387void GrDrawState::AutoViewMatrixRestore::set(GrDrawState* drawState,
388                                             const SkMatrix& preconcatMatrix) {
389    this->restore();
390
391    SkASSERT(NULL == fDrawState);
392    if (NULL == drawState || preconcatMatrix.isIdentity()) {
393        return;
394    }
395    fDrawState = drawState;
396
397    fViewMatrix = drawState->getViewMatrix();
398    drawState->fViewMatrix.preConcat(preconcatMatrix);
399
400    this->doEffectCoordChanges(preconcatMatrix);
401    SkDEBUGCODE(++fDrawState->fBlockEffectRemovalCnt;)
402    drawState->invalidateOptState();
403}
404
405bool GrDrawState::AutoViewMatrixRestore::setIdentity(GrDrawState* drawState) {
406    this->restore();
407
408    if (NULL == drawState) {
409        return false;
410    }
411
412    if (drawState->getViewMatrix().isIdentity()) {
413        return true;
414    }
415
416    drawState->invalidateOptState();
417    fViewMatrix = drawState->getViewMatrix();
418    if (0 == drawState->numTotalStages()) {
419        drawState->fViewMatrix.reset();
420        fDrawState = drawState;
421        fHasGeometryProcessor = false;
422        fNumColorStages = 0;
423        fSavedCoordChanges.reset(0);
424        SkDEBUGCODE(++fDrawState->fBlockEffectRemovalCnt;)
425        return true;
426    } else {
427        SkMatrix inv;
428        if (!fViewMatrix.invert(&inv)) {
429            return false;
430        }
431        drawState->fViewMatrix.reset();
432        fDrawState = drawState;
433        this->doEffectCoordChanges(inv);
434        SkDEBUGCODE(++fDrawState->fBlockEffectRemovalCnt;)
435        return true;
436    }
437}
438
439void GrDrawState::AutoViewMatrixRestore::doEffectCoordChanges(const SkMatrix& coordChangeMatrix) {
440    fSavedCoordChanges.reset(fDrawState->numTotalStages());
441    int i = 0;
442
443    fHasGeometryProcessor = false;
444    if (fDrawState->hasGeometryProcessor()) {
445        fDrawState->fGeometryProcessor->saveCoordChange(&fSavedCoordChanges[i++]);
446        fDrawState->fGeometryProcessor->localCoordChange(coordChangeMatrix);
447        fHasGeometryProcessor = true;
448    }
449
450    fNumColorStages = fDrawState->numColorStages();
451    for (int s = 0; s < fNumColorStages; ++s, ++i) {
452        fDrawState->getColorStage(s).saveCoordChange(&fSavedCoordChanges[i]);
453        fDrawState->fColorStages[s].localCoordChange(coordChangeMatrix);
454    }
455
456    int numCoverageStages = fDrawState->numCoverageStages();
457    for (int s = 0; s < numCoverageStages; ++s, ++i) {
458        fDrawState->getCoverageStage(s).saveCoordChange(&fSavedCoordChanges[i]);
459        fDrawState->fCoverageStages[s].localCoordChange(coordChangeMatrix);
460    }
461}
462
463////////////////////////////////////////////////////////////////////////////////
464
465void GrDrawState::invalidateOptState() const {
466    SkSafeSetNull(fCachedOptState);
467}
468
469////////////////////////////////////////////////////////////////////////////////
470
471GrDrawState::~GrDrawState() {
472    SkSafeUnref(fCachedOptState);
473    SkASSERT(0 == fBlockEffectRemovalCnt);
474}
475
476