blob: a0dc426d7056c4e41dfd2c85bb1e865e8c6c4333 [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
egdaniel776bdbd2014-08-06 11:07:02 -070013bool GrDrawState::State::HaveCompatibleState(const State& a, const State& b,
14 bool explicitLocalCoords) {
15 if (a.fColorStages.count() != b.fColorStages.count() ||
16 a.fCoverageStages.count() != b.fCoverageStages.count() ||
17 a.fSrcBlend != b.fSrcBlend ||
18 a.fDstBlend != b.fDstBlend) {
19 return false;
20 }
21 for (int i = 0; i < a.fColorStages.count(); i++) {
22 if (!GrEffectStage::AreCompatible(a.fColorStages[i], b.fColorStages[i],
23 explicitLocalCoords)) {
24 return false;
25 }
26 }
27 for (int i = 0; i < a.fCoverageStages.count(); i++) {
28 if (!GrEffectStage::AreCompatible(a.fCoverageStages[i], b.fCoverageStages[i],
29 explicitLocalCoords)) {
30 return false;
31 }
32 }
33 return true;
34}
35//////////////////////////////////////////////////////////////////////////////s
bsalomon8f727332014-08-05 07:50:06 -070036GrDrawState::CombinedState GrDrawState::CombineIfPossible(
37 const GrDrawState& a, const GrDrawState& b) {
38
39 bool usingVertexColors = a.hasColorVertexAttribute();
40 if (!usingVertexColors && a.fColor != b.fColor) {
41 return kIncompatible_CombinedState;
42 }
43
44 if (a.fRenderTarget.get() != b.fRenderTarget.get() ||
bsalomon8f727332014-08-05 07:50:06 -070045 !a.fViewMatrix.cheapEqualTo(b.fViewMatrix) ||
bsalomon8f727332014-08-05 07:50:06 -070046 a.fBlendConstant != b.fBlendConstant ||
47 a.fFlagBits != b.fFlagBits ||
48 a.fVACount != b.fVACount ||
49 memcmp(a.fVAPtr, b.fVAPtr, a.fVACount * sizeof(GrVertexAttrib)) ||
50 a.fStencilSettings != b.fStencilSettings ||
51 a.fDrawFace != b.fDrawFace) {
52 return kIncompatible_CombinedState;
53 }
54
55 bool usingVertexCoverage = a.hasCoverageVertexAttribute();
56 if (!usingVertexCoverage && a.fCoverage != b.fCoverage) {
57 return kIncompatible_CombinedState;
58 }
59
60 bool explicitLocalCoords = a.hasLocalCoordAttribute();
egdaniel776bdbd2014-08-06 11:07:02 -070061
bsalomon8f727332014-08-05 07:50:06 -070062 SkASSERT(0 == memcmp(a.fFixedFunctionVertexAttribIndices,
63 b.fFixedFunctionVertexAttribIndices,
64 sizeof(a.fFixedFunctionVertexAttribIndices)));
egdaniel776bdbd2014-08-06 11:07:02 -070065 if (!State::HaveCompatibleState(a.fState, b.fState, explicitLocalCoords)) {
66 return kIncompatible_CombinedState;
67 }
bsalomon8f727332014-08-05 07:50:06 -070068 return kAOrB_CombinedState;
69}
70
71
72//////////////////////////////////////////////////////////////////////////////s
73
74GrDrawState::GrDrawState(const GrDrawState& state, const SkMatrix& preConcatMatrix) {
75 SkDEBUGCODE(fBlockEffectRemovalCnt = 0;)
76 *this = state;
77 if (!preConcatMatrix.isIdentity()) {
egdaniel776bdbd2014-08-06 11:07:02 -070078 for (int i = 0; i < this->numColorStages(); ++i) {
79 fState.fColorStages[i].localCoordChange(preConcatMatrix);
bsalomon8f727332014-08-05 07:50:06 -070080 }
egdaniel776bdbd2014-08-06 11:07:02 -070081 for (int i = 0; i < this->numCoverageStages(); ++i) {
82 fState.fCoverageStages[i].localCoordChange(preConcatMatrix);
bsalomon8f727332014-08-05 07:50:06 -070083 }
84 this->invalidateBlendOptFlags();
85 }
86}
87
88GrDrawState& GrDrawState::operator=(const GrDrawState& that) {
89 SkASSERT(0 == fBlockEffectRemovalCnt || 0 == this->numTotalStages());
90 this->setRenderTarget(that.fRenderTarget.get());
91 fColor = that.fColor;
92 fViewMatrix = that.fViewMatrix;
bsalomon8f727332014-08-05 07:50:06 -070093 fBlendConstant = that.fBlendConstant;
94 fFlagBits = that.fFlagBits;
95 fVACount = that.fVACount;
96 fVAPtr = that.fVAPtr;
97 fStencilSettings = that.fStencilSettings;
98 fCoverage = that.fCoverage;
99 fDrawFace = that.fDrawFace;
bsalomon8f727332014-08-05 07:50:06 -0700100 fOptSrcBlend = that.fOptSrcBlend;
101 fOptDstBlend = that.fOptDstBlend;
102 fBlendOptFlags = that.fBlendOptFlags;
103
egdaniel776bdbd2014-08-06 11:07:02 -0700104 fState = that.fState;
105
bsalomon8f727332014-08-05 07:50:06 -0700106 memcpy(fFixedFunctionVertexAttribIndices,
107 that.fFixedFunctionVertexAttribIndices,
108 sizeof(fFixedFunctionVertexAttribIndices));
109 return *this;
110}
111
112void GrDrawState::onReset(const SkMatrix* initialViewMatrix) {
113 SkASSERT(0 == fBlockEffectRemovalCnt || 0 == this->numTotalStages());
egdaniel776bdbd2014-08-06 11:07:02 -0700114 fState.reset();
bsalomon8f727332014-08-05 07:50:06 -0700115
116 fRenderTarget.reset(NULL);
117
118 this->setDefaultVertexAttribs();
119
120 fColor = 0xffffffff;
121 if (NULL == initialViewMatrix) {
122 fViewMatrix.reset();
123 } else {
124 fViewMatrix = *initialViewMatrix;
125 }
bsalomon8f727332014-08-05 07:50:06 -0700126 fBlendConstant = 0x0;
127 fFlagBits = 0x0;
128 fStencilSettings.setDisabled();
129 fCoverage = 0xffffffff;
130 fDrawFace = kBoth_DrawFace;
131
132 this->invalidateBlendOptFlags();
133}
134
bsalomon@google.com137f1342013-05-29 21:27:53 +0000135bool GrDrawState::setIdentityViewMatrix() {
egdaniel776bdbd2014-08-06 11:07:02 -0700136 if (this->numTotalStages()) {
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000137 SkMatrix invVM;
bsalomon2ed5ef82014-07-07 08:44:05 -0700138 if (!fViewMatrix.invert(&invVM)) {
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000139 // sad trombone sound
140 return false;
141 }
egdaniel776bdbd2014-08-06 11:07:02 -0700142 for (int s = 0; s < this->numColorStages(); ++s) {
143 fState.fColorStages[s].localCoordChange(invVM);
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000144 }
egdaniel776bdbd2014-08-06 11:07:02 -0700145 for (int s = 0; s < this->numCoverageStages(); ++s) {
146 fState.fCoverageStages[s].localCoordChange(invVM);
bsalomon@google.com137f1342013-05-29 21:27:53 +0000147 }
148 }
bsalomon2ed5ef82014-07-07 08:44:05 -0700149 fViewMatrix.reset();
bsalomon@google.com137f1342013-05-29 21:27:53 +0000150 return true;
151}
152
commit-bot@chromium.orgbb6a3172013-05-28 17:25:49 +0000153void GrDrawState::setFromPaint(const GrPaint& paint, const SkMatrix& vm, GrRenderTarget* rt) {
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000154 SkASSERT(0 == fBlockEffectRemovalCnt || 0 == this->numTotalStages());
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000155
egdaniel776bdbd2014-08-06 11:07:02 -0700156 fState.reset();
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000157
commit-bot@chromium.org42dacab2013-07-13 17:24:24 +0000158 for (int i = 0; i < paint.numColorStages(); ++i) {
egdaniel776bdbd2014-08-06 11:07:02 -0700159 fState.fColorStages.push_back(paint.getColorStage(i));
bsalomon@google.comaf84e742012-10-05 13:23:24 +0000160 }
161
commit-bot@chromium.org42dacab2013-07-13 17:24:24 +0000162 for (int i = 0; i < paint.numCoverageStages(); ++i) {
egdaniel776bdbd2014-08-06 11:07:02 -0700163 fState.fCoverageStages.push_back(paint.getCoverageStage(i));
bsalomon@google.comaf84e742012-10-05 13:23:24 +0000164 }
165
commit-bot@chromium.orgbb6a3172013-05-28 17:25:49 +0000166 this->setRenderTarget(rt);
bsalomon@google.comaf84e742012-10-05 13:23:24 +0000167
bsalomon2ed5ef82014-07-07 08:44:05 -0700168 fViewMatrix = vm;
commit-bot@chromium.orgbb6a3172013-05-28 17:25:49 +0000169
170 // These have no equivalent in GrPaint, set them to defaults
bsalomon2ed5ef82014-07-07 08:44:05 -0700171 fBlendConstant = 0x0;
172 fDrawFace = kBoth_DrawFace;
173 fStencilSettings.setDisabled();
commit-bot@chromium.orgbb6a3172013-05-28 17:25:49 +0000174 this->resetStateFlags();
175
bsalomon@google.com21c10c52013-06-13 17:44:07 +0000176 // Enable the clip bit
177 this->enableState(GrDrawState::kClip_StateBit);
178
commit-bot@chromium.orgbb6a3172013-05-28 17:25:49 +0000179 this->setColor(paint.getColor());
bsalomon@google.comc7448ce2012-10-05 19:04:13 +0000180 this->setState(GrDrawState::kDither_StateBit, paint.isDither());
181 this->setState(GrDrawState::kHWAntialias_StateBit, paint.isAntiAlias());
bsalomon@google.comaf84e742012-10-05 13:23:24 +0000182
bsalomon@google.comc7448ce2012-10-05 19:04:13 +0000183 this->setBlendFunc(paint.getSrcBlendCoeff(), paint.getDstBlendCoeff());
bsalomon@google.comc7448ce2012-10-05 19:04:13 +0000184 this->setCoverage(paint.getCoverage());
egdaniel9514d242014-07-18 06:15:43 -0700185 this->invalidateBlendOptFlags();
bsalomon@google.comaf84e742012-10-05 13:23:24 +0000186}
bsalomon@google.com5b3e8902012-10-05 20:13:28 +0000187
188////////////////////////////////////////////////////////////////////////////////
189
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000190static size_t vertex_size(const GrVertexAttrib* attribs, int count) {
191 // this works as long as we're 4 byte-aligned
commit-bot@chromium.org515dcd32013-08-28 14:17:03 +0000192#ifdef SK_DEBUG
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000193 uint32_t overlapCheck = 0;
194#endif
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000195 SkASSERT(count <= GrDrawState::kMaxVertexAttribCnt);
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000196 size_t size = 0;
197 for (int index = 0; index < count; ++index) {
jvanverth@google.com054ae992013-04-01 20:06:51 +0000198 size_t attribSize = GrVertexAttribTypeSize(attribs[index].fType);
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000199 size += attribSize;
commit-bot@chromium.org515dcd32013-08-28 14:17:03 +0000200#ifdef SK_DEBUG
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000201 size_t dwordCount = attribSize >> 2;
202 uint32_t mask = (1 << dwordCount)-1;
203 size_t offsetShift = attribs[index].fOffset >> 2;
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000204 SkASSERT(!(overlapCheck & (mask << offsetShift)));
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000205 overlapCheck |= (mask << offsetShift);
206#endif
jvanverth@google.comcc782382013-01-28 20:39:48 +0000207 }
208 return size;
209}
210
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000211size_t GrDrawState::getVertexSize() const {
bsalomon2ed5ef82014-07-07 08:44:05 -0700212 return vertex_size(fVAPtr, fVACount);
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000213}
214
jvanverth@google.comcc782382013-01-28 20:39:48 +0000215////////////////////////////////////////////////////////////////////////////////
216
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000217void GrDrawState::setVertexAttribs(const GrVertexAttrib* attribs, int count) {
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000218 SkASSERT(count <= kMaxVertexAttribCnt);
robertphillips@google.com42903302013-04-20 12:26:07 +0000219
bsalomon2ed5ef82014-07-07 08:44:05 -0700220 fVAPtr = attribs;
221 fVACount = count;
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;
robertphillips@google.com42903302013-04-20 12:26:07 +0000259
jvanverth@google.com054ae992013-04-01 20:06:51 +0000260 // set all the fixed function indices to -1 except position.
bsalomon2ed5ef82014-07-07 08:44:05 -0700261 memset(fFixedFunctionVertexAttribIndices,
jvanverth@google.com054ae992013-04-01 20:06:51 +0000262 0xff,
bsalomon2ed5ef82014-07-07 08:44:05 -0700263 sizeof(fFixedFunctionVertexAttribIndices));
264 fFixedFunctionVertexAttribIndices[kPosition_GrVertexAttribBinding] = 0;
egdaniel9514d242014-07-18 06:15:43 -0700265 this->invalidateBlendOptFlags();
jvanverth@google.comcc782382013-01-28 20:39:48 +0000266}
267
268////////////////////////////////////////////////////////////////////////////////
269
commit-bot@chromium.orgff6ea262013-03-12 12:26:08 +0000270bool GrDrawState::validateVertexAttribs() const {
jvanverth@google.com054ae992013-04-01 20:06:51 +0000271 // check consistency of effects and attributes
272 GrSLType slTypes[kMaxVertexAttribCnt];
273 for (int i = 0; i < kMaxVertexAttribCnt; ++i) {
274 slTypes[i] = static_cast<GrSLType>(-1);
commit-bot@chromium.orgff6ea262013-03-12 12:26:08 +0000275 }
egdaniel776bdbd2014-08-06 11:07:02 -0700276 int totalStages = this->numTotalStages();
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000277 for (int s = 0; s < totalStages; ++s) {
egdaniel776bdbd2014-08-06 11:07:02 -0700278 int covIdx = s - this->numColorStages();
279 const GrEffectStage& stage = covIdx < 0 ? this->getColorStage(s) :
280 this->getCoverageStage(covIdx);
bsalomonf99f8842014-07-07 11:54:23 -0700281 const GrEffect* effect = stage.getEffect();
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000282 SkASSERT(NULL != effect);
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000283 // make sure that any attribute indices have the correct binding type, that the attrib
284 // type and effect's shader lang type are compatible, and that attributes shared by
285 // multiple effects use the same shader lang type.
286 const int* attributeIndices = stage.getVertexAttribIndices();
287 int numAttributes = stage.getVertexAttribIndexCount();
288 for (int i = 0; i < numAttributes; ++i) {
289 int attribIndex = attributeIndices[i];
bsalomon2ed5ef82014-07-07 08:44:05 -0700290 if (attribIndex >= fVACount ||
291 kEffect_GrVertexAttribBinding != fVAPtr[attribIndex].fBinding) {
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000292 return false;
jvanverth@google.comc7bf2962013-04-01 19:29:32 +0000293 }
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000294
bsalomonf99f8842014-07-07 11:54:23 -0700295 GrSLType effectSLType = effect->vertexAttribType(i);
bsalomon2ed5ef82014-07-07 08:44:05 -0700296 GrVertexAttribType attribType = fVAPtr[attribIndex].fType;
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000297 int slVecCount = GrSLTypeVectorCount(effectSLType);
298 int attribVecCount = GrVertexAttribTypeVectorCount(attribType);
299 if (slVecCount != attribVecCount ||
300 (static_cast<GrSLType>(-1) != slTypes[attribIndex] &&
301 slTypes[attribIndex] != effectSLType)) {
302 return false;
303 }
304 slTypes[attribIndex] = effectSLType;
commit-bot@chromium.orgff6ea262013-03-12 12:26:08 +0000305 }
306 }
307
308 return true;
309}
310
bsalomon@google.comd09ab842013-05-15 17:30:26 +0000311bool GrDrawState::willEffectReadDstColor() const {
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000312 if (!this->isColorWriteDisabled()) {
egdaniel776bdbd2014-08-06 11:07:02 -0700313 for (int s = 0; s < this->numColorStages(); ++s) {
314 if (this->getColorStage(s).getEffect()->willReadDstColor()) {
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000315 return true;
316 }
317 }
318 }
egdaniel776bdbd2014-08-06 11:07:02 -0700319 for (int s = 0; s < this->numCoverageStages(); ++s) {
320 if (this->getCoverageStage(s).getEffect()->willReadDstColor()) {
bsalomon@google.comd09ab842013-05-15 17:30:26 +0000321 return true;
322 }
323 }
324 return false;
325}
326
jvanverth@google.comcc782382013-01-28 20:39:48 +0000327////////////////////////////////////////////////////////////////////////////////
328
jvanverth@google.com054ae992013-04-01 20:06:51 +0000329bool GrDrawState::srcAlphaWillBeOne() const {
jvanverth@google.comcc782382013-01-28 20:39:48 +0000330 uint32_t validComponentFlags;
bsalomon@google.com89e6f5b2013-02-27 18:43:47 +0000331 GrColor color;
jvanverth@google.comcc782382013-01-28 20:39:48 +0000332 // Check if per-vertex or constant color may have partial alpha
jvanverth@google.com054ae992013-04-01 20:06:51 +0000333 if (this->hasColorVertexAttribute()) {
jvanverth@google.comcc782382013-01-28 20:39:48 +0000334 validComponentFlags = 0;
bsalomon@google.com89e6f5b2013-02-27 18:43:47 +0000335 color = 0; // not strictly necessary but we get false alarms from tools about uninit.
jvanverth@google.comcc782382013-01-28 20:39:48 +0000336 } else {
bsalomon@google.comb8eb2e82013-03-28 13:46:42 +0000337 validComponentFlags = kRGBA_GrColorComponentFlags;
jvanverth@google.comcc782382013-01-28 20:39:48 +0000338 color = this->getColor();
339 }
340
341 // Run through the color stages
egdaniel776bdbd2014-08-06 11:07:02 -0700342 for (int s = 0; s < this->numColorStages(); ++s) {
343 const GrEffect* effect = this->getColorStage(s).getEffect();
bsalomonf99f8842014-07-07 11:54:23 -0700344 effect->getConstantColorComponents(&color, &validComponentFlags);
jvanverth@google.comcc782382013-01-28 20:39:48 +0000345 }
346
jvanverth@google.comcc782382013-01-28 20:39:48 +0000347 // Check whether coverage is treated as color. If so we run through the coverage computation.
348 if (this->isCoverageDrawing()) {
commit-bot@chromium.orge0a868c2013-11-22 07:02:11 +0000349 GrColor coverageColor = this->getCoverageColor();
jvanverth@google.comcc782382013-01-28 20:39:48 +0000350 GrColor oldColor = color;
351 color = 0;
352 for (int c = 0; c < 4; ++c) {
353 if (validComponentFlags & (1 << c)) {
354 U8CPU a = (oldColor >> (c * 8)) & 0xff;
355 U8CPU b = (coverageColor >> (c * 8)) & 0xff;
356 color |= (SkMulDiv255Round(a, b) << (c * 8));
357 }
358 }
egdaniel776bdbd2014-08-06 11:07:02 -0700359 for (int s = 0; s < this->numCoverageStages(); ++s) {
360 const GrEffect* effect = this->getCoverageStage(s).getEffect();
bsalomonf99f8842014-07-07 11:54:23 -0700361 effect->getConstantColorComponents(&color, &validComponentFlags);
jvanverth@google.comcc782382013-01-28 20:39:48 +0000362 }
363 }
bsalomon@google.comb8eb2e82013-03-28 13:46:42 +0000364 return (kA_GrColorComponentFlag & validComponentFlags) && 0xff == GrColorUnpackA(color);
jvanverth@google.comcc782382013-01-28 20:39:48 +0000365}
366
jvanverth@google.com054ae992013-04-01 20:06:51 +0000367bool GrDrawState::hasSolidCoverage() const {
bsalomon@google.comd62e88e2013-02-01 14:19:27 +0000368 // If we're drawing coverage directly then coverage is effectively treated as color.
369 if (this->isCoverageDrawing()) {
370 return true;
371 }
372
373 GrColor coverage;
374 uint32_t validComponentFlags;
375 // Initialize to an unknown starting coverage if per-vertex coverage is specified.
jvanverth@google.com054ae992013-04-01 20:06:51 +0000376 if (this->hasCoverageVertexAttribute()) {
bsalomon@google.comd62e88e2013-02-01 14:19:27 +0000377 validComponentFlags = 0;
378 } else {
bsalomon2ed5ef82014-07-07 08:44:05 -0700379 coverage = fCoverage;
bsalomon@google.comb8eb2e82013-03-28 13:46:42 +0000380 validComponentFlags = kRGBA_GrColorComponentFlags;
bsalomon@google.comd62e88e2013-02-01 14:19:27 +0000381 }
382
383 // Run through the coverage stages and see if the coverage will be all ones at the end.
egdaniel776bdbd2014-08-06 11:07:02 -0700384 for (int s = 0; s < this->numCoverageStages(); ++s) {
385 const GrEffect* effect = this->getCoverageStage(s).getEffect();
bsalomonf99f8842014-07-07 11:54:23 -0700386 effect->getConstantColorComponents(&coverage, &validComponentFlags);
bsalomon@google.comd62e88e2013-02-01 14:19:27 +0000387 }
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000388 return (kRGBA_GrColorComponentFlags == validComponentFlags) && (0xffffffff == coverage);
bsalomon@google.comd62e88e2013-02-01 14:19:27 +0000389}
390
jvanverth@google.comcc782382013-01-28 20:39:48 +0000391////////////////////////////////////////////////////////////////////////////////
392
bsalomon@google.com2b446732013-02-12 16:47:41 +0000393// Some blend modes allow folding a fractional coverage value into the color's alpha channel, while
394// others will blend incorrectly.
395bool GrDrawState::canTweakAlphaForCoverage() const {
396 /*
397 The fractional coverage is f.
398 The src and dst coeffs are Cs and Cd.
399 The dst and src colors are S and D.
400 We want the blend to compute: f*Cs*S + (f*Cd + (1-f))D. By tweaking the source color's alpha
401 we're replacing S with S'=fS. It's obvious that that first term will always be ok. The second
402 term can be rearranged as [1-(1-Cd)f]D. By substituting in the various possibilities for Cd we
403 find that only 1, ISA, and ISC produce the correct destination when applied to S' and D.
404 Also, if we're directly rendering coverage (isCoverageDrawing) then coverage is treated as
405 color by definition.
406 */
egdaniel776bdbd2014-08-06 11:07:02 -0700407 return kOne_GrBlendCoeff == fState.fDstBlend ||
408 kISA_GrBlendCoeff == fState.fDstBlend ||
409 kISC_GrBlendCoeff == fState.fDstBlend ||
bsalomon@google.com2b446732013-02-12 16:47:41 +0000410 this->isCoverageDrawing();
411}
412
413GrDrawState::BlendOptFlags GrDrawState::getBlendOpts(bool forceCoverage,
414 GrBlendCoeff* srcCoeff,
415 GrBlendCoeff* dstCoeff) const {
bsalomon@google.com2b446732013-02-12 16:47:41 +0000416 GrBlendCoeff bogusSrcCoeff, bogusDstCoeff;
417 if (NULL == srcCoeff) {
418 srcCoeff = &bogusSrcCoeff;
419 }
bsalomon@google.com2b446732013-02-12 16:47:41 +0000420 if (NULL == dstCoeff) {
421 dstCoeff = &bogusDstCoeff;
422 }
egdaniel9514d242014-07-18 06:15:43 -0700423
424 if (forceCoverage) {
425 return this->calcBlendOpts(true, srcCoeff, dstCoeff);
426 }
427
428 if (0 == (fBlendOptFlags & kInvalid_BlendOptFlag)) {
429 *srcCoeff = fOptSrcBlend;
430 *dstCoeff = fOptDstBlend;
431 return fBlendOptFlags;
432 }
433
434 fBlendOptFlags = this->calcBlendOpts(forceCoverage, srcCoeff, dstCoeff);
435 fOptSrcBlend = *srcCoeff;
436 fOptDstBlend = *dstCoeff;
437
438 return fBlendOptFlags;
439}
440
441GrDrawState::BlendOptFlags GrDrawState::calcBlendOpts(bool forceCoverage,
442 GrBlendCoeff* srcCoeff,
443 GrBlendCoeff* dstCoeff) const {
444 *srcCoeff = this->getSrcBlendCoeff();
bsalomon@google.com2b446732013-02-12 16:47:41 +0000445 *dstCoeff = this->getDstBlendCoeff();
446
447 if (this->isColorWriteDisabled()) {
448 *srcCoeff = kZero_GrBlendCoeff;
449 *dstCoeff = kOne_GrBlendCoeff;
450 }
451
jvanverth@google.com054ae992013-04-01 20:06:51 +0000452 bool srcAIsOne = this->srcAlphaWillBeOne();
bsalomon@google.com2b446732013-02-12 16:47:41 +0000453 bool dstCoeffIsOne = kOne_GrBlendCoeff == *dstCoeff ||
454 (kSA_GrBlendCoeff == *dstCoeff && srcAIsOne);
455 bool dstCoeffIsZero = kZero_GrBlendCoeff == *dstCoeff ||
456 (kISA_GrBlendCoeff == *dstCoeff && srcAIsOne);
457
458 bool covIsZero = !this->isCoverageDrawing() &&
jvanverth@google.com054ae992013-04-01 20:06:51 +0000459 !this->hasCoverageVertexAttribute() &&
commit-bot@chromium.orge0a868c2013-11-22 07:02:11 +0000460 0 == this->getCoverageColor();
bsalomon@google.com2b446732013-02-12 16:47:41 +0000461 // When coeffs are (0,1) there is no reason to draw at all, unless
462 // stenciling is enabled. Having color writes disabled is effectively
463 // (0,1). The same applies when coverage is known to be 0.
464 if ((kZero_GrBlendCoeff == *srcCoeff && dstCoeffIsOne) || covIsZero) {
465 if (this->getStencil().doesWrite()) {
egdaniel0f1a7c42014-07-30 13:18:32 -0700466 return kEmitCoverage_BlendOptFlag;
bsalomon@google.com2b446732013-02-12 16:47:41 +0000467 } else {
468 return kSkipDraw_BlendOptFlag;
469 }
470 }
471
bsalomon@google.com4647f902013-03-26 14:45:27 +0000472 // check for coverage due to constant coverage, per-vertex coverage, or coverage stage
bsalomon@google.com2b446732013-02-12 16:47:41 +0000473 bool hasCoverage = forceCoverage ||
commit-bot@chromium.orge0a868c2013-11-22 07:02:11 +0000474 0xffffffff != this->getCoverageColor() ||
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000475 this->hasCoverageVertexAttribute() ||
egdaniel776bdbd2014-08-06 11:07:02 -0700476 this->numCoverageStages() > 0;
bsalomon@google.com2b446732013-02-12 16:47:41 +0000477
478 // if we don't have coverage we can check whether the dst
479 // has to read at all. If not, we'll disable blending.
480 if (!hasCoverage) {
481 if (dstCoeffIsZero) {
482 if (kOne_GrBlendCoeff == *srcCoeff) {
483 // if there is no coverage and coeffs are (1,0) then we
484 // won't need to read the dst at all, it gets replaced by src
egdaniel0f1a7c42014-07-30 13:18:32 -0700485 *dstCoeff = kZero_GrBlendCoeff;
486 return kNone_BlendOpt;
bsalomon@google.com2b446732013-02-12 16:47:41 +0000487 } else if (kZero_GrBlendCoeff == *srcCoeff) {
488 // if the op is "clear" then we don't need to emit a color
489 // or blend, just write transparent black into the dst.
490 *srcCoeff = kOne_GrBlendCoeff;
491 *dstCoeff = kZero_GrBlendCoeff;
egdaniel0f1a7c42014-07-30 13:18:32 -0700492 return kEmitTransBlack_BlendOptFlag;
bsalomon@google.com2b446732013-02-12 16:47:41 +0000493 }
494 }
495 } else if (this->isCoverageDrawing()) {
496 // we have coverage but we aren't distinguishing it from alpha by request.
497 return kCoverageAsAlpha_BlendOptFlag;
498 } else {
499 // check whether coverage can be safely rolled into alpha
500 // of if we can skip color computation and just emit coverage
501 if (this->canTweakAlphaForCoverage()) {
502 return kCoverageAsAlpha_BlendOptFlag;
503 }
504 if (dstCoeffIsZero) {
505 if (kZero_GrBlendCoeff == *srcCoeff) {
506 // the source color is not included in the blend
507 // the dst coeff is effectively zero so blend works out to:
508 // (c)(0)D + (1-c)D = (1-c)D.
509 *dstCoeff = kISA_GrBlendCoeff;
510 return kEmitCoverage_BlendOptFlag;
511 } else if (srcAIsOne) {
512 // the dst coeff is effectively zero so blend works out to:
513 // cS + (c)(0)D + (1-c)D = cS + (1-c)D.
514 // If Sa is 1 then we can replace Sa with c
515 // and set dst coeff to 1-Sa.
516 *dstCoeff = kISA_GrBlendCoeff;
517 return kCoverageAsAlpha_BlendOptFlag;
518 }
519 } else if (dstCoeffIsOne) {
520 // the dst coeff is effectively one so blend works out to:
521 // cS + (c)(1)D + (1-c)D = cS + D.
522 *dstCoeff = kOne_GrBlendCoeff;
523 return kCoverageAsAlpha_BlendOptFlag;
524 }
525 }
egdaniel0f1a7c42014-07-30 13:18:32 -0700526
bsalomon@google.com2b446732013-02-12 16:47:41 +0000527 return kNone_BlendOpt;
528}
529
egdaniel02cafcc2014-07-21 11:37:28 -0700530bool GrDrawState::canIgnoreColorAttribute() const {
531 if (fBlendOptFlags & kInvalid_BlendOptFlag) {
532 this->getBlendOpts();
533 }
534 return SkToBool(fBlendOptFlags & (GrDrawState::kEmitTransBlack_BlendOptFlag |
535 GrDrawState::kEmitCoverage_BlendOptFlag));
536}
537
bsalomon8f727332014-08-05 07:50:06 -0700538//////////////////////////////////////////////////////////////////////////////
539
540GrDrawState::AutoVertexAttribRestore::AutoVertexAttribRestore(
541 GrDrawState* drawState) {
542 SkASSERT(NULL != drawState);
543 fDrawState = drawState;
544 fVAPtr = drawState->fVAPtr;
545 fVACount = drawState->fVACount;
546 fDrawState->setDefaultVertexAttribs();
547}
548
549//////////////////////////////////////////////////////////////////////////////s
550
551void GrDrawState::AutoRestoreEffects::set(GrDrawState* ds) {
552 if (NULL != fDrawState) {
egdaniel776bdbd2014-08-06 11:07:02 -0700553 int m = fDrawState->numColorStages() - fColorEffectCnt;
bsalomon8f727332014-08-05 07:50:06 -0700554 SkASSERT(m >= 0);
egdaniel776bdbd2014-08-06 11:07:02 -0700555 fDrawState->fState.fColorStages.pop_back_n(m);
bsalomon8f727332014-08-05 07:50:06 -0700556
egdaniel776bdbd2014-08-06 11:07:02 -0700557 int n = fDrawState->numCoverageStages() - fCoverageEffectCnt;
bsalomon8f727332014-08-05 07:50:06 -0700558 SkASSERT(n >= 0);
egdaniel776bdbd2014-08-06 11:07:02 -0700559 fDrawState->fState.fCoverageStages.pop_back_n(n);
bsalomon8f727332014-08-05 07:50:06 -0700560 if (m + n > 0) {
561 fDrawState->invalidateBlendOptFlags();
562 }
563 SkDEBUGCODE(--fDrawState->fBlockEffectRemovalCnt;)
564 }
565 fDrawState = ds;
566 if (NULL != ds) {
egdaniel776bdbd2014-08-06 11:07:02 -0700567 fColorEffectCnt = ds->numColorStages();
568 fCoverageEffectCnt = ds->numCoverageStages();
bsalomon8f727332014-08-05 07:50:06 -0700569 SkDEBUGCODE(++ds->fBlockEffectRemovalCnt;)
570 }
571}
egdaniel02cafcc2014-07-21 11:37:28 -0700572
bsalomon@google.com2b446732013-02-12 16:47:41 +0000573////////////////////////////////////////////////////////////////////////////////
574
bsalomon@google.com2fdcdeb2012-10-08 17:15:55 +0000575void GrDrawState::AutoViewMatrixRestore::restore() {
576 if (NULL != fDrawState) {
commit-bot@chromium.org1acc3d72013-09-06 23:13:05 +0000577 SkDEBUGCODE(--fDrawState->fBlockEffectRemovalCnt;)
bsalomon2ed5ef82014-07-07 08:44:05 -0700578 fDrawState->fViewMatrix = fViewMatrix;
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000579 SkASSERT(fDrawState->numColorStages() >= fNumColorStages);
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000580 int numCoverageStages = fSavedCoordChanges.count() - fNumColorStages;
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000581 SkASSERT(fDrawState->numCoverageStages() >= numCoverageStages);
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000582
583 int i = 0;
584 for (int s = 0; s < fNumColorStages; ++s, ++i) {
egdaniel776bdbd2014-08-06 11:07:02 -0700585 fDrawState->fState.fColorStages[s].restoreCoordChange(fSavedCoordChanges[i]);
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000586 }
587 for (int s = 0; s < numCoverageStages; ++s, ++i) {
egdaniel776bdbd2014-08-06 11:07:02 -0700588 fDrawState->fState.fCoverageStages[s].restoreCoordChange(fSavedCoordChanges[i]);
bsalomon@google.com2fdcdeb2012-10-08 17:15:55 +0000589 }
bsalomon@google.com137f1342013-05-29 21:27:53 +0000590 fDrawState = NULL;
bsalomon@google.com2fdcdeb2012-10-08 17:15:55 +0000591 }
bsalomon@google.com2fdcdeb2012-10-08 17:15:55 +0000592}
593
594void GrDrawState::AutoViewMatrixRestore::set(GrDrawState* drawState,
bsalomon@google.comc7818882013-03-20 19:19:53 +0000595 const SkMatrix& preconcatMatrix) {
bsalomon@google.com2fdcdeb2012-10-08 17:15:55 +0000596 this->restore();
bsalomon@google.com5b3e8902012-10-05 20:13:28 +0000597
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000598 SkASSERT(NULL == fDrawState);
bsalomon@google.com137f1342013-05-29 21:27:53 +0000599 if (NULL == drawState || preconcatMatrix.isIdentity()) {
bsalomon@google.com2fdcdeb2012-10-08 17:15:55 +0000600 return;
601 }
bsalomon@google.com137f1342013-05-29 21:27:53 +0000602 fDrawState = drawState;
bsalomon@google.com2fdcdeb2012-10-08 17:15:55 +0000603
bsalomon@google.com2fdcdeb2012-10-08 17:15:55 +0000604 fViewMatrix = drawState->getViewMatrix();
bsalomon2ed5ef82014-07-07 08:44:05 -0700605 drawState->fViewMatrix.preConcat(preconcatMatrix);
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000606
607 this->doEffectCoordChanges(preconcatMatrix);
commit-bot@chromium.org1acc3d72013-09-06 23:13:05 +0000608 SkDEBUGCODE(++fDrawState->fBlockEffectRemovalCnt;)
bsalomon@google.com2fdcdeb2012-10-08 17:15:55 +0000609}
610
bsalomon@google.com137f1342013-05-29 21:27:53 +0000611bool GrDrawState::AutoViewMatrixRestore::setIdentity(GrDrawState* drawState) {
bsalomon@google.com2fdcdeb2012-10-08 17:15:55 +0000612 this->restore();
613
bsalomon@google.com137f1342013-05-29 21:27:53 +0000614 if (NULL == drawState) {
bsalomon@google.com2fdcdeb2012-10-08 17:15:55 +0000615 return false;
skia.committer@gmail.comf467ce72012-10-09 02:01:37 +0000616 }
bsalomon@google.com2fdcdeb2012-10-08 17:15:55 +0000617
bsalomon@google.com137f1342013-05-29 21:27:53 +0000618 if (drawState->getViewMatrix().isIdentity()) {
619 return true;
620 }
621
bsalomon@google.com5b3e8902012-10-05 20:13:28 +0000622 fViewMatrix = drawState->getViewMatrix();
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000623 if (0 == drawState->numTotalStages()) {
bsalomon2ed5ef82014-07-07 08:44:05 -0700624 drawState->fViewMatrix.reset();
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000625 fDrawState = drawState;
626 fNumColorStages = 0;
627 fSavedCoordChanges.reset(0);
commit-bot@chromium.org1acc3d72013-09-06 23:13:05 +0000628 SkDEBUGCODE(++fDrawState->fBlockEffectRemovalCnt;)
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000629 return true;
630 } else {
631 SkMatrix inv;
632 if (!fViewMatrix.invert(&inv)) {
633 return false;
bsalomon@google.com5b3e8902012-10-05 20:13:28 +0000634 }
bsalomon2ed5ef82014-07-07 08:44:05 -0700635 drawState->fViewMatrix.reset();
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000636 fDrawState = drawState;
637 this->doEffectCoordChanges(inv);
commit-bot@chromium.org1acc3d72013-09-06 23:13:05 +0000638 SkDEBUGCODE(++fDrawState->fBlockEffectRemovalCnt;)
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000639 return true;
bsalomon@google.com5b3e8902012-10-05 20:13:28 +0000640 }
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000641}
642
643void GrDrawState::AutoViewMatrixRestore::doEffectCoordChanges(const SkMatrix& coordChangeMatrix) {
644 fSavedCoordChanges.reset(fDrawState->numTotalStages());
645 int i = 0;
646
647 fNumColorStages = fDrawState->numColorStages();
648 for (int s = 0; s < fNumColorStages; ++s, ++i) {
egdaniel776bdbd2014-08-06 11:07:02 -0700649 fDrawState->getColorStage(s).saveCoordChange(&fSavedCoordChanges[i]);
650 fDrawState->fState.fColorStages[s].localCoordChange(coordChangeMatrix);
bsalomon@google.com137f1342013-05-29 21:27:53 +0000651 }
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000652
653 int numCoverageStages = fDrawState->numCoverageStages();
654 for (int s = 0; s < numCoverageStages; ++s, ++i) {
egdaniel776bdbd2014-08-06 11:07:02 -0700655 fDrawState->getCoverageStage(s).saveCoordChange(&fSavedCoordChanges[i]);
656 fDrawState->fState.fCoverageStages[s].localCoordChange(coordChangeMatrix);
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000657 }
bsalomon@google.com5b3e8902012-10-05 20:13:28 +0000658}