blob: 6acc202065b78a4872c2f52846709ab5c0b6e076 [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) {
bsalomon9b536522014-09-05 09:18:51 -0700302 // See the big comment on the class definition about GPs.
303 if (NULL != fOriginalGP) {
304 SkASSERT(fDrawState->getGeometryProcessor()->getEffect() == fOriginalGP);
305 fOriginalGP->unref();
306 fOriginalGP = NULL;
307 } else {
308 fDrawState->fGeometryProcessor.reset(NULL);
309 }
joshualittbd769d02014-09-04 08:56:46 -0700310
egdaniel21aed572014-08-26 12:24:06 -0700311 int m = fDrawState->numColorStages() - fColorEffectCnt;
312 SkASSERT(m >= 0);
313 fDrawState->fColorStages.pop_back_n(m);
bsalomon@google.comd62e88e2013-02-01 14:19:27 +0000314
egdaniel21aed572014-08-26 12:24:06 -0700315 int n = fDrawState->numCoverageStages() - fCoverageEffectCnt;
316 SkASSERT(n >= 0);
317 fDrawState->fCoverageStages.pop_back_n(n);
318 if (m + n > 0) {
319 fDrawState->invalidateBlendOptFlags();
320 }
321 SkDEBUGCODE(--fDrawState->fBlockEffectRemovalCnt;)
bsalomon@google.comd62e88e2013-02-01 14:19:27 +0000322 }
egdaniel21aed572014-08-26 12:24:06 -0700323 fDrawState = ds;
324 if (NULL != ds) {
bsalomon9b536522014-09-05 09:18:51 -0700325 SkASSERT(NULL == fOriginalGP);
326 if (NULL != ds->getGeometryProcessor()) {
327 fOriginalGP = SkRef(ds->getGeometryProcessor()->getEffect());
joshualittbd769d02014-09-04 08:56:46 -0700328 }
egdaniel21aed572014-08-26 12:24:06 -0700329 fColorEffectCnt = ds->numColorStages();
330 fCoverageEffectCnt = ds->numCoverageStages();
331 SkDEBUGCODE(++ds->fBlockEffectRemovalCnt;)
332 }
bsalomon@google.comd62e88e2013-02-01 14:19:27 +0000333}
334
jvanverth@google.comcc782382013-01-28 20:39:48 +0000335////////////////////////////////////////////////////////////////////////////////
336
egdaniel21aed572014-08-26 12:24:06 -0700337GrRODrawState::BlendOptFlags GrDrawState::getBlendOpts(bool forceCoverage,
338 GrBlendCoeff* srcCoeff,
339 GrBlendCoeff* dstCoeff) const {
bsalomon@google.com2b446732013-02-12 16:47:41 +0000340 GrBlendCoeff bogusSrcCoeff, bogusDstCoeff;
341 if (NULL == srcCoeff) {
342 srcCoeff = &bogusSrcCoeff;
343 }
bsalomon@google.com2b446732013-02-12 16:47:41 +0000344 if (NULL == dstCoeff) {
345 dstCoeff = &bogusDstCoeff;
346 }
egdaniel9514d242014-07-18 06:15:43 -0700347
348 if (forceCoverage) {
349 return this->calcBlendOpts(true, srcCoeff, dstCoeff);
350 }
351
352 if (0 == (fBlendOptFlags & kInvalid_BlendOptFlag)) {
353 *srcCoeff = fOptSrcBlend;
354 *dstCoeff = fOptDstBlend;
355 return fBlendOptFlags;
356 }
357
358 fBlendOptFlags = this->calcBlendOpts(forceCoverage, srcCoeff, dstCoeff);
359 fOptSrcBlend = *srcCoeff;
360 fOptDstBlend = *dstCoeff;
361
362 return fBlendOptFlags;
363}
364
egdaniel21aed572014-08-26 12:24:06 -0700365GrRODrawState::BlendOptFlags GrDrawState::calcBlendOpts(bool forceCoverage,
366 GrBlendCoeff* srcCoeff,
367 GrBlendCoeff* dstCoeff) const {
egdaniel9514d242014-07-18 06:15:43 -0700368 *srcCoeff = this->getSrcBlendCoeff();
bsalomon@google.com2b446732013-02-12 16:47:41 +0000369 *dstCoeff = this->getDstBlendCoeff();
370
371 if (this->isColorWriteDisabled()) {
372 *srcCoeff = kZero_GrBlendCoeff;
373 *dstCoeff = kOne_GrBlendCoeff;
374 }
375
jvanverth@google.com054ae992013-04-01 20:06:51 +0000376 bool srcAIsOne = this->srcAlphaWillBeOne();
bsalomon@google.com2b446732013-02-12 16:47:41 +0000377 bool dstCoeffIsOne = kOne_GrBlendCoeff == *dstCoeff ||
378 (kSA_GrBlendCoeff == *dstCoeff && srcAIsOne);
379 bool dstCoeffIsZero = kZero_GrBlendCoeff == *dstCoeff ||
380 (kISA_GrBlendCoeff == *dstCoeff && srcAIsOne);
381
bsalomon@google.com2b446732013-02-12 16:47:41 +0000382 // When coeffs are (0,1) there is no reason to draw at all, unless
383 // stenciling is enabled. Having color writes disabled is effectively
bsalomon62c447d2014-08-08 08:08:50 -0700384 // (0,1).
385 if ((kZero_GrBlendCoeff == *srcCoeff && dstCoeffIsOne)) {
bsalomon@google.com2b446732013-02-12 16:47:41 +0000386 if (this->getStencil().doesWrite()) {
egdaniel0f1a7c42014-07-30 13:18:32 -0700387 return kEmitCoverage_BlendOptFlag;
bsalomon@google.com2b446732013-02-12 16:47:41 +0000388 } else {
389 return kSkipDraw_BlendOptFlag;
390 }
391 }
392
bsalomon62c447d2014-08-08 08:08:50 -0700393 bool hasCoverage = forceCoverage || !this->hasSolidCoverage();
bsalomon@google.com2b446732013-02-12 16:47:41 +0000394
395 // if we don't have coverage we can check whether the dst
396 // has to read at all. If not, we'll disable blending.
397 if (!hasCoverage) {
398 if (dstCoeffIsZero) {
399 if (kOne_GrBlendCoeff == *srcCoeff) {
400 // if there is no coverage and coeffs are (1,0) then we
401 // won't need to read the dst at all, it gets replaced by src
egdaniel0f1a7c42014-07-30 13:18:32 -0700402 *dstCoeff = kZero_GrBlendCoeff;
403 return kNone_BlendOpt;
bsalomon@google.com2b446732013-02-12 16:47:41 +0000404 } else if (kZero_GrBlendCoeff == *srcCoeff) {
405 // if the op is "clear" then we don't need to emit a color
406 // or blend, just write transparent black into the dst.
407 *srcCoeff = kOne_GrBlendCoeff;
408 *dstCoeff = kZero_GrBlendCoeff;
egdaniel0f1a7c42014-07-30 13:18:32 -0700409 return kEmitTransBlack_BlendOptFlag;
bsalomon@google.com2b446732013-02-12 16:47:41 +0000410 }
411 }
412 } else if (this->isCoverageDrawing()) {
413 // we have coverage but we aren't distinguishing it from alpha by request.
414 return kCoverageAsAlpha_BlendOptFlag;
415 } else {
416 // check whether coverage can be safely rolled into alpha
417 // of if we can skip color computation and just emit coverage
418 if (this->canTweakAlphaForCoverage()) {
419 return kCoverageAsAlpha_BlendOptFlag;
420 }
421 if (dstCoeffIsZero) {
422 if (kZero_GrBlendCoeff == *srcCoeff) {
423 // the source color is not included in the blend
424 // the dst coeff is effectively zero so blend works out to:
425 // (c)(0)D + (1-c)D = (1-c)D.
426 *dstCoeff = kISA_GrBlendCoeff;
427 return kEmitCoverage_BlendOptFlag;
428 } else if (srcAIsOne) {
429 // the dst coeff is effectively zero so blend works out to:
430 // cS + (c)(0)D + (1-c)D = cS + (1-c)D.
431 // If Sa is 1 then we can replace Sa with c
432 // and set dst coeff to 1-Sa.
433 *dstCoeff = kISA_GrBlendCoeff;
434 return kCoverageAsAlpha_BlendOptFlag;
435 }
436 } else if (dstCoeffIsOne) {
437 // the dst coeff is effectively one so blend works out to:
438 // cS + (c)(1)D + (1-c)D = cS + D.
439 *dstCoeff = kOne_GrBlendCoeff;
440 return kCoverageAsAlpha_BlendOptFlag;
441 }
442 }
egdaniel0f1a7c42014-07-30 13:18:32 -0700443
bsalomon@google.com2b446732013-02-12 16:47:41 +0000444 return kNone_BlendOpt;
445}
446
447////////////////////////////////////////////////////////////////////////////////
448
bsalomon@google.com2fdcdeb2012-10-08 17:15:55 +0000449void GrDrawState::AutoViewMatrixRestore::restore() {
450 if (NULL != fDrawState) {
commit-bot@chromium.org1acc3d72013-09-06 23:13:05 +0000451 SkDEBUGCODE(--fDrawState->fBlockEffectRemovalCnt;)
bsalomon2ed5ef82014-07-07 08:44:05 -0700452 fDrawState->fViewMatrix = fViewMatrix;
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000453 SkASSERT(fDrawState->numColorStages() >= fNumColorStages);
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000454 int numCoverageStages = fSavedCoordChanges.count() - fNumColorStages;
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000455 SkASSERT(fDrawState->numCoverageStages() >= numCoverageStages);
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000456
457 int i = 0;
joshualittbd769d02014-09-04 08:56:46 -0700458 if (fHasGeometryProcessor) {
459 SkASSERT(fDrawState->hasGeometryProcessor());
460 fDrawState->fGeometryProcessor->restoreCoordChange(fSavedCoordChanges[i++]);
461 }
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000462 for (int s = 0; s < fNumColorStages; ++s, ++i) {
egdaniel8cbf3d52014-08-21 06:27:22 -0700463 fDrawState->fColorStages[s].restoreCoordChange(fSavedCoordChanges[i]);
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000464 }
465 for (int s = 0; s < numCoverageStages; ++s, ++i) {
egdaniel8cbf3d52014-08-21 06:27:22 -0700466 fDrawState->fCoverageStages[s].restoreCoordChange(fSavedCoordChanges[i]);
bsalomon@google.com2fdcdeb2012-10-08 17:15:55 +0000467 }
bsalomon@google.com137f1342013-05-29 21:27:53 +0000468 fDrawState = NULL;
bsalomon@google.com2fdcdeb2012-10-08 17:15:55 +0000469 }
bsalomon@google.com2fdcdeb2012-10-08 17:15:55 +0000470}
471
472void GrDrawState::AutoViewMatrixRestore::set(GrDrawState* drawState,
bsalomon@google.comc7818882013-03-20 19:19:53 +0000473 const SkMatrix& preconcatMatrix) {
bsalomon@google.com2fdcdeb2012-10-08 17:15:55 +0000474 this->restore();
bsalomon@google.com5b3e8902012-10-05 20:13:28 +0000475
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000476 SkASSERT(NULL == fDrawState);
bsalomon@google.com137f1342013-05-29 21:27:53 +0000477 if (NULL == drawState || preconcatMatrix.isIdentity()) {
bsalomon@google.com2fdcdeb2012-10-08 17:15:55 +0000478 return;
479 }
bsalomon@google.com137f1342013-05-29 21:27:53 +0000480 fDrawState = drawState;
bsalomon@google.com2fdcdeb2012-10-08 17:15:55 +0000481
bsalomon@google.com2fdcdeb2012-10-08 17:15:55 +0000482 fViewMatrix = drawState->getViewMatrix();
bsalomon2ed5ef82014-07-07 08:44:05 -0700483 drawState->fViewMatrix.preConcat(preconcatMatrix);
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000484
485 this->doEffectCoordChanges(preconcatMatrix);
commit-bot@chromium.org1acc3d72013-09-06 23:13:05 +0000486 SkDEBUGCODE(++fDrawState->fBlockEffectRemovalCnt;)
bsalomon@google.com2fdcdeb2012-10-08 17:15:55 +0000487}
488
bsalomon@google.com137f1342013-05-29 21:27:53 +0000489bool GrDrawState::AutoViewMatrixRestore::setIdentity(GrDrawState* drawState) {
bsalomon@google.com2fdcdeb2012-10-08 17:15:55 +0000490 this->restore();
491
bsalomon@google.com137f1342013-05-29 21:27:53 +0000492 if (NULL == drawState) {
bsalomon@google.com2fdcdeb2012-10-08 17:15:55 +0000493 return false;
skia.committer@gmail.comf467ce72012-10-09 02:01:37 +0000494 }
bsalomon@google.com2fdcdeb2012-10-08 17:15:55 +0000495
bsalomon@google.com137f1342013-05-29 21:27:53 +0000496 if (drawState->getViewMatrix().isIdentity()) {
497 return true;
498 }
499
bsalomon@google.com5b3e8902012-10-05 20:13:28 +0000500 fViewMatrix = drawState->getViewMatrix();
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000501 if (0 == drawState->numTotalStages()) {
bsalomon2ed5ef82014-07-07 08:44:05 -0700502 drawState->fViewMatrix.reset();
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000503 fDrawState = drawState;
joshualittbd769d02014-09-04 08:56:46 -0700504 fHasGeometryProcessor = false;
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000505 fNumColorStages = 0;
506 fSavedCoordChanges.reset(0);
commit-bot@chromium.org1acc3d72013-09-06 23:13:05 +0000507 SkDEBUGCODE(++fDrawState->fBlockEffectRemovalCnt;)
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000508 return true;
509 } else {
510 SkMatrix inv;
511 if (!fViewMatrix.invert(&inv)) {
512 return false;
bsalomon@google.com5b3e8902012-10-05 20:13:28 +0000513 }
bsalomon2ed5ef82014-07-07 08:44:05 -0700514 drawState->fViewMatrix.reset();
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000515 fDrawState = drawState;
516 this->doEffectCoordChanges(inv);
commit-bot@chromium.org1acc3d72013-09-06 23:13:05 +0000517 SkDEBUGCODE(++fDrawState->fBlockEffectRemovalCnt;)
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000518 return true;
bsalomon@google.com5b3e8902012-10-05 20:13:28 +0000519 }
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000520}
521
522void GrDrawState::AutoViewMatrixRestore::doEffectCoordChanges(const SkMatrix& coordChangeMatrix) {
523 fSavedCoordChanges.reset(fDrawState->numTotalStages());
524 int i = 0;
525
joshualittbd769d02014-09-04 08:56:46 -0700526 fHasGeometryProcessor = false;
527 if (fDrawState->hasGeometryProcessor()) {
528 fDrawState->fGeometryProcessor->saveCoordChange(&fSavedCoordChanges[i++]);
529 fDrawState->fGeometryProcessor->localCoordChange(coordChangeMatrix);
530 fHasGeometryProcessor = true;
531 }
532
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000533 fNumColorStages = fDrawState->numColorStages();
534 for (int s = 0; s < fNumColorStages; ++s, ++i) {
egdaniel776bdbd2014-08-06 11:07:02 -0700535 fDrawState->getColorStage(s).saveCoordChange(&fSavedCoordChanges[i]);
egdaniel8cbf3d52014-08-21 06:27:22 -0700536 fDrawState->fColorStages[s].localCoordChange(coordChangeMatrix);
bsalomon@google.com137f1342013-05-29 21:27:53 +0000537 }
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000538
539 int numCoverageStages = fDrawState->numCoverageStages();
540 for (int s = 0; s < numCoverageStages; ++s, ++i) {
egdaniel776bdbd2014-08-06 11:07:02 -0700541 fDrawState->getCoverageStage(s).saveCoordChange(&fSavedCoordChanges[i]);
egdaniel8cbf3d52014-08-21 06:27:22 -0700542 fDrawState->fCoverageStages[s].localCoordChange(coordChangeMatrix);
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000543 }
bsalomon@google.com5b3e8902012-10-05 20:13:28 +0000544}
egdaniel21aed572014-08-26 12:24:06 -0700545
546bool GrDrawState::srcAlphaWillBeOne() const {
547 uint32_t validComponentFlags;
548 GrColor color;
549 // Check if per-vertex or constant color may have partial alpha
550 if (this->hasColorVertexAttribute()) {
551 if (fHints & kVertexColorsAreOpaque_Hint) {
552 validComponentFlags = kA_GrColorComponentFlag;
553 color = 0xFF << GrColor_SHIFT_A;
554 } else {
555 validComponentFlags = 0;
556 color = 0; // not strictly necessary but we get false alarms from tools about uninit.
557 }
558 } else {
559 validComponentFlags = kRGBA_GrColorComponentFlags;
560 color = this->getColor();
561 }
562
563 // Run through the color stages
564 for (int s = 0; s < this->numColorStages(); ++s) {
565 const GrEffect* effect = this->getColorStage(s).getEffect();
566 effect->getConstantColorComponents(&color, &validComponentFlags);
567 }
568
569 // Check whether coverage is treated as color. If so we run through the coverage computation.
570 if (this->isCoverageDrawing()) {
571 // The shader generated for coverage drawing runs the full coverage computation and then
572 // makes the shader output be the multiplication of color and coverage. We mirror that here.
573 GrColor coverage;
574 uint32_t coverageComponentFlags;
575 if (this->hasCoverageVertexAttribute()) {
576 coverageComponentFlags = 0;
577 coverage = 0; // suppresses any warnings.
578 } else {
579 coverageComponentFlags = kRGBA_GrColorComponentFlags;
580 coverage = this->getCoverageColor();
581 }
582
583 // Run through the coverage stages
joshualittbd769d02014-09-04 08:56:46 -0700584 if (this->hasGeometryProcessor()) {
585 const GrEffect* effect = fGeometryProcessor->getEffect();
586 effect->getConstantColorComponents(&coverage, &coverageComponentFlags);
587 }
egdaniel21aed572014-08-26 12:24:06 -0700588 for (int s = 0; s < this->numCoverageStages(); ++s) {
589 const GrEffect* effect = this->getCoverageStage(s).getEffect();
590 effect->getConstantColorComponents(&coverage, &coverageComponentFlags);
591 }
592
593 // Since the shader will multiply coverage and color, the only way the final A==1 is if
594 // coverage and color both have A==1.
595 return (kA_GrColorComponentFlag & validComponentFlags & coverageComponentFlags) &&
596 0xFF == GrColorUnpackA(color) && 0xFF == GrColorUnpackA(coverage);
597
598 }
599
600 return (kA_GrColorComponentFlag & validComponentFlags) && 0xFF == GrColorUnpackA(color);
601}
602
603////////////////////////////////////////////////////////////////////////////////
604
605bool GrDrawState::canIgnoreColorAttribute() const {
606 if (fBlendOptFlags & kInvalid_BlendOptFlag) {
607 this->getBlendOpts();
608 }
609 return SkToBool(fBlendOptFlags & (GrRODrawState::kEmitTransBlack_BlendOptFlag |
610 GrRODrawState::kEmitCoverage_BlendOptFlag));
611}
612