blob: a6b3d68238cdc18a20f527c9f7a3dccd5b05b8c9 [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()) {
egdaniel776bdbd2014-08-06 11:07:02 -070057 for (int i = 0; i < this->numColorStages(); ++i) {
egdaniel8cbf3d52014-08-21 06:27:22 -070058 fColorStages[i].localCoordChange(preConcatMatrix);
bsalomon8f727332014-08-05 07:50:06 -070059 }
egdaniel776bdbd2014-08-06 11:07:02 -070060 for (int i = 0; i < this->numCoverageStages(); ++i) {
egdaniel8cbf3d52014-08-21 06:27:22 -070061 fCoverageStages[i].localCoordChange(preConcatMatrix);
bsalomon8f727332014-08-05 07:50:06 -070062 }
63 this->invalidateBlendOptFlags();
64 }
65}
66
67GrDrawState& GrDrawState::operator=(const GrDrawState& that) {
68 SkASSERT(0 == fBlockEffectRemovalCnt || 0 == this->numTotalStages());
69 this->setRenderTarget(that.fRenderTarget.get());
70 fColor = that.fColor;
71 fViewMatrix = that.fViewMatrix;
egdaniel8cbf3d52014-08-21 06:27:22 -070072 fSrcBlend = that.fSrcBlend;
73 fDstBlend = that.fDstBlend;
bsalomon8f727332014-08-05 07:50:06 -070074 fBlendConstant = that.fBlendConstant;
75 fFlagBits = that.fFlagBits;
76 fVACount = that.fVACount;
77 fVAPtr = that.fVAPtr;
egdanielab78e062014-08-22 07:19:35 -070078 fVertexSize = that.fVertexSize;
bsalomon8f727332014-08-05 07:50:06 -070079 fStencilSettings = that.fStencilSettings;
80 fCoverage = that.fCoverage;
81 fDrawFace = that.fDrawFace;
egdaniel8cbf3d52014-08-21 06:27:22 -070082 fColorStages = that.fColorStages;
83 fCoverageStages = that.fCoverageStages;
bsalomon8f727332014-08-05 07:50:06 -070084 fOptSrcBlend = that.fOptSrcBlend;
85 fOptDstBlend = that.fOptDstBlend;
86 fBlendOptFlags = that.fBlendOptFlags;
87
bsalomon62c447d2014-08-08 08:08:50 -070088 fHints = that.fHints;
egdaniel776bdbd2014-08-06 11:07:02 -070089
bsalomon8f727332014-08-05 07:50:06 -070090 memcpy(fFixedFunctionVertexAttribIndices,
91 that.fFixedFunctionVertexAttribIndices,
92 sizeof(fFixedFunctionVertexAttribIndices));
93 return *this;
94}
95
96void GrDrawState::onReset(const SkMatrix* initialViewMatrix) {
97 SkASSERT(0 == fBlockEffectRemovalCnt || 0 == this->numTotalStages());
egdaniel8cbf3d52014-08-21 06:27:22 -070098 fColorStages.reset();
99 fCoverageStages.reset();
bsalomon8f727332014-08-05 07:50:06 -0700100
101 fRenderTarget.reset(NULL);
102
103 this->setDefaultVertexAttribs();
104
105 fColor = 0xffffffff;
106 if (NULL == initialViewMatrix) {
107 fViewMatrix.reset();
108 } else {
109 fViewMatrix = *initialViewMatrix;
110 }
egdaniel8cbf3d52014-08-21 06:27:22 -0700111 fSrcBlend = kOne_GrBlendCoeff;
112 fDstBlend = kZero_GrBlendCoeff;
bsalomon8f727332014-08-05 07:50:06 -0700113 fBlendConstant = 0x0;
114 fFlagBits = 0x0;
115 fStencilSettings.setDisabled();
egdaniel8cbf3d52014-08-21 06:27:22 -0700116 fCoverage = 0xff;
bsalomon8f727332014-08-05 07:50:06 -0700117 fDrawFace = kBoth_DrawFace;
118
bsalomon62c447d2014-08-08 08:08:50 -0700119 fHints = 0;
120
bsalomon8f727332014-08-05 07:50:06 -0700121 this->invalidateBlendOptFlags();
122}
123
bsalomon@google.com137f1342013-05-29 21:27:53 +0000124bool GrDrawState::setIdentityViewMatrix() {
egdaniel776bdbd2014-08-06 11:07:02 -0700125 if (this->numTotalStages()) {
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000126 SkMatrix invVM;
bsalomon2ed5ef82014-07-07 08:44:05 -0700127 if (!fViewMatrix.invert(&invVM)) {
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000128 // sad trombone sound
129 return false;
130 }
egdaniel776bdbd2014-08-06 11:07:02 -0700131 for (int s = 0; s < this->numColorStages(); ++s) {
egdaniel8cbf3d52014-08-21 06:27:22 -0700132 fColorStages[s].localCoordChange(invVM);
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000133 }
egdaniel776bdbd2014-08-06 11:07:02 -0700134 for (int s = 0; s < this->numCoverageStages(); ++s) {
egdaniel8cbf3d52014-08-21 06:27:22 -0700135 fCoverageStages[s].localCoordChange(invVM);
bsalomon@google.com137f1342013-05-29 21:27:53 +0000136 }
137 }
bsalomon2ed5ef82014-07-07 08:44:05 -0700138 fViewMatrix.reset();
bsalomon@google.com137f1342013-05-29 21:27:53 +0000139 return true;
140}
141
commit-bot@chromium.orgbb6a3172013-05-28 17:25:49 +0000142void GrDrawState::setFromPaint(const GrPaint& paint, const SkMatrix& vm, GrRenderTarget* rt) {
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000143 SkASSERT(0 == fBlockEffectRemovalCnt || 0 == this->numTotalStages());
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000144
egdaniel8cbf3d52014-08-21 06:27:22 -0700145 fColorStages.reset();
146 fCoverageStages.reset();
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000147
commit-bot@chromium.org42dacab2013-07-13 17:24:24 +0000148 for (int i = 0; i < paint.numColorStages(); ++i) {
egdaniel8cbf3d52014-08-21 06:27:22 -0700149 fColorStages.push_back(paint.getColorStage(i));
bsalomon@google.comaf84e742012-10-05 13:23:24 +0000150 }
151
commit-bot@chromium.org42dacab2013-07-13 17:24:24 +0000152 for (int i = 0; i < paint.numCoverageStages(); ++i) {
egdaniel8cbf3d52014-08-21 06:27:22 -0700153 fCoverageStages.push_back(paint.getCoverageStage(i));
bsalomon@google.comaf84e742012-10-05 13:23:24 +0000154 }
155
commit-bot@chromium.orgbb6a3172013-05-28 17:25:49 +0000156 this->setRenderTarget(rt);
bsalomon@google.comaf84e742012-10-05 13:23:24 +0000157
bsalomon2ed5ef82014-07-07 08:44:05 -0700158 fViewMatrix = vm;
commit-bot@chromium.orgbb6a3172013-05-28 17:25:49 +0000159
160 // These have no equivalent in GrPaint, set them to defaults
bsalomon2ed5ef82014-07-07 08:44:05 -0700161 fBlendConstant = 0x0;
162 fDrawFace = kBoth_DrawFace;
163 fStencilSettings.setDisabled();
commit-bot@chromium.orgbb6a3172013-05-28 17:25:49 +0000164 this->resetStateFlags();
bsalomon62c447d2014-08-08 08:08:50 -0700165 fHints = 0;
commit-bot@chromium.orgbb6a3172013-05-28 17:25:49 +0000166
bsalomon@google.com21c10c52013-06-13 17:44:07 +0000167 // Enable the clip bit
168 this->enableState(GrDrawState::kClip_StateBit);
169
commit-bot@chromium.orgbb6a3172013-05-28 17:25:49 +0000170 this->setColor(paint.getColor());
bsalomon@google.comc7448ce2012-10-05 19:04:13 +0000171 this->setState(GrDrawState::kDither_StateBit, paint.isDither());
172 this->setState(GrDrawState::kHWAntialias_StateBit, paint.isAntiAlias());
bsalomon@google.comaf84e742012-10-05 13:23:24 +0000173
bsalomon@google.comc7448ce2012-10-05 19:04:13 +0000174 this->setBlendFunc(paint.getSrcBlendCoeff(), paint.getDstBlendCoeff());
bsalomon@google.comc7448ce2012-10-05 19:04:13 +0000175 this->setCoverage(paint.getCoverage());
egdaniel9514d242014-07-18 06:15:43 -0700176 this->invalidateBlendOptFlags();
bsalomon@google.comaf84e742012-10-05 13:23:24 +0000177}
bsalomon@google.com5b3e8902012-10-05 20:13:28 +0000178
179////////////////////////////////////////////////////////////////////////////////
180
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000181static size_t vertex_size(const GrVertexAttrib* attribs, int count) {
182 // this works as long as we're 4 byte-aligned
commit-bot@chromium.org515dcd32013-08-28 14:17:03 +0000183#ifdef SK_DEBUG
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000184 uint32_t overlapCheck = 0;
185#endif
egdaniel21aed572014-08-26 12:24:06 -0700186 SkASSERT(count <= GrRODrawState::kMaxVertexAttribCnt);
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000187 size_t size = 0;
188 for (int index = 0; index < count; ++index) {
jvanverth@google.com054ae992013-04-01 20:06:51 +0000189 size_t attribSize = GrVertexAttribTypeSize(attribs[index].fType);
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000190 size += attribSize;
commit-bot@chromium.org515dcd32013-08-28 14:17:03 +0000191#ifdef SK_DEBUG
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000192 size_t dwordCount = attribSize >> 2;
193 uint32_t mask = (1 << dwordCount)-1;
194 size_t offsetShift = attribs[index].fOffset >> 2;
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000195 SkASSERT(!(overlapCheck & (mask << offsetShift)));
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000196 overlapCheck |= (mask << offsetShift);
197#endif
jvanverth@google.comcc782382013-01-28 20:39:48 +0000198 }
199 return size;
200}
201
202////////////////////////////////////////////////////////////////////////////////
203
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000204void GrDrawState::setVertexAttribs(const GrVertexAttrib* attribs, int count) {
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000205 SkASSERT(count <= kMaxVertexAttribCnt);
robertphillips@google.com42903302013-04-20 12:26:07 +0000206
bsalomon2ed5ef82014-07-07 08:44:05 -0700207 fVAPtr = attribs;
208 fVACount = count;
egdanielab78e062014-08-22 07:19:35 -0700209 fVertexSize = vertex_size(fVAPtr, fVACount);
jvanverth@google.com054ae992013-04-01 20:06:51 +0000210
211 // Set all the indices to -1
bsalomon2ed5ef82014-07-07 08:44:05 -0700212 memset(fFixedFunctionVertexAttribIndices,
jvanverth@google.com054ae992013-04-01 20:06:51 +0000213 0xff,
bsalomon2ed5ef82014-07-07 08:44:05 -0700214 sizeof(fFixedFunctionVertexAttribIndices));
commit-bot@chromium.org515dcd32013-08-28 14:17:03 +0000215#ifdef SK_DEBUG
jvanverth@google.com054ae992013-04-01 20:06:51 +0000216 uint32_t overlapCheck = 0;
217#endif
218 for (int i = 0; i < count; ++i) {
219 if (attribs[i].fBinding < kGrFixedFunctionVertexAttribBindingCnt) {
220 // The fixed function attribs can only be specified once
bsalomon2ed5ef82014-07-07 08:44:05 -0700221 SkASSERT(-1 == fFixedFunctionVertexAttribIndices[attribs[i].fBinding]);
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000222 SkASSERT(GrFixedFunctionVertexAttribVectorCount(attribs[i].fBinding) ==
jvanverth@google.com054ae992013-04-01 20:06:51 +0000223 GrVertexAttribTypeVectorCount(attribs[i].fType));
bsalomon2ed5ef82014-07-07 08:44:05 -0700224 fFixedFunctionVertexAttribIndices[attribs[i].fBinding] = i;
jvanverth@google.com054ae992013-04-01 20:06:51 +0000225 }
commit-bot@chromium.org515dcd32013-08-28 14:17:03 +0000226#ifdef SK_DEBUG
jvanverth@google.com054ae992013-04-01 20:06:51 +0000227 size_t dwordCount = GrVertexAttribTypeSize(attribs[i].fType) >> 2;
228 uint32_t mask = (1 << dwordCount)-1;
229 size_t offsetShift = attribs[i].fOffset >> 2;
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000230 SkASSERT(!(overlapCheck & (mask << offsetShift)));
jvanverth@google.com054ae992013-04-01 20:06:51 +0000231 overlapCheck |= (mask << offsetShift);
232#endif
jvanverth@google.comcc782382013-01-28 20:39:48 +0000233 }
egdaniel9514d242014-07-18 06:15:43 -0700234 this->invalidateBlendOptFlags();
jvanverth@google.com054ae992013-04-01 20:06:51 +0000235 // Positions must be specified.
bsalomon2ed5ef82014-07-07 08:44:05 -0700236 SkASSERT(-1 != fFixedFunctionVertexAttribIndices[kPosition_GrVertexAttribBinding]);
jvanverth@google.comcc782382013-01-28 20:39:48 +0000237}
238
239////////////////////////////////////////////////////////////////////////////////
240
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000241void GrDrawState::setDefaultVertexAttribs() {
jvanverth@google.com054ae992013-04-01 20:06:51 +0000242 static const GrVertexAttrib kPositionAttrib =
243 {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding};
robertphillips@google.com42903302013-04-20 12:26:07 +0000244
bsalomon2ed5ef82014-07-07 08:44:05 -0700245 fVAPtr = &kPositionAttrib;
246 fVACount = 1;
egdanielab78e062014-08-22 07:19:35 -0700247 fVertexSize = GrVertexAttribTypeSize(kVec2f_GrVertexAttribType);
robertphillips@google.com42903302013-04-20 12:26:07 +0000248
jvanverth@google.com054ae992013-04-01 20:06:51 +0000249 // set all the fixed function indices to -1 except position.
bsalomon2ed5ef82014-07-07 08:44:05 -0700250 memset(fFixedFunctionVertexAttribIndices,
jvanverth@google.com054ae992013-04-01 20:06:51 +0000251 0xff,
bsalomon2ed5ef82014-07-07 08:44:05 -0700252 sizeof(fFixedFunctionVertexAttribIndices));
253 fFixedFunctionVertexAttribIndices[kPosition_GrVertexAttribBinding] = 0;
egdaniel9514d242014-07-18 06:15:43 -0700254 this->invalidateBlendOptFlags();
jvanverth@google.comcc782382013-01-28 20:39:48 +0000255}
256
257////////////////////////////////////////////////////////////////////////////////
258
bsalomon62c447d2014-08-08 08:08:50 -0700259bool GrDrawState::couldApplyCoverage(const GrDrawTargetCaps& caps) const {
260 if (caps.dualSourceBlendingSupport()) {
261 return true;
262 }
263 // we can correctly apply coverage if a) we have dual source blending
264 // or b) one of our blend optimizations applies
265 // or c) the src, dst blend coeffs are 1,0 and we will read Dst Color
266 GrBlendCoeff srcCoeff;
267 GrBlendCoeff dstCoeff;
egdaniel21aed572014-08-26 12:24:06 -0700268 GrRODrawState::BlendOptFlags flag = this->getBlendOpts(true, &srcCoeff, &dstCoeff);
269 return GrRODrawState::kNone_BlendOpt != flag ||
bsalomon62c447d2014-08-08 08:08:50 -0700270 (this->willEffectReadDstColor() &&
271 kOne_GrBlendCoeff == srcCoeff && kZero_GrBlendCoeff == dstCoeff);
272}
273
egdaniel21aed572014-08-26 12:24:06 -0700274//////////////////////////////////////////////////////////////////////////////
jvanverth@google.comcc782382013-01-28 20:39:48 +0000275
egdaniel21aed572014-08-26 12:24:06 -0700276GrDrawState::AutoVertexAttribRestore::AutoVertexAttribRestore(
277 GrDrawState* drawState) {
278 SkASSERT(NULL != drawState);
279 fDrawState = drawState;
280 fVAPtr = drawState->fVAPtr;
281 fVACount = drawState->fVACount;
282 fDrawState->setDefaultVertexAttribs();
jvanverth@google.comcc782382013-01-28 20:39:48 +0000283}
284
egdaniel21aed572014-08-26 12:24:06 -0700285//////////////////////////////////////////////////////////////////////////////s
bsalomon@google.comd62e88e2013-02-01 14:19:27 +0000286
egdaniel21aed572014-08-26 12:24:06 -0700287void GrDrawState::AutoRestoreEffects::set(GrDrawState* ds) {
288 if (NULL != fDrawState) {
289 int m = fDrawState->numColorStages() - fColorEffectCnt;
290 SkASSERT(m >= 0);
291 fDrawState->fColorStages.pop_back_n(m);
bsalomon@google.comd62e88e2013-02-01 14:19:27 +0000292
egdaniel21aed572014-08-26 12:24:06 -0700293 int n = fDrawState->numCoverageStages() - fCoverageEffectCnt;
294 SkASSERT(n >= 0);
295 fDrawState->fCoverageStages.pop_back_n(n);
296 if (m + n > 0) {
297 fDrawState->invalidateBlendOptFlags();
298 }
299 SkDEBUGCODE(--fDrawState->fBlockEffectRemovalCnt;)
bsalomon@google.comd62e88e2013-02-01 14:19:27 +0000300 }
egdaniel21aed572014-08-26 12:24:06 -0700301 fDrawState = ds;
302 if (NULL != ds) {
303 fColorEffectCnt = ds->numColorStages();
304 fCoverageEffectCnt = ds->numCoverageStages();
305 SkDEBUGCODE(++ds->fBlockEffectRemovalCnt;)
306 }
bsalomon@google.comd62e88e2013-02-01 14:19:27 +0000307}
308
jvanverth@google.comcc782382013-01-28 20:39:48 +0000309////////////////////////////////////////////////////////////////////////////////
310
egdaniel21aed572014-08-26 12:24:06 -0700311GrRODrawState::BlendOptFlags GrDrawState::getBlendOpts(bool forceCoverage,
312 GrBlendCoeff* srcCoeff,
313 GrBlendCoeff* dstCoeff) const {
bsalomon@google.com2b446732013-02-12 16:47:41 +0000314 GrBlendCoeff bogusSrcCoeff, bogusDstCoeff;
315 if (NULL == srcCoeff) {
316 srcCoeff = &bogusSrcCoeff;
317 }
bsalomon@google.com2b446732013-02-12 16:47:41 +0000318 if (NULL == dstCoeff) {
319 dstCoeff = &bogusDstCoeff;
320 }
egdaniel9514d242014-07-18 06:15:43 -0700321
322 if (forceCoverage) {
323 return this->calcBlendOpts(true, srcCoeff, dstCoeff);
324 }
325
326 if (0 == (fBlendOptFlags & kInvalid_BlendOptFlag)) {
327 *srcCoeff = fOptSrcBlend;
328 *dstCoeff = fOptDstBlend;
329 return fBlendOptFlags;
330 }
331
332 fBlendOptFlags = this->calcBlendOpts(forceCoverage, srcCoeff, dstCoeff);
333 fOptSrcBlend = *srcCoeff;
334 fOptDstBlend = *dstCoeff;
335
336 return fBlendOptFlags;
337}
338
egdaniel21aed572014-08-26 12:24:06 -0700339GrRODrawState::BlendOptFlags GrDrawState::calcBlendOpts(bool forceCoverage,
340 GrBlendCoeff* srcCoeff,
341 GrBlendCoeff* dstCoeff) const {
egdaniel9514d242014-07-18 06:15:43 -0700342 *srcCoeff = this->getSrcBlendCoeff();
bsalomon@google.com2b446732013-02-12 16:47:41 +0000343 *dstCoeff = this->getDstBlendCoeff();
344
345 if (this->isColorWriteDisabled()) {
346 *srcCoeff = kZero_GrBlendCoeff;
347 *dstCoeff = kOne_GrBlendCoeff;
348 }
349
jvanverth@google.com054ae992013-04-01 20:06:51 +0000350 bool srcAIsOne = this->srcAlphaWillBeOne();
bsalomon@google.com2b446732013-02-12 16:47:41 +0000351 bool dstCoeffIsOne = kOne_GrBlendCoeff == *dstCoeff ||
352 (kSA_GrBlendCoeff == *dstCoeff && srcAIsOne);
353 bool dstCoeffIsZero = kZero_GrBlendCoeff == *dstCoeff ||
354 (kISA_GrBlendCoeff == *dstCoeff && srcAIsOne);
355
bsalomon@google.com2b446732013-02-12 16:47:41 +0000356 // When coeffs are (0,1) there is no reason to draw at all, unless
357 // stenciling is enabled. Having color writes disabled is effectively
bsalomon62c447d2014-08-08 08:08:50 -0700358 // (0,1).
359 if ((kZero_GrBlendCoeff == *srcCoeff && dstCoeffIsOne)) {
bsalomon@google.com2b446732013-02-12 16:47:41 +0000360 if (this->getStencil().doesWrite()) {
egdaniel0f1a7c42014-07-30 13:18:32 -0700361 return kEmitCoverage_BlendOptFlag;
bsalomon@google.com2b446732013-02-12 16:47:41 +0000362 } else {
363 return kSkipDraw_BlendOptFlag;
364 }
365 }
366
bsalomon62c447d2014-08-08 08:08:50 -0700367 bool hasCoverage = forceCoverage || !this->hasSolidCoverage();
bsalomon@google.com2b446732013-02-12 16:47:41 +0000368
369 // if we don't have coverage we can check whether the dst
370 // has to read at all. If not, we'll disable blending.
371 if (!hasCoverage) {
372 if (dstCoeffIsZero) {
373 if (kOne_GrBlendCoeff == *srcCoeff) {
374 // if there is no coverage and coeffs are (1,0) then we
375 // won't need to read the dst at all, it gets replaced by src
egdaniel0f1a7c42014-07-30 13:18:32 -0700376 *dstCoeff = kZero_GrBlendCoeff;
377 return kNone_BlendOpt;
bsalomon@google.com2b446732013-02-12 16:47:41 +0000378 } else if (kZero_GrBlendCoeff == *srcCoeff) {
379 // if the op is "clear" then we don't need to emit a color
380 // or blend, just write transparent black into the dst.
381 *srcCoeff = kOne_GrBlendCoeff;
382 *dstCoeff = kZero_GrBlendCoeff;
egdaniel0f1a7c42014-07-30 13:18:32 -0700383 return kEmitTransBlack_BlendOptFlag;
bsalomon@google.com2b446732013-02-12 16:47:41 +0000384 }
385 }
386 } else if (this->isCoverageDrawing()) {
387 // we have coverage but we aren't distinguishing it from alpha by request.
388 return kCoverageAsAlpha_BlendOptFlag;
389 } else {
390 // check whether coverage can be safely rolled into alpha
391 // of if we can skip color computation and just emit coverage
392 if (this->canTweakAlphaForCoverage()) {
393 return kCoverageAsAlpha_BlendOptFlag;
394 }
395 if (dstCoeffIsZero) {
396 if (kZero_GrBlendCoeff == *srcCoeff) {
397 // the source color is not included in the blend
398 // the dst coeff is effectively zero so blend works out to:
399 // (c)(0)D + (1-c)D = (1-c)D.
400 *dstCoeff = kISA_GrBlendCoeff;
401 return kEmitCoverage_BlendOptFlag;
402 } else if (srcAIsOne) {
403 // the dst coeff is effectively zero so blend works out to:
404 // cS + (c)(0)D + (1-c)D = cS + (1-c)D.
405 // If Sa is 1 then we can replace Sa with c
406 // and set dst coeff to 1-Sa.
407 *dstCoeff = kISA_GrBlendCoeff;
408 return kCoverageAsAlpha_BlendOptFlag;
409 }
410 } else if (dstCoeffIsOne) {
411 // the dst coeff is effectively one so blend works out to:
412 // cS + (c)(1)D + (1-c)D = cS + D.
413 *dstCoeff = kOne_GrBlendCoeff;
414 return kCoverageAsAlpha_BlendOptFlag;
415 }
416 }
egdaniel0f1a7c42014-07-30 13:18:32 -0700417
bsalomon@google.com2b446732013-02-12 16:47:41 +0000418 return kNone_BlendOpt;
419}
420
421////////////////////////////////////////////////////////////////////////////////
422
bsalomon@google.com2fdcdeb2012-10-08 17:15:55 +0000423void GrDrawState::AutoViewMatrixRestore::restore() {
424 if (NULL != fDrawState) {
commit-bot@chromium.org1acc3d72013-09-06 23:13:05 +0000425 SkDEBUGCODE(--fDrawState->fBlockEffectRemovalCnt;)
bsalomon2ed5ef82014-07-07 08:44:05 -0700426 fDrawState->fViewMatrix = fViewMatrix;
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000427 SkASSERT(fDrawState->numColorStages() >= fNumColorStages);
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000428 int numCoverageStages = fSavedCoordChanges.count() - fNumColorStages;
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000429 SkASSERT(fDrawState->numCoverageStages() >= numCoverageStages);
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000430
431 int i = 0;
432 for (int s = 0; s < fNumColorStages; ++s, ++i) {
egdaniel8cbf3d52014-08-21 06:27:22 -0700433 fDrawState->fColorStages[s].restoreCoordChange(fSavedCoordChanges[i]);
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000434 }
435 for (int s = 0; s < numCoverageStages; ++s, ++i) {
egdaniel8cbf3d52014-08-21 06:27:22 -0700436 fDrawState->fCoverageStages[s].restoreCoordChange(fSavedCoordChanges[i]);
bsalomon@google.com2fdcdeb2012-10-08 17:15:55 +0000437 }
bsalomon@google.com137f1342013-05-29 21:27:53 +0000438 fDrawState = NULL;
bsalomon@google.com2fdcdeb2012-10-08 17:15:55 +0000439 }
bsalomon@google.com2fdcdeb2012-10-08 17:15:55 +0000440}
441
442void GrDrawState::AutoViewMatrixRestore::set(GrDrawState* drawState,
bsalomon@google.comc7818882013-03-20 19:19:53 +0000443 const SkMatrix& preconcatMatrix) {
bsalomon@google.com2fdcdeb2012-10-08 17:15:55 +0000444 this->restore();
bsalomon@google.com5b3e8902012-10-05 20:13:28 +0000445
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000446 SkASSERT(NULL == fDrawState);
bsalomon@google.com137f1342013-05-29 21:27:53 +0000447 if (NULL == drawState || preconcatMatrix.isIdentity()) {
bsalomon@google.com2fdcdeb2012-10-08 17:15:55 +0000448 return;
449 }
bsalomon@google.com137f1342013-05-29 21:27:53 +0000450 fDrawState = drawState;
bsalomon@google.com2fdcdeb2012-10-08 17:15:55 +0000451
bsalomon@google.com2fdcdeb2012-10-08 17:15:55 +0000452 fViewMatrix = drawState->getViewMatrix();
bsalomon2ed5ef82014-07-07 08:44:05 -0700453 drawState->fViewMatrix.preConcat(preconcatMatrix);
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000454
455 this->doEffectCoordChanges(preconcatMatrix);
commit-bot@chromium.org1acc3d72013-09-06 23:13:05 +0000456 SkDEBUGCODE(++fDrawState->fBlockEffectRemovalCnt;)
bsalomon@google.com2fdcdeb2012-10-08 17:15:55 +0000457}
458
bsalomon@google.com137f1342013-05-29 21:27:53 +0000459bool GrDrawState::AutoViewMatrixRestore::setIdentity(GrDrawState* drawState) {
bsalomon@google.com2fdcdeb2012-10-08 17:15:55 +0000460 this->restore();
461
bsalomon@google.com137f1342013-05-29 21:27:53 +0000462 if (NULL == drawState) {
bsalomon@google.com2fdcdeb2012-10-08 17:15:55 +0000463 return false;
skia.committer@gmail.comf467ce72012-10-09 02:01:37 +0000464 }
bsalomon@google.com2fdcdeb2012-10-08 17:15:55 +0000465
bsalomon@google.com137f1342013-05-29 21:27:53 +0000466 if (drawState->getViewMatrix().isIdentity()) {
467 return true;
468 }
469
bsalomon@google.com5b3e8902012-10-05 20:13:28 +0000470 fViewMatrix = drawState->getViewMatrix();
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000471 if (0 == drawState->numTotalStages()) {
bsalomon2ed5ef82014-07-07 08:44:05 -0700472 drawState->fViewMatrix.reset();
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000473 fDrawState = drawState;
474 fNumColorStages = 0;
475 fSavedCoordChanges.reset(0);
commit-bot@chromium.org1acc3d72013-09-06 23:13:05 +0000476 SkDEBUGCODE(++fDrawState->fBlockEffectRemovalCnt;)
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000477 return true;
478 } else {
479 SkMatrix inv;
480 if (!fViewMatrix.invert(&inv)) {
481 return false;
bsalomon@google.com5b3e8902012-10-05 20:13:28 +0000482 }
bsalomon2ed5ef82014-07-07 08:44:05 -0700483 drawState->fViewMatrix.reset();
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000484 fDrawState = drawState;
485 this->doEffectCoordChanges(inv);
commit-bot@chromium.org1acc3d72013-09-06 23:13:05 +0000486 SkDEBUGCODE(++fDrawState->fBlockEffectRemovalCnt;)
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000487 return true;
bsalomon@google.com5b3e8902012-10-05 20:13:28 +0000488 }
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000489}
490
491void GrDrawState::AutoViewMatrixRestore::doEffectCoordChanges(const SkMatrix& coordChangeMatrix) {
492 fSavedCoordChanges.reset(fDrawState->numTotalStages());
493 int i = 0;
494
495 fNumColorStages = fDrawState->numColorStages();
496 for (int s = 0; s < fNumColorStages; ++s, ++i) {
egdaniel776bdbd2014-08-06 11:07:02 -0700497 fDrawState->getColorStage(s).saveCoordChange(&fSavedCoordChanges[i]);
egdaniel8cbf3d52014-08-21 06:27:22 -0700498 fDrawState->fColorStages[s].localCoordChange(coordChangeMatrix);
bsalomon@google.com137f1342013-05-29 21:27:53 +0000499 }
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000500
501 int numCoverageStages = fDrawState->numCoverageStages();
502 for (int s = 0; s < numCoverageStages; ++s, ++i) {
egdaniel776bdbd2014-08-06 11:07:02 -0700503 fDrawState->getCoverageStage(s).saveCoordChange(&fSavedCoordChanges[i]);
egdaniel8cbf3d52014-08-21 06:27:22 -0700504 fDrawState->fCoverageStages[s].localCoordChange(coordChangeMatrix);
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000505 }
bsalomon@google.com5b3e8902012-10-05 20:13:28 +0000506}
egdaniel21aed572014-08-26 12:24:06 -0700507
508bool GrDrawState::srcAlphaWillBeOne() const {
509 uint32_t validComponentFlags;
510 GrColor color;
511 // Check if per-vertex or constant color may have partial alpha
512 if (this->hasColorVertexAttribute()) {
513 if (fHints & kVertexColorsAreOpaque_Hint) {
514 validComponentFlags = kA_GrColorComponentFlag;
515 color = 0xFF << GrColor_SHIFT_A;
516 } else {
517 validComponentFlags = 0;
518 color = 0; // not strictly necessary but we get false alarms from tools about uninit.
519 }
520 } else {
521 validComponentFlags = kRGBA_GrColorComponentFlags;
522 color = this->getColor();
523 }
524
525 // Run through the color stages
526 for (int s = 0; s < this->numColorStages(); ++s) {
527 const GrEffect* effect = this->getColorStage(s).getEffect();
528 effect->getConstantColorComponents(&color, &validComponentFlags);
529 }
530
531 // Check whether coverage is treated as color. If so we run through the coverage computation.
532 if (this->isCoverageDrawing()) {
533 // The shader generated for coverage drawing runs the full coverage computation and then
534 // makes the shader output be the multiplication of color and coverage. We mirror that here.
535 GrColor coverage;
536 uint32_t coverageComponentFlags;
537 if (this->hasCoverageVertexAttribute()) {
538 coverageComponentFlags = 0;
539 coverage = 0; // suppresses any warnings.
540 } else {
541 coverageComponentFlags = kRGBA_GrColorComponentFlags;
542 coverage = this->getCoverageColor();
543 }
544
545 // Run through the coverage stages
546 for (int s = 0; s < this->numCoverageStages(); ++s) {
547 const GrEffect* effect = this->getCoverageStage(s).getEffect();
548 effect->getConstantColorComponents(&coverage, &coverageComponentFlags);
549 }
550
551 // Since the shader will multiply coverage and color, the only way the final A==1 is if
552 // coverage and color both have A==1.
553 return (kA_GrColorComponentFlag & validComponentFlags & coverageComponentFlags) &&
554 0xFF == GrColorUnpackA(color) && 0xFF == GrColorUnpackA(coverage);
555
556 }
557
558 return (kA_GrColorComponentFlag & validComponentFlags) && 0xFF == GrColorUnpackA(color);
559}
560
561////////////////////////////////////////////////////////////////////////////////
562
563bool GrDrawState::canIgnoreColorAttribute() const {
564 if (fBlendOptFlags & kInvalid_BlendOptFlag) {
565 this->getBlendOpts();
566 }
567 return SkToBool(fBlendOptFlags & (GrRODrawState::kEmitTransBlack_BlendOptFlag |
568 GrRODrawState::kEmitCoverage_BlendOptFlag));
569}
570