blob: 236d48f229ef2b478a7e1e77c5f13bca4e190326 [file] [log] [blame]
bsalomon@google.comaf84e742012-10-05 13:23:24 +00001/*
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"
bsalomon@google.comaf84e742012-10-05 13:23:24 +00009#include "GrPaint.h"
bsalomon62c447d2014-08-08 08:08:50 -070010#include "GrDrawTargetCaps.h"
bsalomon@google.comaf84e742012-10-05 13:23:24 +000011
bsalomon8f727332014-08-05 07:50:06 -070012//////////////////////////////////////////////////////////////////////////////s
13
14GrDrawState::CombinedState GrDrawState::CombineIfPossible(
bsalomon62c447d2014-08-08 08:08:50 -070015 const GrDrawState& a, const GrDrawState& b, const GrDrawTargetCaps& caps) {
bsalomon8f727332014-08-05 07:50:06 -070016
egdaniel21aed572014-08-26 12:24:06 -070017 if (!a.isEqual(b)) {
bsalomon8f727332014-08-05 07:50:06 -070018 return kIncompatible_CombinedState;
19 }
20
egdaniel21aed572014-08-26 12:24:06 -070021 // If the general draw states are equal (from check above) we know hasColorVertexAttribute()
22 // is equivalent for both a and b
23 if (a.hasColorVertexAttribute()) {
bsalomon62c447d2014-08-08 08:08:50 -070024 // If one is opaque and the other is not then the combined state is not opaque. Moreover,
25 // if the opaqueness affects the ability to get color/coverage blending correct then we
26 // don't combine the draw states.
27 bool aIsOpaque = (kVertexColorsAreOpaque_Hint & a.fHints);
28 bool bIsOpaque = (kVertexColorsAreOpaque_Hint & b.fHints);
29 if (aIsOpaque != bIsOpaque) {
30 const GrDrawState* opaque;
31 const GrDrawState* nonOpaque;
32 if (aIsOpaque) {
33 opaque = &a;
34 nonOpaque = &b;
35 } else {
36 opaque = &b;
37 nonOpaque = &a;
38 }
39 if (!opaque->hasSolidCoverage() && opaque->couldApplyCoverage(caps)) {
40 SkASSERT(!nonOpaque->hasSolidCoverage());
41 if (!nonOpaque->couldApplyCoverage(caps)) {
42 return kIncompatible_CombinedState;
43 }
44 }
45 return aIsOpaque ? kB_CombinedState : kA_CombinedState;
46 }
47 }
bsalomon8f727332014-08-05 07:50:06 -070048 return kAOrB_CombinedState;
49}
50
bsalomon8f727332014-08-05 07:50:06 -070051//////////////////////////////////////////////////////////////////////////////s
52
53GrDrawState::GrDrawState(const GrDrawState& state, const SkMatrix& preConcatMatrix) {
54 SkDEBUGCODE(fBlockEffectRemovalCnt = 0;)
55 *this = state;
56 if (!preConcatMatrix.isIdentity()) {
joshualittbd769d02014-09-04 08:56:46 -070057 if (this->hasGeometryProcessor()) {
58 fGeometryProcessor->localCoordChange(preConcatMatrix);
59 }
egdaniel776bdbd2014-08-06 11:07:02 -070060 for (int i = 0; i < this->numColorStages(); ++i) {
egdaniel8cbf3d52014-08-21 06:27:22 -070061 fColorStages[i].localCoordChange(preConcatMatrix);
bsalomon8f727332014-08-05 07:50:06 -070062 }
egdaniel776bdbd2014-08-06 11:07:02 -070063 for (int i = 0; i < this->numCoverageStages(); ++i) {
egdaniel8cbf3d52014-08-21 06:27:22 -070064 fCoverageStages[i].localCoordChange(preConcatMatrix);
bsalomon8f727332014-08-05 07:50:06 -070065 }
66 this->invalidateBlendOptFlags();
67 }
68}
69
70GrDrawState& GrDrawState::operator=(const GrDrawState& that) {
71 SkASSERT(0 == fBlockEffectRemovalCnt || 0 == this->numTotalStages());
72 this->setRenderTarget(that.fRenderTarget.get());
73 fColor = that.fColor;
74 fViewMatrix = that.fViewMatrix;
egdaniel8cbf3d52014-08-21 06:27:22 -070075 fSrcBlend = that.fSrcBlend;
76 fDstBlend = that.fDstBlend;
bsalomon8f727332014-08-05 07:50:06 -070077 fBlendConstant = that.fBlendConstant;
78 fFlagBits = that.fFlagBits;
79 fVACount = that.fVACount;
80 fVAPtr = that.fVAPtr;
egdaniel7b3d5ee2014-08-28 05:41:14 -070081 fVAStride = that.fVAStride;
bsalomon8f727332014-08-05 07:50:06 -070082 fStencilSettings = that.fStencilSettings;
83 fCoverage = that.fCoverage;
84 fDrawFace = that.fDrawFace;
joshualittbd769d02014-09-04 08:56:46 -070085 if (that.hasGeometryProcessor()) {
86 fGeometryProcessor.reset(SkNEW_ARGS(GrEffectStage, (*that.fGeometryProcessor.get())));
87 } else {
88 fGeometryProcessor.reset(NULL);
89 }
egdaniel8cbf3d52014-08-21 06:27:22 -070090 fColorStages = that.fColorStages;
91 fCoverageStages = that.fCoverageStages;
bsalomon8f727332014-08-05 07:50:06 -070092 fOptSrcBlend = that.fOptSrcBlend;
93 fOptDstBlend = that.fOptDstBlend;
94 fBlendOptFlags = that.fBlendOptFlags;
95
bsalomon62c447d2014-08-08 08:08:50 -070096 fHints = that.fHints;
egdaniel776bdbd2014-08-06 11:07:02 -070097
bsalomon8f727332014-08-05 07:50:06 -070098 memcpy(fFixedFunctionVertexAttribIndices,
99 that.fFixedFunctionVertexAttribIndices,
100 sizeof(fFixedFunctionVertexAttribIndices));
101 return *this;
102}
103
104void GrDrawState::onReset(const SkMatrix* initialViewMatrix) {
105 SkASSERT(0 == fBlockEffectRemovalCnt || 0 == this->numTotalStages());
joshualittbd769d02014-09-04 08:56:46 -0700106 fGeometryProcessor.reset(NULL);
egdaniel8cbf3d52014-08-21 06:27:22 -0700107 fColorStages.reset();
108 fCoverageStages.reset();
bsalomon8f727332014-08-05 07:50:06 -0700109
110 fRenderTarget.reset(NULL);
111
112 this->setDefaultVertexAttribs();
113
114 fColor = 0xffffffff;
115 if (NULL == initialViewMatrix) {
116 fViewMatrix.reset();
117 } else {
118 fViewMatrix = *initialViewMatrix;
119 }
egdaniel8cbf3d52014-08-21 06:27:22 -0700120 fSrcBlend = kOne_GrBlendCoeff;
121 fDstBlend = kZero_GrBlendCoeff;
bsalomon8f727332014-08-05 07:50:06 -0700122 fBlendConstant = 0x0;
123 fFlagBits = 0x0;
124 fStencilSettings.setDisabled();
egdaniel8cbf3d52014-08-21 06:27:22 -0700125 fCoverage = 0xff;
bsalomon8f727332014-08-05 07:50:06 -0700126 fDrawFace = kBoth_DrawFace;
127
bsalomon62c447d2014-08-08 08:08:50 -0700128 fHints = 0;
129
bsalomon8f727332014-08-05 07:50:06 -0700130 this->invalidateBlendOptFlags();
131}
132
bsalomon@google.com137f1342013-05-29 21:27:53 +0000133bool GrDrawState::setIdentityViewMatrix() {
egdaniel776bdbd2014-08-06 11:07:02 -0700134 if (this->numTotalStages()) {
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000135 SkMatrix invVM;
bsalomon2ed5ef82014-07-07 08:44:05 -0700136 if (!fViewMatrix.invert(&invVM)) {
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000137 // sad trombone sound
138 return false;
139 }
joshualittbd769d02014-09-04 08:56:46 -0700140 if (this->hasGeometryProcessor()) {
141 fGeometryProcessor->localCoordChange(invVM);
142 }
egdaniel776bdbd2014-08-06 11:07:02 -0700143 for (int s = 0; s < this->numColorStages(); ++s) {
egdaniel8cbf3d52014-08-21 06:27:22 -0700144 fColorStages[s].localCoordChange(invVM);
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000145 }
egdaniel776bdbd2014-08-06 11:07:02 -0700146 for (int s = 0; s < this->numCoverageStages(); ++s) {
egdaniel8cbf3d52014-08-21 06:27:22 -0700147 fCoverageStages[s].localCoordChange(invVM);
bsalomon@google.com137f1342013-05-29 21:27:53 +0000148 }
149 }
bsalomon2ed5ef82014-07-07 08:44:05 -0700150 fViewMatrix.reset();
bsalomon@google.com137f1342013-05-29 21:27:53 +0000151 return true;
152}
153
commit-bot@chromium.orgbb6a3172013-05-28 17:25:49 +0000154void GrDrawState::setFromPaint(const GrPaint& paint, const SkMatrix& vm, GrRenderTarget* rt) {
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000155 SkASSERT(0 == fBlockEffectRemovalCnt || 0 == this->numTotalStages());
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000156
joshualittbd769d02014-09-04 08:56:46 -0700157 fGeometryProcessor.reset(NULL);
egdaniel8cbf3d52014-08-21 06:27:22 -0700158 fColorStages.reset();
159 fCoverageStages.reset();
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000160
commit-bot@chromium.org42dacab2013-07-13 17:24:24 +0000161 for (int i = 0; i < paint.numColorStages(); ++i) {
egdaniel8cbf3d52014-08-21 06:27:22 -0700162 fColorStages.push_back(paint.getColorStage(i));
bsalomon@google.comaf84e742012-10-05 13:23:24 +0000163 }
164
commit-bot@chromium.org42dacab2013-07-13 17:24:24 +0000165 for (int i = 0; i < paint.numCoverageStages(); ++i) {
egdaniel8cbf3d52014-08-21 06:27:22 -0700166 fCoverageStages.push_back(paint.getCoverageStage(i));
bsalomon@google.comaf84e742012-10-05 13:23:24 +0000167 }
168
commit-bot@chromium.orgbb6a3172013-05-28 17:25:49 +0000169 this->setRenderTarget(rt);
bsalomon@google.comaf84e742012-10-05 13:23:24 +0000170
bsalomon2ed5ef82014-07-07 08:44:05 -0700171 fViewMatrix = vm;
commit-bot@chromium.orgbb6a3172013-05-28 17:25:49 +0000172
173 // These have no equivalent in GrPaint, set them to defaults
bsalomon2ed5ef82014-07-07 08:44:05 -0700174 fBlendConstant = 0x0;
175 fDrawFace = kBoth_DrawFace;
176 fStencilSettings.setDisabled();
commit-bot@chromium.orgbb6a3172013-05-28 17:25:49 +0000177 this->resetStateFlags();
bsalomon62c447d2014-08-08 08:08:50 -0700178 fHints = 0;
commit-bot@chromium.orgbb6a3172013-05-28 17:25:49 +0000179
bsalomon@google.com21c10c52013-06-13 17:44:07 +0000180 // Enable the clip bit
181 this->enableState(GrDrawState::kClip_StateBit);
182
commit-bot@chromium.orgbb6a3172013-05-28 17:25:49 +0000183 this->setColor(paint.getColor());
bsalomon@google.comc7448ce2012-10-05 19:04:13 +0000184 this->setState(GrDrawState::kDither_StateBit, paint.isDither());
185 this->setState(GrDrawState::kHWAntialias_StateBit, paint.isAntiAlias());
bsalomon@google.comaf84e742012-10-05 13:23:24 +0000186
bsalomon@google.comc7448ce2012-10-05 19:04:13 +0000187 this->setBlendFunc(paint.getSrcBlendCoeff(), paint.getDstBlendCoeff());
bsalomon@google.comc7448ce2012-10-05 19:04:13 +0000188 this->setCoverage(paint.getCoverage());
egdaniel9514d242014-07-18 06:15:43 -0700189 this->invalidateBlendOptFlags();
bsalomon@google.comaf84e742012-10-05 13:23:24 +0000190}
bsalomon@google.com5b3e8902012-10-05 20:13:28 +0000191
192////////////////////////////////////////////////////////////////////////////////
193
egdaniel7b3d5ee2014-08-28 05:41:14 -0700194static void validate_vertex_attribs(const GrVertexAttrib* attribs, int count, size_t stride) {
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000195 // this works as long as we're 4 byte-aligned
commit-bot@chromium.org515dcd32013-08-28 14:17:03 +0000196#ifdef SK_DEBUG
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000197 uint32_t overlapCheck = 0;
egdaniel21aed572014-08-26 12:24:06 -0700198 SkASSERT(count <= GrRODrawState::kMaxVertexAttribCnt);
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000199 for (int index = 0; index < count; ++index) {
jvanverth@google.com054ae992013-04-01 20:06:51 +0000200 size_t attribSize = GrVertexAttribTypeSize(attribs[index].fType);
egdaniel7b3d5ee2014-08-28 05:41:14 -0700201 size_t attribOffset = attribs[index].fOffset;
202 SkASSERT(attribOffset + attribSize <= stride);
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000203 size_t dwordCount = attribSize >> 2;
204 uint32_t mask = (1 << dwordCount)-1;
egdaniel7b3d5ee2014-08-28 05:41:14 -0700205 size_t offsetShift = attribOffset >> 2;
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000206 SkASSERT(!(overlapCheck & (mask << offsetShift)));
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000207 overlapCheck |= (mask << offsetShift);
djsollenea81ced2014-08-27 13:07:34 -0700208 }
egdaniel7b3d5ee2014-08-28 05:41:14 -0700209#endif
jvanverth@google.comcc782382013-01-28 20:39:48 +0000210}
211
212////////////////////////////////////////////////////////////////////////////////
213
egdaniel7b3d5ee2014-08-28 05:41:14 -0700214void GrDrawState::internalSetVertexAttribs(const GrVertexAttrib* attribs, int count,
215 size_t stride) {
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000216 SkASSERT(count <= kMaxVertexAttribCnt);
robertphillips@google.com42903302013-04-20 12:26:07 +0000217
bsalomon2ed5ef82014-07-07 08:44:05 -0700218 fVAPtr = attribs;
219 fVACount = count;
egdaniel7b3d5ee2014-08-28 05:41:14 -0700220 fVAStride = stride;
221 validate_vertex_attribs(fVAPtr, fVACount, fVAStride);
jvanverth@google.com054ae992013-04-01 20:06:51 +0000222
223 // Set all the indices to -1
bsalomon2ed5ef82014-07-07 08:44:05 -0700224 memset(fFixedFunctionVertexAttribIndices,
jvanverth@google.com054ae992013-04-01 20:06:51 +0000225 0xff,
bsalomon2ed5ef82014-07-07 08:44:05 -0700226 sizeof(fFixedFunctionVertexAttribIndices));
commit-bot@chromium.org515dcd32013-08-28 14:17:03 +0000227#ifdef SK_DEBUG
jvanverth@google.com054ae992013-04-01 20:06:51 +0000228 uint32_t overlapCheck = 0;
229#endif
230 for (int i = 0; i < count; ++i) {
231 if (attribs[i].fBinding < kGrFixedFunctionVertexAttribBindingCnt) {
232 // The fixed function attribs can only be specified once
bsalomon2ed5ef82014-07-07 08:44:05 -0700233 SkASSERT(-1 == fFixedFunctionVertexAttribIndices[attribs[i].fBinding]);
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000234 SkASSERT(GrFixedFunctionVertexAttribVectorCount(attribs[i].fBinding) ==
jvanverth@google.com054ae992013-04-01 20:06:51 +0000235 GrVertexAttribTypeVectorCount(attribs[i].fType));
bsalomon2ed5ef82014-07-07 08:44:05 -0700236 fFixedFunctionVertexAttribIndices[attribs[i].fBinding] = i;
jvanverth@google.com054ae992013-04-01 20:06:51 +0000237 }
commit-bot@chromium.org515dcd32013-08-28 14:17:03 +0000238#ifdef SK_DEBUG
jvanverth@google.com054ae992013-04-01 20:06:51 +0000239 size_t dwordCount = GrVertexAttribTypeSize(attribs[i].fType) >> 2;
240 uint32_t mask = (1 << dwordCount)-1;
241 size_t offsetShift = attribs[i].fOffset >> 2;
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000242 SkASSERT(!(overlapCheck & (mask << offsetShift)));
jvanverth@google.com054ae992013-04-01 20:06:51 +0000243 overlapCheck |= (mask << offsetShift);
244#endif
jvanverth@google.comcc782382013-01-28 20:39:48 +0000245 }
egdaniel9514d242014-07-18 06:15:43 -0700246 this->invalidateBlendOptFlags();
jvanverth@google.com054ae992013-04-01 20:06:51 +0000247 // Positions must be specified.
bsalomon2ed5ef82014-07-07 08:44:05 -0700248 SkASSERT(-1 != fFixedFunctionVertexAttribIndices[kPosition_GrVertexAttribBinding]);
jvanverth@google.comcc782382013-01-28 20:39:48 +0000249}
250
251////////////////////////////////////////////////////////////////////////////////
252
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000253void GrDrawState::setDefaultVertexAttribs() {
jvanverth@google.com054ae992013-04-01 20:06:51 +0000254 static const GrVertexAttrib kPositionAttrib =
255 {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding};
robertphillips@google.com42903302013-04-20 12:26:07 +0000256
bsalomon2ed5ef82014-07-07 08:44:05 -0700257 fVAPtr = &kPositionAttrib;
258 fVACount = 1;
egdaniel7b3d5ee2014-08-28 05:41:14 -0700259 fVAStride = GrVertexAttribTypeSize(kVec2f_GrVertexAttribType);
robertphillips@google.com42903302013-04-20 12:26:07 +0000260
jvanverth@google.com054ae992013-04-01 20:06:51 +0000261 // set all the fixed function indices to -1 except position.
bsalomon2ed5ef82014-07-07 08:44:05 -0700262 memset(fFixedFunctionVertexAttribIndices,
jvanverth@google.com054ae992013-04-01 20:06:51 +0000263 0xff,
bsalomon2ed5ef82014-07-07 08:44:05 -0700264 sizeof(fFixedFunctionVertexAttribIndices));
265 fFixedFunctionVertexAttribIndices[kPosition_GrVertexAttribBinding] = 0;
egdaniel9514d242014-07-18 06:15:43 -0700266 this->invalidateBlendOptFlags();
jvanverth@google.comcc782382013-01-28 20:39:48 +0000267}
268
269////////////////////////////////////////////////////////////////////////////////
270
bsalomon62c447d2014-08-08 08:08:50 -0700271bool GrDrawState::couldApplyCoverage(const GrDrawTargetCaps& caps) const {
272 if (caps.dualSourceBlendingSupport()) {
273 return true;
274 }
275 // we can correctly apply coverage if a) we have dual source blending
276 // or b) one of our blend optimizations applies
277 // or c) the src, dst blend coeffs are 1,0 and we will read Dst Color
278 GrBlendCoeff srcCoeff;
279 GrBlendCoeff dstCoeff;
egdaniel21aed572014-08-26 12:24:06 -0700280 GrRODrawState::BlendOptFlags flag = this->getBlendOpts(true, &srcCoeff, &dstCoeff);
281 return GrRODrawState::kNone_BlendOpt != flag ||
bsalomon62c447d2014-08-08 08:08:50 -0700282 (this->willEffectReadDstColor() &&
283 kOne_GrBlendCoeff == srcCoeff && kZero_GrBlendCoeff == dstCoeff);
284}
285
egdaniel21aed572014-08-26 12:24:06 -0700286//////////////////////////////////////////////////////////////////////////////
jvanverth@google.comcc782382013-01-28 20:39:48 +0000287
egdaniel21aed572014-08-26 12:24:06 -0700288GrDrawState::AutoVertexAttribRestore::AutoVertexAttribRestore(
289 GrDrawState* drawState) {
290 SkASSERT(NULL != drawState);
291 fDrawState = drawState;
292 fVAPtr = drawState->fVAPtr;
293 fVACount = drawState->fVACount;
egdaniel7b3d5ee2014-08-28 05:41:14 -0700294 fVAStride = drawState->fVAStride;
egdaniel21aed572014-08-26 12:24:06 -0700295 fDrawState->setDefaultVertexAttribs();
jvanverth@google.comcc782382013-01-28 20:39:48 +0000296}
297
egdaniel21aed572014-08-26 12:24:06 -0700298//////////////////////////////////////////////////////////////////////////////s
bsalomon@google.comd62e88e2013-02-01 14:19:27 +0000299
egdaniel21aed572014-08-26 12:24:06 -0700300void GrDrawState::AutoRestoreEffects::set(GrDrawState* ds) {
301 if (NULL != fDrawState) {
joshualittbd769d02014-09-04 08:56:46 -0700302 fDrawState->fGeometryProcessor.reset(fGeometryProcessor.detach());
303
egdaniel21aed572014-08-26 12:24:06 -0700304 int m = fDrawState->numColorStages() - fColorEffectCnt;
305 SkASSERT(m >= 0);
306 fDrawState->fColorStages.pop_back_n(m);
bsalomon@google.comd62e88e2013-02-01 14:19:27 +0000307
egdaniel21aed572014-08-26 12:24:06 -0700308 int n = fDrawState->numCoverageStages() - fCoverageEffectCnt;
309 SkASSERT(n >= 0);
310 fDrawState->fCoverageStages.pop_back_n(n);
311 if (m + n > 0) {
312 fDrawState->invalidateBlendOptFlags();
313 }
314 SkDEBUGCODE(--fDrawState->fBlockEffectRemovalCnt;)
bsalomon@google.comd62e88e2013-02-01 14:19:27 +0000315 }
egdaniel21aed572014-08-26 12:24:06 -0700316 fDrawState = ds;
317 if (NULL != ds) {
joshualittbd769d02014-09-04 08:56:46 -0700318 if (ds->hasGeometryProcessor()) {
319 fGeometryProcessor.reset(SkNEW_ARGS(GrEffectStage, (*ds->getGeometryProcessor())));
320 } else {
321 fGeometryProcessor.reset(NULL);
322 }
egdaniel21aed572014-08-26 12:24:06 -0700323 fColorEffectCnt = ds->numColorStages();
324 fCoverageEffectCnt = ds->numCoverageStages();
325 SkDEBUGCODE(++ds->fBlockEffectRemovalCnt;)
326 }
bsalomon@google.comd62e88e2013-02-01 14:19:27 +0000327}
328
jvanverth@google.comcc782382013-01-28 20:39:48 +0000329////////////////////////////////////////////////////////////////////////////////
330
egdaniel21aed572014-08-26 12:24:06 -0700331GrRODrawState::BlendOptFlags GrDrawState::getBlendOpts(bool forceCoverage,
332 GrBlendCoeff* srcCoeff,
333 GrBlendCoeff* dstCoeff) const {
bsalomon@google.com2b446732013-02-12 16:47:41 +0000334 GrBlendCoeff bogusSrcCoeff, bogusDstCoeff;
335 if (NULL == srcCoeff) {
336 srcCoeff = &bogusSrcCoeff;
337 }
bsalomon@google.com2b446732013-02-12 16:47:41 +0000338 if (NULL == dstCoeff) {
339 dstCoeff = &bogusDstCoeff;
340 }
egdaniel9514d242014-07-18 06:15:43 -0700341
342 if (forceCoverage) {
343 return this->calcBlendOpts(true, srcCoeff, dstCoeff);
344 }
345
346 if (0 == (fBlendOptFlags & kInvalid_BlendOptFlag)) {
347 *srcCoeff = fOptSrcBlend;
348 *dstCoeff = fOptDstBlend;
349 return fBlendOptFlags;
350 }
351
352 fBlendOptFlags = this->calcBlendOpts(forceCoverage, srcCoeff, dstCoeff);
353 fOptSrcBlend = *srcCoeff;
354 fOptDstBlend = *dstCoeff;
355
356 return fBlendOptFlags;
357}
358
egdaniel21aed572014-08-26 12:24:06 -0700359GrRODrawState::BlendOptFlags GrDrawState::calcBlendOpts(bool forceCoverage,
360 GrBlendCoeff* srcCoeff,
361 GrBlendCoeff* dstCoeff) const {
egdaniel9514d242014-07-18 06:15:43 -0700362 *srcCoeff = this->getSrcBlendCoeff();
bsalomon@google.com2b446732013-02-12 16:47:41 +0000363 *dstCoeff = this->getDstBlendCoeff();
364
365 if (this->isColorWriteDisabled()) {
366 *srcCoeff = kZero_GrBlendCoeff;
367 *dstCoeff = kOne_GrBlendCoeff;
368 }
369
jvanverth@google.com054ae992013-04-01 20:06:51 +0000370 bool srcAIsOne = this->srcAlphaWillBeOne();
bsalomon@google.com2b446732013-02-12 16:47:41 +0000371 bool dstCoeffIsOne = kOne_GrBlendCoeff == *dstCoeff ||
372 (kSA_GrBlendCoeff == *dstCoeff && srcAIsOne);
373 bool dstCoeffIsZero = kZero_GrBlendCoeff == *dstCoeff ||
374 (kISA_GrBlendCoeff == *dstCoeff && srcAIsOne);
375
bsalomon@google.com2b446732013-02-12 16:47:41 +0000376 // When coeffs are (0,1) there is no reason to draw at all, unless
377 // stenciling is enabled. Having color writes disabled is effectively
bsalomon62c447d2014-08-08 08:08:50 -0700378 // (0,1).
379 if ((kZero_GrBlendCoeff == *srcCoeff && dstCoeffIsOne)) {
bsalomon@google.com2b446732013-02-12 16:47:41 +0000380 if (this->getStencil().doesWrite()) {
egdaniel0f1a7c42014-07-30 13:18:32 -0700381 return kEmitCoverage_BlendOptFlag;
bsalomon@google.com2b446732013-02-12 16:47:41 +0000382 } else {
383 return kSkipDraw_BlendOptFlag;
384 }
385 }
386
bsalomon62c447d2014-08-08 08:08:50 -0700387 bool hasCoverage = forceCoverage || !this->hasSolidCoverage();
bsalomon@google.com2b446732013-02-12 16:47:41 +0000388
389 // if we don't have coverage we can check whether the dst
390 // has to read at all. If not, we'll disable blending.
391 if (!hasCoverage) {
392 if (dstCoeffIsZero) {
393 if (kOne_GrBlendCoeff == *srcCoeff) {
394 // if there is no coverage and coeffs are (1,0) then we
395 // won't need to read the dst at all, it gets replaced by src
egdaniel0f1a7c42014-07-30 13:18:32 -0700396 *dstCoeff = kZero_GrBlendCoeff;
397 return kNone_BlendOpt;
bsalomon@google.com2b446732013-02-12 16:47:41 +0000398 } else if (kZero_GrBlendCoeff == *srcCoeff) {
399 // if the op is "clear" then we don't need to emit a color
400 // or blend, just write transparent black into the dst.
401 *srcCoeff = kOne_GrBlendCoeff;
402 *dstCoeff = kZero_GrBlendCoeff;
egdaniel0f1a7c42014-07-30 13:18:32 -0700403 return kEmitTransBlack_BlendOptFlag;
bsalomon@google.com2b446732013-02-12 16:47:41 +0000404 }
405 }
406 } else if (this->isCoverageDrawing()) {
407 // we have coverage but we aren't distinguishing it from alpha by request.
408 return kCoverageAsAlpha_BlendOptFlag;
409 } else {
410 // check whether coverage can be safely rolled into alpha
411 // of if we can skip color computation and just emit coverage
412 if (this->canTweakAlphaForCoverage()) {
413 return kCoverageAsAlpha_BlendOptFlag;
414 }
415 if (dstCoeffIsZero) {
416 if (kZero_GrBlendCoeff == *srcCoeff) {
417 // the source color is not included in the blend
418 // the dst coeff is effectively zero so blend works out to:
419 // (c)(0)D + (1-c)D = (1-c)D.
420 *dstCoeff = kISA_GrBlendCoeff;
421 return kEmitCoverage_BlendOptFlag;
422 } else if (srcAIsOne) {
423 // the dst coeff is effectively zero so blend works out to:
424 // cS + (c)(0)D + (1-c)D = cS + (1-c)D.
425 // If Sa is 1 then we can replace Sa with c
426 // and set dst coeff to 1-Sa.
427 *dstCoeff = kISA_GrBlendCoeff;
428 return kCoverageAsAlpha_BlendOptFlag;
429 }
430 } else if (dstCoeffIsOne) {
431 // the dst coeff is effectively one so blend works out to:
432 // cS + (c)(1)D + (1-c)D = cS + D.
433 *dstCoeff = kOne_GrBlendCoeff;
434 return kCoverageAsAlpha_BlendOptFlag;
435 }
436 }
egdaniel0f1a7c42014-07-30 13:18:32 -0700437
bsalomon@google.com2b446732013-02-12 16:47:41 +0000438 return kNone_BlendOpt;
439}
440
441////////////////////////////////////////////////////////////////////////////////
442
bsalomon@google.com2fdcdeb2012-10-08 17:15:55 +0000443void GrDrawState::AutoViewMatrixRestore::restore() {
444 if (NULL != fDrawState) {
commit-bot@chromium.org1acc3d72013-09-06 23:13:05 +0000445 SkDEBUGCODE(--fDrawState->fBlockEffectRemovalCnt;)
bsalomon2ed5ef82014-07-07 08:44:05 -0700446 fDrawState->fViewMatrix = fViewMatrix;
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000447 SkASSERT(fDrawState->numColorStages() >= fNumColorStages);
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000448 int numCoverageStages = fSavedCoordChanges.count() - fNumColorStages;
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000449 SkASSERT(fDrawState->numCoverageStages() >= numCoverageStages);
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000450
451 int i = 0;
joshualittbd769d02014-09-04 08:56:46 -0700452 if (fHasGeometryProcessor) {
453 SkASSERT(fDrawState->hasGeometryProcessor());
454 fDrawState->fGeometryProcessor->restoreCoordChange(fSavedCoordChanges[i++]);
455 }
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000456 for (int s = 0; s < fNumColorStages; ++s, ++i) {
egdaniel8cbf3d52014-08-21 06:27:22 -0700457 fDrawState->fColorStages[s].restoreCoordChange(fSavedCoordChanges[i]);
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000458 }
459 for (int s = 0; s < numCoverageStages; ++s, ++i) {
egdaniel8cbf3d52014-08-21 06:27:22 -0700460 fDrawState->fCoverageStages[s].restoreCoordChange(fSavedCoordChanges[i]);
bsalomon@google.com2fdcdeb2012-10-08 17:15:55 +0000461 }
bsalomon@google.com137f1342013-05-29 21:27:53 +0000462 fDrawState = NULL;
bsalomon@google.com2fdcdeb2012-10-08 17:15:55 +0000463 }
bsalomon@google.com2fdcdeb2012-10-08 17:15:55 +0000464}
465
466void GrDrawState::AutoViewMatrixRestore::set(GrDrawState* drawState,
bsalomon@google.comc7818882013-03-20 19:19:53 +0000467 const SkMatrix& preconcatMatrix) {
bsalomon@google.com2fdcdeb2012-10-08 17:15:55 +0000468 this->restore();
bsalomon@google.com5b3e8902012-10-05 20:13:28 +0000469
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000470 SkASSERT(NULL == fDrawState);
bsalomon@google.com137f1342013-05-29 21:27:53 +0000471 if (NULL == drawState || preconcatMatrix.isIdentity()) {
bsalomon@google.com2fdcdeb2012-10-08 17:15:55 +0000472 return;
473 }
bsalomon@google.com137f1342013-05-29 21:27:53 +0000474 fDrawState = drawState;
bsalomon@google.com2fdcdeb2012-10-08 17:15:55 +0000475
bsalomon@google.com2fdcdeb2012-10-08 17:15:55 +0000476 fViewMatrix = drawState->getViewMatrix();
bsalomon2ed5ef82014-07-07 08:44:05 -0700477 drawState->fViewMatrix.preConcat(preconcatMatrix);
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000478
479 this->doEffectCoordChanges(preconcatMatrix);
commit-bot@chromium.org1acc3d72013-09-06 23:13:05 +0000480 SkDEBUGCODE(++fDrawState->fBlockEffectRemovalCnt;)
bsalomon@google.com2fdcdeb2012-10-08 17:15:55 +0000481}
482
bsalomon@google.com137f1342013-05-29 21:27:53 +0000483bool GrDrawState::AutoViewMatrixRestore::setIdentity(GrDrawState* drawState) {
bsalomon@google.com2fdcdeb2012-10-08 17:15:55 +0000484 this->restore();
485
bsalomon@google.com137f1342013-05-29 21:27:53 +0000486 if (NULL == drawState) {
bsalomon@google.com2fdcdeb2012-10-08 17:15:55 +0000487 return false;
skia.committer@gmail.comf467ce72012-10-09 02:01:37 +0000488 }
bsalomon@google.com2fdcdeb2012-10-08 17:15:55 +0000489
bsalomon@google.com137f1342013-05-29 21:27:53 +0000490 if (drawState->getViewMatrix().isIdentity()) {
491 return true;
492 }
493
bsalomon@google.com5b3e8902012-10-05 20:13:28 +0000494 fViewMatrix = drawState->getViewMatrix();
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000495 if (0 == drawState->numTotalStages()) {
bsalomon2ed5ef82014-07-07 08:44:05 -0700496 drawState->fViewMatrix.reset();
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000497 fDrawState = drawState;
joshualittbd769d02014-09-04 08:56:46 -0700498 fHasGeometryProcessor = false;
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000499 fNumColorStages = 0;
500 fSavedCoordChanges.reset(0);
commit-bot@chromium.org1acc3d72013-09-06 23:13:05 +0000501 SkDEBUGCODE(++fDrawState->fBlockEffectRemovalCnt;)
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000502 return true;
503 } else {
504 SkMatrix inv;
505 if (!fViewMatrix.invert(&inv)) {
506 return false;
bsalomon@google.com5b3e8902012-10-05 20:13:28 +0000507 }
bsalomon2ed5ef82014-07-07 08:44:05 -0700508 drawState->fViewMatrix.reset();
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000509 fDrawState = drawState;
510 this->doEffectCoordChanges(inv);
commit-bot@chromium.org1acc3d72013-09-06 23:13:05 +0000511 SkDEBUGCODE(++fDrawState->fBlockEffectRemovalCnt;)
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000512 return true;
bsalomon@google.com5b3e8902012-10-05 20:13:28 +0000513 }
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000514}
515
516void GrDrawState::AutoViewMatrixRestore::doEffectCoordChanges(const SkMatrix& coordChangeMatrix) {
517 fSavedCoordChanges.reset(fDrawState->numTotalStages());
518 int i = 0;
519
joshualittbd769d02014-09-04 08:56:46 -0700520 fHasGeometryProcessor = false;
521 if (fDrawState->hasGeometryProcessor()) {
522 fDrawState->fGeometryProcessor->saveCoordChange(&fSavedCoordChanges[i++]);
523 fDrawState->fGeometryProcessor->localCoordChange(coordChangeMatrix);
524 fHasGeometryProcessor = true;
525 }
526
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000527 fNumColorStages = fDrawState->numColorStages();
528 for (int s = 0; s < fNumColorStages; ++s, ++i) {
egdaniel776bdbd2014-08-06 11:07:02 -0700529 fDrawState->getColorStage(s).saveCoordChange(&fSavedCoordChanges[i]);
egdaniel8cbf3d52014-08-21 06:27:22 -0700530 fDrawState->fColorStages[s].localCoordChange(coordChangeMatrix);
bsalomon@google.com137f1342013-05-29 21:27:53 +0000531 }
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000532
533 int numCoverageStages = fDrawState->numCoverageStages();
534 for (int s = 0; s < numCoverageStages; ++s, ++i) {
egdaniel776bdbd2014-08-06 11:07:02 -0700535 fDrawState->getCoverageStage(s).saveCoordChange(&fSavedCoordChanges[i]);
egdaniel8cbf3d52014-08-21 06:27:22 -0700536 fDrawState->fCoverageStages[s].localCoordChange(coordChangeMatrix);
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000537 }
bsalomon@google.com5b3e8902012-10-05 20:13:28 +0000538}
egdaniel21aed572014-08-26 12:24:06 -0700539
540bool GrDrawState::srcAlphaWillBeOne() const {
541 uint32_t validComponentFlags;
542 GrColor color;
543 // Check if per-vertex or constant color may have partial alpha
544 if (this->hasColorVertexAttribute()) {
545 if (fHints & kVertexColorsAreOpaque_Hint) {
546 validComponentFlags = kA_GrColorComponentFlag;
547 color = 0xFF << GrColor_SHIFT_A;
548 } else {
549 validComponentFlags = 0;
550 color = 0; // not strictly necessary but we get false alarms from tools about uninit.
551 }
552 } else {
553 validComponentFlags = kRGBA_GrColorComponentFlags;
554 color = this->getColor();
555 }
556
557 // Run through the color stages
558 for (int s = 0; s < this->numColorStages(); ++s) {
559 const GrEffect* effect = this->getColorStage(s).getEffect();
560 effect->getConstantColorComponents(&color, &validComponentFlags);
561 }
562
563 // Check whether coverage is treated as color. If so we run through the coverage computation.
564 if (this->isCoverageDrawing()) {
565 // The shader generated for coverage drawing runs the full coverage computation and then
566 // makes the shader output be the multiplication of color and coverage. We mirror that here.
567 GrColor coverage;
568 uint32_t coverageComponentFlags;
569 if (this->hasCoverageVertexAttribute()) {
570 coverageComponentFlags = 0;
571 coverage = 0; // suppresses any warnings.
572 } else {
573 coverageComponentFlags = kRGBA_GrColorComponentFlags;
574 coverage = this->getCoverageColor();
575 }
576
577 // Run through the coverage stages
joshualittbd769d02014-09-04 08:56:46 -0700578 if (this->hasGeometryProcessor()) {
579 const GrEffect* effect = fGeometryProcessor->getEffect();
580 effect->getConstantColorComponents(&coverage, &coverageComponentFlags);
581 }
egdaniel21aed572014-08-26 12:24:06 -0700582 for (int s = 0; s < this->numCoverageStages(); ++s) {
583 const GrEffect* effect = this->getCoverageStage(s).getEffect();
584 effect->getConstantColorComponents(&coverage, &coverageComponentFlags);
585 }
586
587 // Since the shader will multiply coverage and color, the only way the final A==1 is if
588 // coverage and color both have A==1.
589 return (kA_GrColorComponentFlag & validComponentFlags & coverageComponentFlags) &&
590 0xFF == GrColorUnpackA(color) && 0xFF == GrColorUnpackA(coverage);
591
592 }
593
594 return (kA_GrColorComponentFlag & validComponentFlags) && 0xFF == GrColorUnpackA(color);
595}
596
597////////////////////////////////////////////////////////////////////////////////
598
599bool GrDrawState::canIgnoreColorAttribute() const {
600 if (fBlendOptFlags & kInvalid_BlendOptFlag) {
601 this->getBlendOpts();
602 }
603 return SkToBool(fBlendOptFlags & (GrRODrawState::kEmitTransBlack_BlendOptFlag |
604 GrRODrawState::kEmitCoverage_BlendOptFlag));
605}
606