blob: 3189a0a079353a7be315dde3994394c166247db2 [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"
10
bsalomon8f727332014-08-05 07:50:06 -070011//////////////////////////////////////////////////////////////////////////////s
12
13GrDrawState::CombinedState GrDrawState::CombineIfPossible(
14 const GrDrawState& a, const GrDrawState& b) {
15
16 bool usingVertexColors = a.hasColorVertexAttribute();
17 if (!usingVertexColors && a.fColor != b.fColor) {
18 return kIncompatible_CombinedState;
19 }
20
21 if (a.fRenderTarget.get() != b.fRenderTarget.get() ||
22 a.fColorStages.count() != b.fColorStages.count() ||
23 a.fCoverageStages.count() != b.fCoverageStages.count() ||
24 !a.fViewMatrix.cheapEqualTo(b.fViewMatrix) ||
25 a.fSrcBlend != b.fSrcBlend ||
26 a.fDstBlend != b.fDstBlend ||
27 a.fBlendConstant != b.fBlendConstant ||
28 a.fFlagBits != b.fFlagBits ||
29 a.fVACount != b.fVACount ||
30 memcmp(a.fVAPtr, b.fVAPtr, a.fVACount * sizeof(GrVertexAttrib)) ||
31 a.fStencilSettings != b.fStencilSettings ||
32 a.fDrawFace != b.fDrawFace) {
33 return kIncompatible_CombinedState;
34 }
35
36 bool usingVertexCoverage = a.hasCoverageVertexAttribute();
37 if (!usingVertexCoverage && a.fCoverage != b.fCoverage) {
38 return kIncompatible_CombinedState;
39 }
40
41 bool explicitLocalCoords = a.hasLocalCoordAttribute();
42 for (int i = 0; i < a.fColorStages.count(); i++) {
43 if (!GrEffectStage::AreCompatible(a.fColorStages[i], b.fColorStages[i],
44 explicitLocalCoords)) {
45 return kIncompatible_CombinedState;
46 }
47 }
48 for (int i = 0; i < a.fCoverageStages.count(); i++) {
49 if (!GrEffectStage::AreCompatible(a.fCoverageStages[i], b.fCoverageStages[i],
50 explicitLocalCoords)) {
51 return kIncompatible_CombinedState;
52 }
53 }
54 SkASSERT(0 == memcmp(a.fFixedFunctionVertexAttribIndices,
55 b.fFixedFunctionVertexAttribIndices,
56 sizeof(a.fFixedFunctionVertexAttribIndices)));
57 return kAOrB_CombinedState;
58}
59
60
61//////////////////////////////////////////////////////////////////////////////s
62
63GrDrawState::GrDrawState(const GrDrawState& state, const SkMatrix& preConcatMatrix) {
64 SkDEBUGCODE(fBlockEffectRemovalCnt = 0;)
65 *this = state;
66 if (!preConcatMatrix.isIdentity()) {
67 for (int i = 0; i < fColorStages.count(); ++i) {
68 fColorStages[i].localCoordChange(preConcatMatrix);
69 }
70 for (int i = 0; i < fCoverageStages.count(); ++i) {
71 fCoverageStages[i].localCoordChange(preConcatMatrix);
72 }
73 this->invalidateBlendOptFlags();
74 }
75}
76
77GrDrawState& GrDrawState::operator=(const GrDrawState& that) {
78 SkASSERT(0 == fBlockEffectRemovalCnt || 0 == this->numTotalStages());
79 this->setRenderTarget(that.fRenderTarget.get());
80 fColor = that.fColor;
81 fViewMatrix = that.fViewMatrix;
82 fSrcBlend = that.fSrcBlend;
83 fDstBlend = that.fDstBlend;
84 fBlendConstant = that.fBlendConstant;
85 fFlagBits = that.fFlagBits;
86 fVACount = that.fVACount;
87 fVAPtr = that.fVAPtr;
88 fStencilSettings = that.fStencilSettings;
89 fCoverage = that.fCoverage;
90 fDrawFace = that.fDrawFace;
91 fColorStages = that.fColorStages;
92 fCoverageStages = that.fCoverageStages;
93 fOptSrcBlend = that.fOptSrcBlend;
94 fOptDstBlend = that.fOptDstBlend;
95 fBlendOptFlags = that.fBlendOptFlags;
96
97 memcpy(fFixedFunctionVertexAttribIndices,
98 that.fFixedFunctionVertexAttribIndices,
99 sizeof(fFixedFunctionVertexAttribIndices));
100 return *this;
101}
102
103void GrDrawState::onReset(const SkMatrix* initialViewMatrix) {
104 SkASSERT(0 == fBlockEffectRemovalCnt || 0 == this->numTotalStages());
105 fColorStages.reset();
106 fCoverageStages.reset();
107
108 fRenderTarget.reset(NULL);
109
110 this->setDefaultVertexAttribs();
111
112 fColor = 0xffffffff;
113 if (NULL == initialViewMatrix) {
114 fViewMatrix.reset();
115 } else {
116 fViewMatrix = *initialViewMatrix;
117 }
118 fSrcBlend = kOne_GrBlendCoeff;
119 fDstBlend = kZero_GrBlendCoeff;
120 fBlendConstant = 0x0;
121 fFlagBits = 0x0;
122 fStencilSettings.setDisabled();
123 fCoverage = 0xffffffff;
124 fDrawFace = kBoth_DrawFace;
125
126 this->invalidateBlendOptFlags();
127}
128
bsalomon@google.com137f1342013-05-29 21:27:53 +0000129bool GrDrawState::setIdentityViewMatrix() {
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000130 if (fColorStages.count() || fCoverageStages.count()) {
131 SkMatrix invVM;
bsalomon2ed5ef82014-07-07 08:44:05 -0700132 if (!fViewMatrix.invert(&invVM)) {
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000133 // sad trombone sound
134 return false;
135 }
136 for (int s = 0; s < fColorStages.count(); ++s) {
137 fColorStages[s].localCoordChange(invVM);
138 }
139 for (int s = 0; s < fCoverageStages.count(); ++s) {
140 fCoverageStages[s].localCoordChange(invVM);
bsalomon@google.com137f1342013-05-29 21:27:53 +0000141 }
142 }
bsalomon2ed5ef82014-07-07 08:44:05 -0700143 fViewMatrix.reset();
bsalomon@google.com137f1342013-05-29 21:27:53 +0000144 return true;
145}
146
commit-bot@chromium.orgbb6a3172013-05-28 17:25:49 +0000147void GrDrawState::setFromPaint(const GrPaint& paint, const SkMatrix& vm, GrRenderTarget* rt) {
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000148 SkASSERT(0 == fBlockEffectRemovalCnt || 0 == this->numTotalStages());
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000149
150 fColorStages.reset();
151 fCoverageStages.reset();
152
commit-bot@chromium.org42dacab2013-07-13 17:24:24 +0000153 for (int i = 0; i < paint.numColorStages(); ++i) {
154 fColorStages.push_back(paint.getColorStage(i));
bsalomon@google.comaf84e742012-10-05 13:23:24 +0000155 }
156
commit-bot@chromium.org42dacab2013-07-13 17:24:24 +0000157 for (int i = 0; i < paint.numCoverageStages(); ++i) {
158 fCoverageStages.push_back(paint.getCoverageStage(i));
bsalomon@google.comaf84e742012-10-05 13:23:24 +0000159 }
160
commit-bot@chromium.orgbb6a3172013-05-28 17:25:49 +0000161 this->setRenderTarget(rt);
bsalomon@google.comaf84e742012-10-05 13:23:24 +0000162
bsalomon2ed5ef82014-07-07 08:44:05 -0700163 fViewMatrix = vm;
commit-bot@chromium.orgbb6a3172013-05-28 17:25:49 +0000164
165 // These have no equivalent in GrPaint, set them to defaults
bsalomon2ed5ef82014-07-07 08:44:05 -0700166 fBlendConstant = 0x0;
167 fDrawFace = kBoth_DrawFace;
168 fStencilSettings.setDisabled();
commit-bot@chromium.orgbb6a3172013-05-28 17:25:49 +0000169 this->resetStateFlags();
170
bsalomon@google.com21c10c52013-06-13 17:44:07 +0000171 // Enable the clip bit
172 this->enableState(GrDrawState::kClip_StateBit);
173
commit-bot@chromium.orgbb6a3172013-05-28 17:25:49 +0000174 this->setColor(paint.getColor());
bsalomon@google.comc7448ce2012-10-05 19:04:13 +0000175 this->setState(GrDrawState::kDither_StateBit, paint.isDither());
176 this->setState(GrDrawState::kHWAntialias_StateBit, paint.isAntiAlias());
bsalomon@google.comaf84e742012-10-05 13:23:24 +0000177
bsalomon@google.comc7448ce2012-10-05 19:04:13 +0000178 this->setBlendFunc(paint.getSrcBlendCoeff(), paint.getDstBlendCoeff());
bsalomon@google.comc7448ce2012-10-05 19:04:13 +0000179 this->setCoverage(paint.getCoverage());
egdaniel9514d242014-07-18 06:15:43 -0700180 this->invalidateBlendOptFlags();
bsalomon@google.comaf84e742012-10-05 13:23:24 +0000181}
bsalomon@google.com5b3e8902012-10-05 20:13:28 +0000182
183////////////////////////////////////////////////////////////////////////////////
184
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000185static size_t vertex_size(const GrVertexAttrib* attribs, int count) {
186 // this works as long as we're 4 byte-aligned
commit-bot@chromium.org515dcd32013-08-28 14:17:03 +0000187#ifdef SK_DEBUG
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000188 uint32_t overlapCheck = 0;
189#endif
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000190 SkASSERT(count <= GrDrawState::kMaxVertexAttribCnt);
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000191 size_t size = 0;
192 for (int index = 0; index < count; ++index) {
jvanverth@google.com054ae992013-04-01 20:06:51 +0000193 size_t attribSize = GrVertexAttribTypeSize(attribs[index].fType);
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000194 size += attribSize;
commit-bot@chromium.org515dcd32013-08-28 14:17:03 +0000195#ifdef SK_DEBUG
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000196 size_t dwordCount = attribSize >> 2;
197 uint32_t mask = (1 << dwordCount)-1;
198 size_t offsetShift = attribs[index].fOffset >> 2;
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000199 SkASSERT(!(overlapCheck & (mask << offsetShift)));
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000200 overlapCheck |= (mask << offsetShift);
201#endif
jvanverth@google.comcc782382013-01-28 20:39:48 +0000202 }
203 return size;
204}
205
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000206size_t GrDrawState::getVertexSize() const {
bsalomon2ed5ef82014-07-07 08:44:05 -0700207 return vertex_size(fVAPtr, fVACount);
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000208}
209
jvanverth@google.comcc782382013-01-28 20:39:48 +0000210////////////////////////////////////////////////////////////////////////////////
211
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000212void GrDrawState::setVertexAttribs(const GrVertexAttrib* attribs, int count) {
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000213 SkASSERT(count <= kMaxVertexAttribCnt);
robertphillips@google.com42903302013-04-20 12:26:07 +0000214
bsalomon2ed5ef82014-07-07 08:44:05 -0700215 fVAPtr = attribs;
216 fVACount = count;
jvanverth@google.com054ae992013-04-01 20:06:51 +0000217
218 // Set all the indices to -1
bsalomon2ed5ef82014-07-07 08:44:05 -0700219 memset(fFixedFunctionVertexAttribIndices,
jvanverth@google.com054ae992013-04-01 20:06:51 +0000220 0xff,
bsalomon2ed5ef82014-07-07 08:44:05 -0700221 sizeof(fFixedFunctionVertexAttribIndices));
commit-bot@chromium.org515dcd32013-08-28 14:17:03 +0000222#ifdef SK_DEBUG
jvanverth@google.com054ae992013-04-01 20:06:51 +0000223 uint32_t overlapCheck = 0;
224#endif
225 for (int i = 0; i < count; ++i) {
226 if (attribs[i].fBinding < kGrFixedFunctionVertexAttribBindingCnt) {
227 // The fixed function attribs can only be specified once
bsalomon2ed5ef82014-07-07 08:44:05 -0700228 SkASSERT(-1 == fFixedFunctionVertexAttribIndices[attribs[i].fBinding]);
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000229 SkASSERT(GrFixedFunctionVertexAttribVectorCount(attribs[i].fBinding) ==
jvanverth@google.com054ae992013-04-01 20:06:51 +0000230 GrVertexAttribTypeVectorCount(attribs[i].fType));
bsalomon2ed5ef82014-07-07 08:44:05 -0700231 fFixedFunctionVertexAttribIndices[attribs[i].fBinding] = i;
jvanverth@google.com054ae992013-04-01 20:06:51 +0000232 }
commit-bot@chromium.org515dcd32013-08-28 14:17:03 +0000233#ifdef SK_DEBUG
jvanverth@google.com054ae992013-04-01 20:06:51 +0000234 size_t dwordCount = GrVertexAttribTypeSize(attribs[i].fType) >> 2;
235 uint32_t mask = (1 << dwordCount)-1;
236 size_t offsetShift = attribs[i].fOffset >> 2;
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000237 SkASSERT(!(overlapCheck & (mask << offsetShift)));
jvanverth@google.com054ae992013-04-01 20:06:51 +0000238 overlapCheck |= (mask << offsetShift);
239#endif
jvanverth@google.comcc782382013-01-28 20:39:48 +0000240 }
egdaniel9514d242014-07-18 06:15:43 -0700241 this->invalidateBlendOptFlags();
jvanverth@google.com054ae992013-04-01 20:06:51 +0000242 // Positions must be specified.
bsalomon2ed5ef82014-07-07 08:44:05 -0700243 SkASSERT(-1 != fFixedFunctionVertexAttribIndices[kPosition_GrVertexAttribBinding]);
jvanverth@google.comcc782382013-01-28 20:39:48 +0000244}
245
246////////////////////////////////////////////////////////////////////////////////
247
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000248void GrDrawState::setDefaultVertexAttribs() {
jvanverth@google.com054ae992013-04-01 20:06:51 +0000249 static const GrVertexAttrib kPositionAttrib =
250 {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding};
robertphillips@google.com42903302013-04-20 12:26:07 +0000251
bsalomon2ed5ef82014-07-07 08:44:05 -0700252 fVAPtr = &kPositionAttrib;
253 fVACount = 1;
robertphillips@google.com42903302013-04-20 12:26:07 +0000254
jvanverth@google.com054ae992013-04-01 20:06:51 +0000255 // set all the fixed function indices to -1 except position.
bsalomon2ed5ef82014-07-07 08:44:05 -0700256 memset(fFixedFunctionVertexAttribIndices,
jvanverth@google.com054ae992013-04-01 20:06:51 +0000257 0xff,
bsalomon2ed5ef82014-07-07 08:44:05 -0700258 sizeof(fFixedFunctionVertexAttribIndices));
259 fFixedFunctionVertexAttribIndices[kPosition_GrVertexAttribBinding] = 0;
egdaniel9514d242014-07-18 06:15:43 -0700260 this->invalidateBlendOptFlags();
jvanverth@google.comcc782382013-01-28 20:39:48 +0000261}
262
263////////////////////////////////////////////////////////////////////////////////
264
commit-bot@chromium.orgff6ea262013-03-12 12:26:08 +0000265bool GrDrawState::validateVertexAttribs() const {
jvanverth@google.com054ae992013-04-01 20:06:51 +0000266 // check consistency of effects and attributes
267 GrSLType slTypes[kMaxVertexAttribCnt];
268 for (int i = 0; i < kMaxVertexAttribCnt; ++i) {
269 slTypes[i] = static_cast<GrSLType>(-1);
commit-bot@chromium.orgff6ea262013-03-12 12:26:08 +0000270 }
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000271 int totalStages = fColorStages.count() + fCoverageStages.count();
272 for (int s = 0; s < totalStages; ++s) {
273 int covIdx = s - fColorStages.count();
274 const GrEffectStage& stage = covIdx < 0 ? fColorStages[s] : fCoverageStages[covIdx];
bsalomonf99f8842014-07-07 11:54:23 -0700275 const GrEffect* effect = stage.getEffect();
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000276 SkASSERT(NULL != effect);
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000277 // make sure that any attribute indices have the correct binding type, that the attrib
278 // type and effect's shader lang type are compatible, and that attributes shared by
279 // multiple effects use the same shader lang type.
280 const int* attributeIndices = stage.getVertexAttribIndices();
281 int numAttributes = stage.getVertexAttribIndexCount();
282 for (int i = 0; i < numAttributes; ++i) {
283 int attribIndex = attributeIndices[i];
bsalomon2ed5ef82014-07-07 08:44:05 -0700284 if (attribIndex >= fVACount ||
285 kEffect_GrVertexAttribBinding != fVAPtr[attribIndex].fBinding) {
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000286 return false;
jvanverth@google.comc7bf2962013-04-01 19:29:32 +0000287 }
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000288
bsalomonf99f8842014-07-07 11:54:23 -0700289 GrSLType effectSLType = effect->vertexAttribType(i);
bsalomon2ed5ef82014-07-07 08:44:05 -0700290 GrVertexAttribType attribType = fVAPtr[attribIndex].fType;
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000291 int slVecCount = GrSLTypeVectorCount(effectSLType);
292 int attribVecCount = GrVertexAttribTypeVectorCount(attribType);
293 if (slVecCount != attribVecCount ||
294 (static_cast<GrSLType>(-1) != slTypes[attribIndex] &&
295 slTypes[attribIndex] != effectSLType)) {
296 return false;
297 }
298 slTypes[attribIndex] = effectSLType;
commit-bot@chromium.orgff6ea262013-03-12 12:26:08 +0000299 }
300 }
301
302 return true;
303}
304
bsalomon@google.comd09ab842013-05-15 17:30:26 +0000305bool GrDrawState::willEffectReadDstColor() const {
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000306 if (!this->isColorWriteDisabled()) {
307 for (int s = 0; s < fColorStages.count(); ++s) {
bsalomonf99f8842014-07-07 11:54:23 -0700308 if (fColorStages[s].getEffect()->willReadDstColor()) {
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000309 return true;
310 }
311 }
312 }
313 for (int s = 0; s < fCoverageStages.count(); ++s) {
bsalomonf99f8842014-07-07 11:54:23 -0700314 if (fCoverageStages[s].getEffect()->willReadDstColor()) {
bsalomon@google.comd09ab842013-05-15 17:30:26 +0000315 return true;
316 }
317 }
318 return false;
319}
320
jvanverth@google.comcc782382013-01-28 20:39:48 +0000321////////////////////////////////////////////////////////////////////////////////
322
jvanverth@google.com054ae992013-04-01 20:06:51 +0000323bool GrDrawState::srcAlphaWillBeOne() const {
jvanverth@google.comcc782382013-01-28 20:39:48 +0000324 uint32_t validComponentFlags;
bsalomon@google.com89e6f5b2013-02-27 18:43:47 +0000325 GrColor color;
jvanverth@google.comcc782382013-01-28 20:39:48 +0000326 // Check if per-vertex or constant color may have partial alpha
jvanverth@google.com054ae992013-04-01 20:06:51 +0000327 if (this->hasColorVertexAttribute()) {
jvanverth@google.comcc782382013-01-28 20:39:48 +0000328 validComponentFlags = 0;
bsalomon@google.com89e6f5b2013-02-27 18:43:47 +0000329 color = 0; // not strictly necessary but we get false alarms from tools about uninit.
jvanverth@google.comcc782382013-01-28 20:39:48 +0000330 } else {
bsalomon@google.comb8eb2e82013-03-28 13:46:42 +0000331 validComponentFlags = kRGBA_GrColorComponentFlags;
jvanverth@google.comcc782382013-01-28 20:39:48 +0000332 color = this->getColor();
333 }
334
335 // Run through the color stages
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000336 for (int s = 0; s < fColorStages.count(); ++s) {
bsalomonf99f8842014-07-07 11:54:23 -0700337 const GrEffect* effect = fColorStages[s].getEffect();
338 effect->getConstantColorComponents(&color, &validComponentFlags);
jvanverth@google.comcc782382013-01-28 20:39:48 +0000339 }
340
jvanverth@google.comcc782382013-01-28 20:39:48 +0000341 // Check whether coverage is treated as color. If so we run through the coverage computation.
342 if (this->isCoverageDrawing()) {
commit-bot@chromium.orge0a868c2013-11-22 07:02:11 +0000343 GrColor coverageColor = this->getCoverageColor();
jvanverth@google.comcc782382013-01-28 20:39:48 +0000344 GrColor oldColor = color;
345 color = 0;
346 for (int c = 0; c < 4; ++c) {
347 if (validComponentFlags & (1 << c)) {
348 U8CPU a = (oldColor >> (c * 8)) & 0xff;
349 U8CPU b = (coverageColor >> (c * 8)) & 0xff;
350 color |= (SkMulDiv255Round(a, b) << (c * 8));
351 }
352 }
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000353 for (int s = 0; s < fCoverageStages.count(); ++s) {
bsalomonf99f8842014-07-07 11:54:23 -0700354 const GrEffect* effect = fCoverageStages[s].getEffect();
355 effect->getConstantColorComponents(&color, &validComponentFlags);
jvanverth@google.comcc782382013-01-28 20:39:48 +0000356 }
357 }
bsalomon@google.comb8eb2e82013-03-28 13:46:42 +0000358 return (kA_GrColorComponentFlag & validComponentFlags) && 0xff == GrColorUnpackA(color);
jvanverth@google.comcc782382013-01-28 20:39:48 +0000359}
360
jvanverth@google.com054ae992013-04-01 20:06:51 +0000361bool GrDrawState::hasSolidCoverage() const {
bsalomon@google.comd62e88e2013-02-01 14:19:27 +0000362 // If we're drawing coverage directly then coverage is effectively treated as color.
363 if (this->isCoverageDrawing()) {
364 return true;
365 }
366
367 GrColor coverage;
368 uint32_t validComponentFlags;
369 // Initialize to an unknown starting coverage if per-vertex coverage is specified.
jvanverth@google.com054ae992013-04-01 20:06:51 +0000370 if (this->hasCoverageVertexAttribute()) {
bsalomon@google.comd62e88e2013-02-01 14:19:27 +0000371 validComponentFlags = 0;
372 } else {
bsalomon2ed5ef82014-07-07 08:44:05 -0700373 coverage = fCoverage;
bsalomon@google.comb8eb2e82013-03-28 13:46:42 +0000374 validComponentFlags = kRGBA_GrColorComponentFlags;
bsalomon@google.comd62e88e2013-02-01 14:19:27 +0000375 }
376
377 // Run through the coverage stages and see if the coverage will be all ones at the end.
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000378 for (int s = 0; s < fCoverageStages.count(); ++s) {
bsalomonf99f8842014-07-07 11:54:23 -0700379 const GrEffect* effect = fCoverageStages[s].getEffect();
380 effect->getConstantColorComponents(&coverage, &validComponentFlags);
bsalomon@google.comd62e88e2013-02-01 14:19:27 +0000381 }
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000382 return (kRGBA_GrColorComponentFlags == validComponentFlags) && (0xffffffff == coverage);
bsalomon@google.comd62e88e2013-02-01 14:19:27 +0000383}
384
jvanverth@google.comcc782382013-01-28 20:39:48 +0000385////////////////////////////////////////////////////////////////////////////////
386
bsalomon@google.com2b446732013-02-12 16:47:41 +0000387// Some blend modes allow folding a fractional coverage value into the color's alpha channel, while
388// others will blend incorrectly.
389bool GrDrawState::canTweakAlphaForCoverage() const {
390 /*
391 The fractional coverage is f.
392 The src and dst coeffs are Cs and Cd.
393 The dst and src colors are S and D.
394 We want the blend to compute: f*Cs*S + (f*Cd + (1-f))D. By tweaking the source color's alpha
395 we're replacing S with S'=fS. It's obvious that that first term will always be ok. The second
396 term can be rearranged as [1-(1-Cd)f]D. By substituting in the various possibilities for Cd we
397 find that only 1, ISA, and ISC produce the correct destination when applied to S' and D.
398 Also, if we're directly rendering coverage (isCoverageDrawing) then coverage is treated as
399 color by definition.
400 */
bsalomon2ed5ef82014-07-07 08:44:05 -0700401 return kOne_GrBlendCoeff == fDstBlend ||
402 kISA_GrBlendCoeff == fDstBlend ||
403 kISC_GrBlendCoeff == fDstBlend ||
bsalomon@google.com2b446732013-02-12 16:47:41 +0000404 this->isCoverageDrawing();
405}
406
407GrDrawState::BlendOptFlags GrDrawState::getBlendOpts(bool forceCoverage,
408 GrBlendCoeff* srcCoeff,
409 GrBlendCoeff* dstCoeff) const {
bsalomon@google.com2b446732013-02-12 16:47:41 +0000410 GrBlendCoeff bogusSrcCoeff, bogusDstCoeff;
411 if (NULL == srcCoeff) {
412 srcCoeff = &bogusSrcCoeff;
413 }
bsalomon@google.com2b446732013-02-12 16:47:41 +0000414 if (NULL == dstCoeff) {
415 dstCoeff = &bogusDstCoeff;
416 }
egdaniel9514d242014-07-18 06:15:43 -0700417
418 if (forceCoverage) {
419 return this->calcBlendOpts(true, srcCoeff, dstCoeff);
420 }
421
422 if (0 == (fBlendOptFlags & kInvalid_BlendOptFlag)) {
423 *srcCoeff = fOptSrcBlend;
424 *dstCoeff = fOptDstBlend;
425 return fBlendOptFlags;
426 }
427
428 fBlendOptFlags = this->calcBlendOpts(forceCoverage, srcCoeff, dstCoeff);
429 fOptSrcBlend = *srcCoeff;
430 fOptDstBlend = *dstCoeff;
431
432 return fBlendOptFlags;
433}
434
435GrDrawState::BlendOptFlags GrDrawState::calcBlendOpts(bool forceCoverage,
436 GrBlendCoeff* srcCoeff,
437 GrBlendCoeff* dstCoeff) const {
438 *srcCoeff = this->getSrcBlendCoeff();
bsalomon@google.com2b446732013-02-12 16:47:41 +0000439 *dstCoeff = this->getDstBlendCoeff();
440
441 if (this->isColorWriteDisabled()) {
442 *srcCoeff = kZero_GrBlendCoeff;
443 *dstCoeff = kOne_GrBlendCoeff;
444 }
445
jvanverth@google.com054ae992013-04-01 20:06:51 +0000446 bool srcAIsOne = this->srcAlphaWillBeOne();
bsalomon@google.com2b446732013-02-12 16:47:41 +0000447 bool dstCoeffIsOne = kOne_GrBlendCoeff == *dstCoeff ||
448 (kSA_GrBlendCoeff == *dstCoeff && srcAIsOne);
449 bool dstCoeffIsZero = kZero_GrBlendCoeff == *dstCoeff ||
450 (kISA_GrBlendCoeff == *dstCoeff && srcAIsOne);
451
452 bool covIsZero = !this->isCoverageDrawing() &&
jvanverth@google.com054ae992013-04-01 20:06:51 +0000453 !this->hasCoverageVertexAttribute() &&
commit-bot@chromium.orge0a868c2013-11-22 07:02:11 +0000454 0 == this->getCoverageColor();
bsalomon@google.com2b446732013-02-12 16:47:41 +0000455 // When coeffs are (0,1) there is no reason to draw at all, unless
456 // stenciling is enabled. Having color writes disabled is effectively
457 // (0,1). The same applies when coverage is known to be 0.
458 if ((kZero_GrBlendCoeff == *srcCoeff && dstCoeffIsOne) || covIsZero) {
459 if (this->getStencil().doesWrite()) {
egdaniel0f1a7c42014-07-30 13:18:32 -0700460 return kEmitCoverage_BlendOptFlag;
bsalomon@google.com2b446732013-02-12 16:47:41 +0000461 } else {
462 return kSkipDraw_BlendOptFlag;
463 }
464 }
465
bsalomon@google.com4647f902013-03-26 14:45:27 +0000466 // check for coverage due to constant coverage, per-vertex coverage, or coverage stage
bsalomon@google.com2b446732013-02-12 16:47:41 +0000467 bool hasCoverage = forceCoverage ||
commit-bot@chromium.orge0a868c2013-11-22 07:02:11 +0000468 0xffffffff != this->getCoverageColor() ||
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000469 this->hasCoverageVertexAttribute() ||
470 fCoverageStages.count() > 0;
bsalomon@google.com2b446732013-02-12 16:47:41 +0000471
472 // if we don't have coverage we can check whether the dst
473 // has to read at all. If not, we'll disable blending.
474 if (!hasCoverage) {
475 if (dstCoeffIsZero) {
476 if (kOne_GrBlendCoeff == *srcCoeff) {
477 // if there is no coverage and coeffs are (1,0) then we
478 // won't need to read the dst at all, it gets replaced by src
egdaniel0f1a7c42014-07-30 13:18:32 -0700479 *dstCoeff = kZero_GrBlendCoeff;
480 return kNone_BlendOpt;
bsalomon@google.com2b446732013-02-12 16:47:41 +0000481 } else if (kZero_GrBlendCoeff == *srcCoeff) {
482 // if the op is "clear" then we don't need to emit a color
483 // or blend, just write transparent black into the dst.
484 *srcCoeff = kOne_GrBlendCoeff;
485 *dstCoeff = kZero_GrBlendCoeff;
egdaniel0f1a7c42014-07-30 13:18:32 -0700486 return kEmitTransBlack_BlendOptFlag;
bsalomon@google.com2b446732013-02-12 16:47:41 +0000487 }
488 }
489 } else if (this->isCoverageDrawing()) {
490 // we have coverage but we aren't distinguishing it from alpha by request.
491 return kCoverageAsAlpha_BlendOptFlag;
492 } else {
493 // check whether coverage can be safely rolled into alpha
494 // of if we can skip color computation and just emit coverage
495 if (this->canTweakAlphaForCoverage()) {
496 return kCoverageAsAlpha_BlendOptFlag;
497 }
498 if (dstCoeffIsZero) {
499 if (kZero_GrBlendCoeff == *srcCoeff) {
500 // the source color is not included in the blend
501 // the dst coeff is effectively zero so blend works out to:
502 // (c)(0)D + (1-c)D = (1-c)D.
503 *dstCoeff = kISA_GrBlendCoeff;
504 return kEmitCoverage_BlendOptFlag;
505 } else if (srcAIsOne) {
506 // the dst coeff is effectively zero so blend works out to:
507 // cS + (c)(0)D + (1-c)D = cS + (1-c)D.
508 // If Sa is 1 then we can replace Sa with c
509 // and set dst coeff to 1-Sa.
510 *dstCoeff = kISA_GrBlendCoeff;
511 return kCoverageAsAlpha_BlendOptFlag;
512 }
513 } else if (dstCoeffIsOne) {
514 // the dst coeff is effectively one so blend works out to:
515 // cS + (c)(1)D + (1-c)D = cS + D.
516 *dstCoeff = kOne_GrBlendCoeff;
517 return kCoverageAsAlpha_BlendOptFlag;
518 }
519 }
egdaniel0f1a7c42014-07-30 13:18:32 -0700520
bsalomon@google.com2b446732013-02-12 16:47:41 +0000521 return kNone_BlendOpt;
522}
523
egdaniel02cafcc2014-07-21 11:37:28 -0700524bool GrDrawState::canIgnoreColorAttribute() const {
525 if (fBlendOptFlags & kInvalid_BlendOptFlag) {
526 this->getBlendOpts();
527 }
528 return SkToBool(fBlendOptFlags & (GrDrawState::kEmitTransBlack_BlendOptFlag |
529 GrDrawState::kEmitCoverage_BlendOptFlag));
530}
531
bsalomon8f727332014-08-05 07:50:06 -0700532//////////////////////////////////////////////////////////////////////////////
533
534GrDrawState::AutoVertexAttribRestore::AutoVertexAttribRestore(
535 GrDrawState* drawState) {
536 SkASSERT(NULL != drawState);
537 fDrawState = drawState;
538 fVAPtr = drawState->fVAPtr;
539 fVACount = drawState->fVACount;
540 fDrawState->setDefaultVertexAttribs();
541}
542
543//////////////////////////////////////////////////////////////////////////////s
544
545void GrDrawState::AutoRestoreEffects::set(GrDrawState* ds) {
546 if (NULL != fDrawState) {
547 int m = fDrawState->fColorStages.count() - fColorEffectCnt;
548 SkASSERT(m >= 0);
549 fDrawState->fColorStages.pop_back_n(m);
550
551 int n = fDrawState->fCoverageStages.count() - fCoverageEffectCnt;
552 SkASSERT(n >= 0);
553 fDrawState->fCoverageStages.pop_back_n(n);
554 if (m + n > 0) {
555 fDrawState->invalidateBlendOptFlags();
556 }
557 SkDEBUGCODE(--fDrawState->fBlockEffectRemovalCnt;)
558 }
559 fDrawState = ds;
560 if (NULL != ds) {
561 fColorEffectCnt = ds->fColorStages.count();
562 fCoverageEffectCnt = ds->fCoverageStages.count();
563 SkDEBUGCODE(++ds->fBlockEffectRemovalCnt;)
564 }
565}
egdaniel02cafcc2014-07-21 11:37:28 -0700566
bsalomon@google.com2b446732013-02-12 16:47:41 +0000567////////////////////////////////////////////////////////////////////////////////
568
bsalomon@google.com2fdcdeb2012-10-08 17:15:55 +0000569void GrDrawState::AutoViewMatrixRestore::restore() {
570 if (NULL != fDrawState) {
commit-bot@chromium.org1acc3d72013-09-06 23:13:05 +0000571 SkDEBUGCODE(--fDrawState->fBlockEffectRemovalCnt;)
bsalomon2ed5ef82014-07-07 08:44:05 -0700572 fDrawState->fViewMatrix = fViewMatrix;
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000573 SkASSERT(fDrawState->numColorStages() >= fNumColorStages);
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000574 int numCoverageStages = fSavedCoordChanges.count() - fNumColorStages;
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000575 SkASSERT(fDrawState->numCoverageStages() >= numCoverageStages);
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000576
577 int i = 0;
578 for (int s = 0; s < fNumColorStages; ++s, ++i) {
579 fDrawState->fColorStages[s].restoreCoordChange(fSavedCoordChanges[i]);
580 }
581 for (int s = 0; s < numCoverageStages; ++s, ++i) {
582 fDrawState->fCoverageStages[s].restoreCoordChange(fSavedCoordChanges[i]);
bsalomon@google.com2fdcdeb2012-10-08 17:15:55 +0000583 }
bsalomon@google.com137f1342013-05-29 21:27:53 +0000584 fDrawState = NULL;
bsalomon@google.com2fdcdeb2012-10-08 17:15:55 +0000585 }
bsalomon@google.com2fdcdeb2012-10-08 17:15:55 +0000586}
587
588void GrDrawState::AutoViewMatrixRestore::set(GrDrawState* drawState,
bsalomon@google.comc7818882013-03-20 19:19:53 +0000589 const SkMatrix& preconcatMatrix) {
bsalomon@google.com2fdcdeb2012-10-08 17:15:55 +0000590 this->restore();
bsalomon@google.com5b3e8902012-10-05 20:13:28 +0000591
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000592 SkASSERT(NULL == fDrawState);
bsalomon@google.com137f1342013-05-29 21:27:53 +0000593 if (NULL == drawState || preconcatMatrix.isIdentity()) {
bsalomon@google.com2fdcdeb2012-10-08 17:15:55 +0000594 return;
595 }
bsalomon@google.com137f1342013-05-29 21:27:53 +0000596 fDrawState = drawState;
bsalomon@google.com2fdcdeb2012-10-08 17:15:55 +0000597
bsalomon@google.com2fdcdeb2012-10-08 17:15:55 +0000598 fViewMatrix = drawState->getViewMatrix();
bsalomon2ed5ef82014-07-07 08:44:05 -0700599 drawState->fViewMatrix.preConcat(preconcatMatrix);
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000600
601 this->doEffectCoordChanges(preconcatMatrix);
commit-bot@chromium.org1acc3d72013-09-06 23:13:05 +0000602 SkDEBUGCODE(++fDrawState->fBlockEffectRemovalCnt;)
bsalomon@google.com2fdcdeb2012-10-08 17:15:55 +0000603}
604
bsalomon@google.com137f1342013-05-29 21:27:53 +0000605bool GrDrawState::AutoViewMatrixRestore::setIdentity(GrDrawState* drawState) {
bsalomon@google.com2fdcdeb2012-10-08 17:15:55 +0000606 this->restore();
607
bsalomon@google.com137f1342013-05-29 21:27:53 +0000608 if (NULL == drawState) {
bsalomon@google.com2fdcdeb2012-10-08 17:15:55 +0000609 return false;
skia.committer@gmail.comf467ce72012-10-09 02:01:37 +0000610 }
bsalomon@google.com2fdcdeb2012-10-08 17:15:55 +0000611
bsalomon@google.com137f1342013-05-29 21:27:53 +0000612 if (drawState->getViewMatrix().isIdentity()) {
613 return true;
614 }
615
bsalomon@google.com5b3e8902012-10-05 20:13:28 +0000616 fViewMatrix = drawState->getViewMatrix();
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000617 if (0 == drawState->numTotalStages()) {
bsalomon2ed5ef82014-07-07 08:44:05 -0700618 drawState->fViewMatrix.reset();
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000619 fDrawState = drawState;
620 fNumColorStages = 0;
621 fSavedCoordChanges.reset(0);
commit-bot@chromium.org1acc3d72013-09-06 23:13:05 +0000622 SkDEBUGCODE(++fDrawState->fBlockEffectRemovalCnt;)
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000623 return true;
624 } else {
625 SkMatrix inv;
626 if (!fViewMatrix.invert(&inv)) {
627 return false;
bsalomon@google.com5b3e8902012-10-05 20:13:28 +0000628 }
bsalomon2ed5ef82014-07-07 08:44:05 -0700629 drawState->fViewMatrix.reset();
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000630 fDrawState = drawState;
631 this->doEffectCoordChanges(inv);
commit-bot@chromium.org1acc3d72013-09-06 23:13:05 +0000632 SkDEBUGCODE(++fDrawState->fBlockEffectRemovalCnt;)
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000633 return true;
bsalomon@google.com5b3e8902012-10-05 20:13:28 +0000634 }
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000635}
636
637void GrDrawState::AutoViewMatrixRestore::doEffectCoordChanges(const SkMatrix& coordChangeMatrix) {
638 fSavedCoordChanges.reset(fDrawState->numTotalStages());
639 int i = 0;
640
641 fNumColorStages = fDrawState->numColorStages();
642 for (int s = 0; s < fNumColorStages; ++s, ++i) {
643 fDrawState->fColorStages[s].saveCoordChange(&fSavedCoordChanges[i]);
644 fDrawState->fColorStages[s].localCoordChange(coordChangeMatrix);
bsalomon@google.com137f1342013-05-29 21:27:53 +0000645 }
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000646
647 int numCoverageStages = fDrawState->numCoverageStages();
648 for (int s = 0; s < numCoverageStages; ++s, ++i) {
649 fDrawState->fCoverageStages[s].saveCoordChange(&fSavedCoordChanges[i]);
650 fDrawState->fCoverageStages[s].localCoordChange(coordChangeMatrix);
651 }
bsalomon@google.com5b3e8902012-10-05 20:13:28 +0000652}