blob: e13c6057f846b228f96771f2c205617bda0e6871 [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
egdaniel776bdbd2014-08-06 11:07:02 -070014bool GrDrawState::State::HaveCompatibleState(const State& a, const State& b,
15 bool explicitLocalCoords) {
16 if (a.fColorStages.count() != b.fColorStages.count() ||
17 a.fCoverageStages.count() != b.fCoverageStages.count() ||
18 a.fSrcBlend != b.fSrcBlend ||
19 a.fDstBlend != b.fDstBlend) {
20 return false;
21 }
22 for (int i = 0; i < a.fColorStages.count(); i++) {
23 if (!GrEffectStage::AreCompatible(a.fColorStages[i], b.fColorStages[i],
24 explicitLocalCoords)) {
25 return false;
26 }
27 }
28 for (int i = 0; i < a.fCoverageStages.count(); i++) {
29 if (!GrEffectStage::AreCompatible(a.fCoverageStages[i], b.fCoverageStages[i],
30 explicitLocalCoords)) {
31 return false;
32 }
33 }
34 return true;
35}
36//////////////////////////////////////////////////////////////////////////////s
bsalomon8f727332014-08-05 07:50:06 -070037GrDrawState::CombinedState GrDrawState::CombineIfPossible(
bsalomon62c447d2014-08-08 08:08:50 -070038 const GrDrawState& a, const GrDrawState& b, const GrDrawTargetCaps& caps) {
bsalomon8f727332014-08-05 07:50:06 -070039
40 bool usingVertexColors = a.hasColorVertexAttribute();
41 if (!usingVertexColors && a.fColor != b.fColor) {
42 return kIncompatible_CombinedState;
43 }
44
45 if (a.fRenderTarget.get() != b.fRenderTarget.get() ||
bsalomon8f727332014-08-05 07:50:06 -070046 !a.fViewMatrix.cheapEqualTo(b.fViewMatrix) ||
bsalomon8f727332014-08-05 07:50:06 -070047 a.fBlendConstant != b.fBlendConstant ||
48 a.fFlagBits != b.fFlagBits ||
49 a.fVACount != b.fVACount ||
50 memcmp(a.fVAPtr, b.fVAPtr, a.fVACount * sizeof(GrVertexAttrib)) ||
51 a.fStencilSettings != b.fStencilSettings ||
52 a.fDrawFace != b.fDrawFace) {
53 return kIncompatible_CombinedState;
54 }
55
56 bool usingVertexCoverage = a.hasCoverageVertexAttribute();
57 if (!usingVertexCoverage && a.fCoverage != b.fCoverage) {
58 return kIncompatible_CombinedState;
59 }
60
61 bool explicitLocalCoords = a.hasLocalCoordAttribute();
egdaniel776bdbd2014-08-06 11:07:02 -070062
bsalomon8f727332014-08-05 07:50:06 -070063 SkASSERT(0 == memcmp(a.fFixedFunctionVertexAttribIndices,
64 b.fFixedFunctionVertexAttribIndices,
65 sizeof(a.fFixedFunctionVertexAttribIndices)));
egdaniel776bdbd2014-08-06 11:07:02 -070066 if (!State::HaveCompatibleState(a.fState, b.fState, explicitLocalCoords)) {
67 return kIncompatible_CombinedState;
68 }
bsalomon62c447d2014-08-08 08:08:50 -070069
70 if (usingVertexColors) {
71 // If one is opaque and the other is not then the combined state is not opaque. Moreover,
72 // if the opaqueness affects the ability to get color/coverage blending correct then we
73 // don't combine the draw states.
74 bool aIsOpaque = (kVertexColorsAreOpaque_Hint & a.fHints);
75 bool bIsOpaque = (kVertexColorsAreOpaque_Hint & b.fHints);
76 if (aIsOpaque != bIsOpaque) {
77 const GrDrawState* opaque;
78 const GrDrawState* nonOpaque;
79 if (aIsOpaque) {
80 opaque = &a;
81 nonOpaque = &b;
82 } else {
83 opaque = &b;
84 nonOpaque = &a;
85 }
86 if (!opaque->hasSolidCoverage() && opaque->couldApplyCoverage(caps)) {
87 SkASSERT(!nonOpaque->hasSolidCoverage());
88 if (!nonOpaque->couldApplyCoverage(caps)) {
89 return kIncompatible_CombinedState;
90 }
91 }
92 return aIsOpaque ? kB_CombinedState : kA_CombinedState;
93 }
94 }
bsalomon8f727332014-08-05 07:50:06 -070095 return kAOrB_CombinedState;
96}
97
bsalomon8f727332014-08-05 07:50:06 -070098//////////////////////////////////////////////////////////////////////////////s
99
100GrDrawState::GrDrawState(const GrDrawState& state, const SkMatrix& preConcatMatrix) {
101 SkDEBUGCODE(fBlockEffectRemovalCnt = 0;)
102 *this = state;
103 if (!preConcatMatrix.isIdentity()) {
egdaniel776bdbd2014-08-06 11:07:02 -0700104 for (int i = 0; i < this->numColorStages(); ++i) {
105 fState.fColorStages[i].localCoordChange(preConcatMatrix);
bsalomon8f727332014-08-05 07:50:06 -0700106 }
egdaniel776bdbd2014-08-06 11:07:02 -0700107 for (int i = 0; i < this->numCoverageStages(); ++i) {
108 fState.fCoverageStages[i].localCoordChange(preConcatMatrix);
bsalomon8f727332014-08-05 07:50:06 -0700109 }
110 this->invalidateBlendOptFlags();
111 }
112}
113
114GrDrawState& GrDrawState::operator=(const GrDrawState& that) {
115 SkASSERT(0 == fBlockEffectRemovalCnt || 0 == this->numTotalStages());
116 this->setRenderTarget(that.fRenderTarget.get());
117 fColor = that.fColor;
118 fViewMatrix = that.fViewMatrix;
bsalomon8f727332014-08-05 07:50:06 -0700119 fBlendConstant = that.fBlendConstant;
120 fFlagBits = that.fFlagBits;
121 fVACount = that.fVACount;
122 fVAPtr = that.fVAPtr;
123 fStencilSettings = that.fStencilSettings;
124 fCoverage = that.fCoverage;
125 fDrawFace = that.fDrawFace;
bsalomon8f727332014-08-05 07:50:06 -0700126 fOptSrcBlend = that.fOptSrcBlend;
127 fOptDstBlend = that.fOptDstBlend;
128 fBlendOptFlags = that.fBlendOptFlags;
129
egdaniel776bdbd2014-08-06 11:07:02 -0700130 fState = that.fState;
bsalomon62c447d2014-08-08 08:08:50 -0700131 fHints = that.fHints;
egdaniel776bdbd2014-08-06 11:07:02 -0700132
bsalomon8f727332014-08-05 07:50:06 -0700133 memcpy(fFixedFunctionVertexAttribIndices,
134 that.fFixedFunctionVertexAttribIndices,
135 sizeof(fFixedFunctionVertexAttribIndices));
136 return *this;
137}
138
139void GrDrawState::onReset(const SkMatrix* initialViewMatrix) {
140 SkASSERT(0 == fBlockEffectRemovalCnt || 0 == this->numTotalStages());
egdaniel776bdbd2014-08-06 11:07:02 -0700141 fState.reset();
bsalomon8f727332014-08-05 07:50:06 -0700142
143 fRenderTarget.reset(NULL);
144
145 this->setDefaultVertexAttribs();
146
147 fColor = 0xffffffff;
148 if (NULL == initialViewMatrix) {
149 fViewMatrix.reset();
150 } else {
151 fViewMatrix = *initialViewMatrix;
152 }
bsalomon8f727332014-08-05 07:50:06 -0700153 fBlendConstant = 0x0;
154 fFlagBits = 0x0;
155 fStencilSettings.setDisabled();
156 fCoverage = 0xffffffff;
157 fDrawFace = kBoth_DrawFace;
158
bsalomon62c447d2014-08-08 08:08:50 -0700159 fHints = 0;
160
bsalomon8f727332014-08-05 07:50:06 -0700161 this->invalidateBlendOptFlags();
162}
163
bsalomon@google.com137f1342013-05-29 21:27:53 +0000164bool GrDrawState::setIdentityViewMatrix() {
egdaniel776bdbd2014-08-06 11:07:02 -0700165 if (this->numTotalStages()) {
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000166 SkMatrix invVM;
bsalomon2ed5ef82014-07-07 08:44:05 -0700167 if (!fViewMatrix.invert(&invVM)) {
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000168 // sad trombone sound
169 return false;
170 }
egdaniel776bdbd2014-08-06 11:07:02 -0700171 for (int s = 0; s < this->numColorStages(); ++s) {
172 fState.fColorStages[s].localCoordChange(invVM);
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000173 }
egdaniel776bdbd2014-08-06 11:07:02 -0700174 for (int s = 0; s < this->numCoverageStages(); ++s) {
175 fState.fCoverageStages[s].localCoordChange(invVM);
bsalomon@google.com137f1342013-05-29 21:27:53 +0000176 }
177 }
bsalomon2ed5ef82014-07-07 08:44:05 -0700178 fViewMatrix.reset();
bsalomon@google.com137f1342013-05-29 21:27:53 +0000179 return true;
180}
181
commit-bot@chromium.orgbb6a3172013-05-28 17:25:49 +0000182void GrDrawState::setFromPaint(const GrPaint& paint, const SkMatrix& vm, GrRenderTarget* rt) {
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000183 SkASSERT(0 == fBlockEffectRemovalCnt || 0 == this->numTotalStages());
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000184
egdaniel776bdbd2014-08-06 11:07:02 -0700185 fState.reset();
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000186
commit-bot@chromium.org42dacab2013-07-13 17:24:24 +0000187 for (int i = 0; i < paint.numColorStages(); ++i) {
egdaniel776bdbd2014-08-06 11:07:02 -0700188 fState.fColorStages.push_back(paint.getColorStage(i));
bsalomon@google.comaf84e742012-10-05 13:23:24 +0000189 }
190
commit-bot@chromium.org42dacab2013-07-13 17:24:24 +0000191 for (int i = 0; i < paint.numCoverageStages(); ++i) {
egdaniel776bdbd2014-08-06 11:07:02 -0700192 fState.fCoverageStages.push_back(paint.getCoverageStage(i));
bsalomon@google.comaf84e742012-10-05 13:23:24 +0000193 }
194
commit-bot@chromium.orgbb6a3172013-05-28 17:25:49 +0000195 this->setRenderTarget(rt);
bsalomon@google.comaf84e742012-10-05 13:23:24 +0000196
bsalomon2ed5ef82014-07-07 08:44:05 -0700197 fViewMatrix = vm;
commit-bot@chromium.orgbb6a3172013-05-28 17:25:49 +0000198
199 // These have no equivalent in GrPaint, set them to defaults
bsalomon2ed5ef82014-07-07 08:44:05 -0700200 fBlendConstant = 0x0;
201 fDrawFace = kBoth_DrawFace;
202 fStencilSettings.setDisabled();
commit-bot@chromium.orgbb6a3172013-05-28 17:25:49 +0000203 this->resetStateFlags();
bsalomon62c447d2014-08-08 08:08:50 -0700204 fHints = 0;
commit-bot@chromium.orgbb6a3172013-05-28 17:25:49 +0000205
bsalomon@google.com21c10c52013-06-13 17:44:07 +0000206 // Enable the clip bit
207 this->enableState(GrDrawState::kClip_StateBit);
208
commit-bot@chromium.orgbb6a3172013-05-28 17:25:49 +0000209 this->setColor(paint.getColor());
bsalomon@google.comc7448ce2012-10-05 19:04:13 +0000210 this->setState(GrDrawState::kDither_StateBit, paint.isDither());
211 this->setState(GrDrawState::kHWAntialias_StateBit, paint.isAntiAlias());
bsalomon@google.comaf84e742012-10-05 13:23:24 +0000212
bsalomon@google.comc7448ce2012-10-05 19:04:13 +0000213 this->setBlendFunc(paint.getSrcBlendCoeff(), paint.getDstBlendCoeff());
bsalomon@google.comc7448ce2012-10-05 19:04:13 +0000214 this->setCoverage(paint.getCoverage());
egdaniel9514d242014-07-18 06:15:43 -0700215 this->invalidateBlendOptFlags();
bsalomon@google.comaf84e742012-10-05 13:23:24 +0000216}
bsalomon@google.com5b3e8902012-10-05 20:13:28 +0000217
218////////////////////////////////////////////////////////////////////////////////
219
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000220static size_t vertex_size(const GrVertexAttrib* attribs, int count) {
221 // this works as long as we're 4 byte-aligned
commit-bot@chromium.org515dcd32013-08-28 14:17:03 +0000222#ifdef SK_DEBUG
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000223 uint32_t overlapCheck = 0;
224#endif
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000225 SkASSERT(count <= GrDrawState::kMaxVertexAttribCnt);
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000226 size_t size = 0;
227 for (int index = 0; index < count; ++index) {
jvanverth@google.com054ae992013-04-01 20:06:51 +0000228 size_t attribSize = GrVertexAttribTypeSize(attribs[index].fType);
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000229 size += attribSize;
commit-bot@chromium.org515dcd32013-08-28 14:17:03 +0000230#ifdef SK_DEBUG
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000231 size_t dwordCount = attribSize >> 2;
232 uint32_t mask = (1 << dwordCount)-1;
233 size_t offsetShift = attribs[index].fOffset >> 2;
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000234 SkASSERT(!(overlapCheck & (mask << offsetShift)));
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000235 overlapCheck |= (mask << offsetShift);
236#endif
jvanverth@google.comcc782382013-01-28 20:39:48 +0000237 }
238 return size;
239}
240
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000241size_t GrDrawState::getVertexSize() const {
bsalomon2ed5ef82014-07-07 08:44:05 -0700242 return vertex_size(fVAPtr, fVACount);
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000243}
244
jvanverth@google.comcc782382013-01-28 20:39:48 +0000245////////////////////////////////////////////////////////////////////////////////
246
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000247void GrDrawState::setVertexAttribs(const GrVertexAttrib* attribs, int count) {
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000248 SkASSERT(count <= kMaxVertexAttribCnt);
robertphillips@google.com42903302013-04-20 12:26:07 +0000249
bsalomon2ed5ef82014-07-07 08:44:05 -0700250 fVAPtr = attribs;
251 fVACount = count;
jvanverth@google.com054ae992013-04-01 20:06:51 +0000252
253 // Set all the indices to -1
bsalomon2ed5ef82014-07-07 08:44:05 -0700254 memset(fFixedFunctionVertexAttribIndices,
jvanverth@google.com054ae992013-04-01 20:06:51 +0000255 0xff,
bsalomon2ed5ef82014-07-07 08:44:05 -0700256 sizeof(fFixedFunctionVertexAttribIndices));
commit-bot@chromium.org515dcd32013-08-28 14:17:03 +0000257#ifdef SK_DEBUG
jvanverth@google.com054ae992013-04-01 20:06:51 +0000258 uint32_t overlapCheck = 0;
259#endif
260 for (int i = 0; i < count; ++i) {
261 if (attribs[i].fBinding < kGrFixedFunctionVertexAttribBindingCnt) {
262 // The fixed function attribs can only be specified once
bsalomon2ed5ef82014-07-07 08:44:05 -0700263 SkASSERT(-1 == fFixedFunctionVertexAttribIndices[attribs[i].fBinding]);
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000264 SkASSERT(GrFixedFunctionVertexAttribVectorCount(attribs[i].fBinding) ==
jvanverth@google.com054ae992013-04-01 20:06:51 +0000265 GrVertexAttribTypeVectorCount(attribs[i].fType));
bsalomon2ed5ef82014-07-07 08:44:05 -0700266 fFixedFunctionVertexAttribIndices[attribs[i].fBinding] = i;
jvanverth@google.com054ae992013-04-01 20:06:51 +0000267 }
commit-bot@chromium.org515dcd32013-08-28 14:17:03 +0000268#ifdef SK_DEBUG
jvanverth@google.com054ae992013-04-01 20:06:51 +0000269 size_t dwordCount = GrVertexAttribTypeSize(attribs[i].fType) >> 2;
270 uint32_t mask = (1 << dwordCount)-1;
271 size_t offsetShift = attribs[i].fOffset >> 2;
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000272 SkASSERT(!(overlapCheck & (mask << offsetShift)));
jvanverth@google.com054ae992013-04-01 20:06:51 +0000273 overlapCheck |= (mask << offsetShift);
274#endif
jvanverth@google.comcc782382013-01-28 20:39:48 +0000275 }
egdaniel9514d242014-07-18 06:15:43 -0700276 this->invalidateBlendOptFlags();
jvanverth@google.com054ae992013-04-01 20:06:51 +0000277 // Positions must be specified.
bsalomon2ed5ef82014-07-07 08:44:05 -0700278 SkASSERT(-1 != fFixedFunctionVertexAttribIndices[kPosition_GrVertexAttribBinding]);
jvanverth@google.comcc782382013-01-28 20:39:48 +0000279}
280
281////////////////////////////////////////////////////////////////////////////////
282
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000283void GrDrawState::setDefaultVertexAttribs() {
jvanverth@google.com054ae992013-04-01 20:06:51 +0000284 static const GrVertexAttrib kPositionAttrib =
285 {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding};
robertphillips@google.com42903302013-04-20 12:26:07 +0000286
bsalomon2ed5ef82014-07-07 08:44:05 -0700287 fVAPtr = &kPositionAttrib;
288 fVACount = 1;
robertphillips@google.com42903302013-04-20 12:26:07 +0000289
jvanverth@google.com054ae992013-04-01 20:06:51 +0000290 // set all the fixed function indices to -1 except position.
bsalomon2ed5ef82014-07-07 08:44:05 -0700291 memset(fFixedFunctionVertexAttribIndices,
jvanverth@google.com054ae992013-04-01 20:06:51 +0000292 0xff,
bsalomon2ed5ef82014-07-07 08:44:05 -0700293 sizeof(fFixedFunctionVertexAttribIndices));
294 fFixedFunctionVertexAttribIndices[kPosition_GrVertexAttribBinding] = 0;
egdaniel9514d242014-07-18 06:15:43 -0700295 this->invalidateBlendOptFlags();
jvanverth@google.comcc782382013-01-28 20:39:48 +0000296}
297
298////////////////////////////////////////////////////////////////////////////////
299
commit-bot@chromium.orgff6ea262013-03-12 12:26:08 +0000300bool GrDrawState::validateVertexAttribs() const {
jvanverth@google.com054ae992013-04-01 20:06:51 +0000301 // check consistency of effects and attributes
302 GrSLType slTypes[kMaxVertexAttribCnt];
303 for (int i = 0; i < kMaxVertexAttribCnt; ++i) {
304 slTypes[i] = static_cast<GrSLType>(-1);
commit-bot@chromium.orgff6ea262013-03-12 12:26:08 +0000305 }
egdaniel776bdbd2014-08-06 11:07:02 -0700306 int totalStages = this->numTotalStages();
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000307 for (int s = 0; s < totalStages; ++s) {
egdaniel776bdbd2014-08-06 11:07:02 -0700308 int covIdx = s - this->numColorStages();
309 const GrEffectStage& stage = covIdx < 0 ? this->getColorStage(s) :
310 this->getCoverageStage(covIdx);
bsalomonf99f8842014-07-07 11:54:23 -0700311 const GrEffect* effect = stage.getEffect();
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000312 SkASSERT(NULL != effect);
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000313 // make sure that any attribute indices have the correct binding type, that the attrib
314 // type and effect's shader lang type are compatible, and that attributes shared by
315 // multiple effects use the same shader lang type.
316 const int* attributeIndices = stage.getVertexAttribIndices();
317 int numAttributes = stage.getVertexAttribIndexCount();
318 for (int i = 0; i < numAttributes; ++i) {
319 int attribIndex = attributeIndices[i];
bsalomon2ed5ef82014-07-07 08:44:05 -0700320 if (attribIndex >= fVACount ||
321 kEffect_GrVertexAttribBinding != fVAPtr[attribIndex].fBinding) {
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000322 return false;
jvanverth@google.comc7bf2962013-04-01 19:29:32 +0000323 }
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000324
bsalomonf99f8842014-07-07 11:54:23 -0700325 GrSLType effectSLType = effect->vertexAttribType(i);
bsalomon2ed5ef82014-07-07 08:44:05 -0700326 GrVertexAttribType attribType = fVAPtr[attribIndex].fType;
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000327 int slVecCount = GrSLTypeVectorCount(effectSLType);
328 int attribVecCount = GrVertexAttribTypeVectorCount(attribType);
329 if (slVecCount != attribVecCount ||
330 (static_cast<GrSLType>(-1) != slTypes[attribIndex] &&
331 slTypes[attribIndex] != effectSLType)) {
332 return false;
333 }
334 slTypes[attribIndex] = effectSLType;
commit-bot@chromium.orgff6ea262013-03-12 12:26:08 +0000335 }
336 }
337
338 return true;
339}
340
bsalomon@google.comd09ab842013-05-15 17:30:26 +0000341bool GrDrawState::willEffectReadDstColor() const {
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000342 if (!this->isColorWriteDisabled()) {
egdaniel776bdbd2014-08-06 11:07:02 -0700343 for (int s = 0; s < this->numColorStages(); ++s) {
344 if (this->getColorStage(s).getEffect()->willReadDstColor()) {
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000345 return true;
346 }
347 }
348 }
egdaniel776bdbd2014-08-06 11:07:02 -0700349 for (int s = 0; s < this->numCoverageStages(); ++s) {
350 if (this->getCoverageStage(s).getEffect()->willReadDstColor()) {
bsalomon@google.comd09ab842013-05-15 17:30:26 +0000351 return true;
352 }
353 }
354 return false;
355}
356
jvanverth@google.comcc782382013-01-28 20:39:48 +0000357////////////////////////////////////////////////////////////////////////////////
358
bsalomon62c447d2014-08-08 08:08:50 -0700359bool GrDrawState::couldApplyCoverage(const GrDrawTargetCaps& caps) const {
360 if (caps.dualSourceBlendingSupport()) {
361 return true;
362 }
363 // we can correctly apply coverage if a) we have dual source blending
364 // or b) one of our blend optimizations applies
365 // or c) the src, dst blend coeffs are 1,0 and we will read Dst Color
366 GrBlendCoeff srcCoeff;
367 GrBlendCoeff dstCoeff;
368 GrDrawState::BlendOptFlags flag = this->getBlendOpts(true, &srcCoeff, &dstCoeff);
369 return GrDrawState::kNone_BlendOpt != flag ||
370 (this->willEffectReadDstColor() &&
371 kOne_GrBlendCoeff == srcCoeff && kZero_GrBlendCoeff == dstCoeff);
372}
373
jvanverth@google.com054ae992013-04-01 20:06:51 +0000374bool GrDrawState::srcAlphaWillBeOne() const {
jvanverth@google.comcc782382013-01-28 20:39:48 +0000375 uint32_t validComponentFlags;
bsalomon@google.com89e6f5b2013-02-27 18:43:47 +0000376 GrColor color;
jvanverth@google.comcc782382013-01-28 20:39:48 +0000377 // Check if per-vertex or constant color may have partial alpha
jvanverth@google.com054ae992013-04-01 20:06:51 +0000378 if (this->hasColorVertexAttribute()) {
bsalomon62c447d2014-08-08 08:08:50 -0700379 if (fHints & kVertexColorsAreOpaque_Hint) {
380 validComponentFlags = kA_GrColorComponentFlag;
381 color = 0xFF << GrColor_SHIFT_A;
382 } else {
383 validComponentFlags = 0;
384 color = 0; // not strictly necessary but we get false alarms from tools about uninit.
385 }
jvanverth@google.comcc782382013-01-28 20:39:48 +0000386 } else {
bsalomon@google.comb8eb2e82013-03-28 13:46:42 +0000387 validComponentFlags = kRGBA_GrColorComponentFlags;
jvanverth@google.comcc782382013-01-28 20:39:48 +0000388 color = this->getColor();
389 }
390
391 // Run through the color stages
egdaniel776bdbd2014-08-06 11:07:02 -0700392 for (int s = 0; s < this->numColorStages(); ++s) {
393 const GrEffect* effect = this->getColorStage(s).getEffect();
bsalomonf99f8842014-07-07 11:54:23 -0700394 effect->getConstantColorComponents(&color, &validComponentFlags);
jvanverth@google.comcc782382013-01-28 20:39:48 +0000395 }
396
jvanverth@google.comcc782382013-01-28 20:39:48 +0000397 // Check whether coverage is treated as color. If so we run through the coverage computation.
398 if (this->isCoverageDrawing()) {
bsalomon637e57e2014-08-18 11:49:37 -0700399 // The shader generated for coverage drawing runs the full coverage computation and then
400 // makes the shader output be the multiplication of color and coverage. We mirror that here.
401 GrColor coverage;
402 uint32_t coverageComponentFlags;
403 if (this->hasCoverageVertexAttribute()) {
404 coverageComponentFlags = 0;
405 coverage = 0; // suppresses any warnings.
406 } else {
407 coverageComponentFlags = kRGBA_GrColorComponentFlags;
408 coverage = this->getCoverageColor();
jvanverth@google.comcc782382013-01-28 20:39:48 +0000409 }
bsalomon637e57e2014-08-18 11:49:37 -0700410
411 // Run through the coverage stages
egdaniel776bdbd2014-08-06 11:07:02 -0700412 for (int s = 0; s < this->numCoverageStages(); ++s) {
413 const GrEffect* effect = this->getCoverageStage(s).getEffect();
bsalomon637e57e2014-08-18 11:49:37 -0700414 effect->getConstantColorComponents(&coverage, &coverageComponentFlags);
jvanverth@google.comcc782382013-01-28 20:39:48 +0000415 }
bsalomon637e57e2014-08-18 11:49:37 -0700416
417 // Since the shader will multiply coverage and color, the only way the final A==1 is if
418 // coverage and color both have A==1.
419 return (kA_GrColorComponentFlag & validComponentFlags & coverageComponentFlags) &&
420 0xFF == GrColorUnpackA(color) && 0xFF == GrColorUnpackA(coverage);
421
jvanverth@google.comcc782382013-01-28 20:39:48 +0000422 }
bsalomon637e57e2014-08-18 11:49:37 -0700423
424 return (kA_GrColorComponentFlag & validComponentFlags) && 0xFF == GrColorUnpackA(color);
jvanverth@google.comcc782382013-01-28 20:39:48 +0000425}
426
jvanverth@google.com054ae992013-04-01 20:06:51 +0000427bool GrDrawState::hasSolidCoverage() const {
bsalomon@google.comd62e88e2013-02-01 14:19:27 +0000428 // If we're drawing coverage directly then coverage is effectively treated as color.
429 if (this->isCoverageDrawing()) {
430 return true;
431 }
432
433 GrColor coverage;
434 uint32_t validComponentFlags;
435 // Initialize to an unknown starting coverage if per-vertex coverage is specified.
jvanverth@google.com054ae992013-04-01 20:06:51 +0000436 if (this->hasCoverageVertexAttribute()) {
bsalomon@google.comd62e88e2013-02-01 14:19:27 +0000437 validComponentFlags = 0;
438 } else {
bsalomon2ed5ef82014-07-07 08:44:05 -0700439 coverage = fCoverage;
bsalomon@google.comb8eb2e82013-03-28 13:46:42 +0000440 validComponentFlags = kRGBA_GrColorComponentFlags;
bsalomon@google.comd62e88e2013-02-01 14:19:27 +0000441 }
442
443 // Run through the coverage stages and see if the coverage will be all ones at the end.
egdaniel776bdbd2014-08-06 11:07:02 -0700444 for (int s = 0; s < this->numCoverageStages(); ++s) {
445 const GrEffect* effect = this->getCoverageStage(s).getEffect();
bsalomonf99f8842014-07-07 11:54:23 -0700446 effect->getConstantColorComponents(&coverage, &validComponentFlags);
bsalomon@google.comd62e88e2013-02-01 14:19:27 +0000447 }
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000448 return (kRGBA_GrColorComponentFlags == validComponentFlags) && (0xffffffff == coverage);
bsalomon@google.comd62e88e2013-02-01 14:19:27 +0000449}
450
jvanverth@google.comcc782382013-01-28 20:39:48 +0000451////////////////////////////////////////////////////////////////////////////////
452
bsalomon@google.com2b446732013-02-12 16:47:41 +0000453// Some blend modes allow folding a fractional coverage value into the color's alpha channel, while
454// others will blend incorrectly.
455bool GrDrawState::canTweakAlphaForCoverage() const {
456 /*
457 The fractional coverage is f.
458 The src and dst coeffs are Cs and Cd.
459 The dst and src colors are S and D.
460 We want the blend to compute: f*Cs*S + (f*Cd + (1-f))D. By tweaking the source color's alpha
461 we're replacing S with S'=fS. It's obvious that that first term will always be ok. The second
462 term can be rearranged as [1-(1-Cd)f]D. By substituting in the various possibilities for Cd we
463 find that only 1, ISA, and ISC produce the correct destination when applied to S' and D.
464 Also, if we're directly rendering coverage (isCoverageDrawing) then coverage is treated as
465 color by definition.
466 */
egdaniel776bdbd2014-08-06 11:07:02 -0700467 return kOne_GrBlendCoeff == fState.fDstBlend ||
468 kISA_GrBlendCoeff == fState.fDstBlend ||
469 kISC_GrBlendCoeff == fState.fDstBlend ||
bsalomon@google.com2b446732013-02-12 16:47:41 +0000470 this->isCoverageDrawing();
471}
472
473GrDrawState::BlendOptFlags GrDrawState::getBlendOpts(bool forceCoverage,
474 GrBlendCoeff* srcCoeff,
475 GrBlendCoeff* dstCoeff) const {
bsalomon@google.com2b446732013-02-12 16:47:41 +0000476 GrBlendCoeff bogusSrcCoeff, bogusDstCoeff;
477 if (NULL == srcCoeff) {
478 srcCoeff = &bogusSrcCoeff;
479 }
bsalomon@google.com2b446732013-02-12 16:47:41 +0000480 if (NULL == dstCoeff) {
481 dstCoeff = &bogusDstCoeff;
482 }
egdaniel9514d242014-07-18 06:15:43 -0700483
484 if (forceCoverage) {
485 return this->calcBlendOpts(true, srcCoeff, dstCoeff);
486 }
487
488 if (0 == (fBlendOptFlags & kInvalid_BlendOptFlag)) {
489 *srcCoeff = fOptSrcBlend;
490 *dstCoeff = fOptDstBlend;
491 return fBlendOptFlags;
492 }
493
494 fBlendOptFlags = this->calcBlendOpts(forceCoverage, srcCoeff, dstCoeff);
495 fOptSrcBlend = *srcCoeff;
496 fOptDstBlend = *dstCoeff;
497
498 return fBlendOptFlags;
499}
500
501GrDrawState::BlendOptFlags GrDrawState::calcBlendOpts(bool forceCoverage,
502 GrBlendCoeff* srcCoeff,
503 GrBlendCoeff* dstCoeff) const {
504 *srcCoeff = this->getSrcBlendCoeff();
bsalomon@google.com2b446732013-02-12 16:47:41 +0000505 *dstCoeff = this->getDstBlendCoeff();
506
507 if (this->isColorWriteDisabled()) {
508 *srcCoeff = kZero_GrBlendCoeff;
509 *dstCoeff = kOne_GrBlendCoeff;
510 }
511
jvanverth@google.com054ae992013-04-01 20:06:51 +0000512 bool srcAIsOne = this->srcAlphaWillBeOne();
bsalomon@google.com2b446732013-02-12 16:47:41 +0000513 bool dstCoeffIsOne = kOne_GrBlendCoeff == *dstCoeff ||
514 (kSA_GrBlendCoeff == *dstCoeff && srcAIsOne);
515 bool dstCoeffIsZero = kZero_GrBlendCoeff == *dstCoeff ||
516 (kISA_GrBlendCoeff == *dstCoeff && srcAIsOne);
517
bsalomon@google.com2b446732013-02-12 16:47:41 +0000518 // When coeffs are (0,1) there is no reason to draw at all, unless
519 // stenciling is enabled. Having color writes disabled is effectively
bsalomon62c447d2014-08-08 08:08:50 -0700520 // (0,1).
521 if ((kZero_GrBlendCoeff == *srcCoeff && dstCoeffIsOne)) {
bsalomon@google.com2b446732013-02-12 16:47:41 +0000522 if (this->getStencil().doesWrite()) {
egdaniel0f1a7c42014-07-30 13:18:32 -0700523 return kEmitCoverage_BlendOptFlag;
bsalomon@google.com2b446732013-02-12 16:47:41 +0000524 } else {
525 return kSkipDraw_BlendOptFlag;
526 }
527 }
528
bsalomon62c447d2014-08-08 08:08:50 -0700529 bool hasCoverage = forceCoverage || !this->hasSolidCoverage();
bsalomon@google.com2b446732013-02-12 16:47:41 +0000530
531 // if we don't have coverage we can check whether the dst
532 // has to read at all. If not, we'll disable blending.
533 if (!hasCoverage) {
534 if (dstCoeffIsZero) {
535 if (kOne_GrBlendCoeff == *srcCoeff) {
536 // if there is no coverage and coeffs are (1,0) then we
537 // won't need to read the dst at all, it gets replaced by src
egdaniel0f1a7c42014-07-30 13:18:32 -0700538 *dstCoeff = kZero_GrBlendCoeff;
539 return kNone_BlendOpt;
bsalomon@google.com2b446732013-02-12 16:47:41 +0000540 } else if (kZero_GrBlendCoeff == *srcCoeff) {
541 // if the op is "clear" then we don't need to emit a color
542 // or blend, just write transparent black into the dst.
543 *srcCoeff = kOne_GrBlendCoeff;
544 *dstCoeff = kZero_GrBlendCoeff;
egdaniel0f1a7c42014-07-30 13:18:32 -0700545 return kEmitTransBlack_BlendOptFlag;
bsalomon@google.com2b446732013-02-12 16:47:41 +0000546 }
547 }
548 } else if (this->isCoverageDrawing()) {
549 // we have coverage but we aren't distinguishing it from alpha by request.
550 return kCoverageAsAlpha_BlendOptFlag;
551 } else {
552 // check whether coverage can be safely rolled into alpha
553 // of if we can skip color computation and just emit coverage
554 if (this->canTweakAlphaForCoverage()) {
555 return kCoverageAsAlpha_BlendOptFlag;
556 }
557 if (dstCoeffIsZero) {
558 if (kZero_GrBlendCoeff == *srcCoeff) {
559 // the source color is not included in the blend
560 // the dst coeff is effectively zero so blend works out to:
561 // (c)(0)D + (1-c)D = (1-c)D.
562 *dstCoeff = kISA_GrBlendCoeff;
563 return kEmitCoverage_BlendOptFlag;
564 } else if (srcAIsOne) {
565 // the dst coeff is effectively zero so blend works out to:
566 // cS + (c)(0)D + (1-c)D = cS + (1-c)D.
567 // If Sa is 1 then we can replace Sa with c
568 // and set dst coeff to 1-Sa.
569 *dstCoeff = kISA_GrBlendCoeff;
570 return kCoverageAsAlpha_BlendOptFlag;
571 }
572 } else if (dstCoeffIsOne) {
573 // the dst coeff is effectively one so blend works out to:
574 // cS + (c)(1)D + (1-c)D = cS + D.
575 *dstCoeff = kOne_GrBlendCoeff;
576 return kCoverageAsAlpha_BlendOptFlag;
577 }
578 }
egdaniel0f1a7c42014-07-30 13:18:32 -0700579
bsalomon@google.com2b446732013-02-12 16:47:41 +0000580 return kNone_BlendOpt;
581}
582
egdaniel02cafcc2014-07-21 11:37:28 -0700583bool GrDrawState::canIgnoreColorAttribute() const {
584 if (fBlendOptFlags & kInvalid_BlendOptFlag) {
585 this->getBlendOpts();
586 }
587 return SkToBool(fBlendOptFlags & (GrDrawState::kEmitTransBlack_BlendOptFlag |
588 GrDrawState::kEmitCoverage_BlendOptFlag));
589}
590
bsalomon8f727332014-08-05 07:50:06 -0700591//////////////////////////////////////////////////////////////////////////////
592
593GrDrawState::AutoVertexAttribRestore::AutoVertexAttribRestore(
594 GrDrawState* drawState) {
595 SkASSERT(NULL != drawState);
596 fDrawState = drawState;
597 fVAPtr = drawState->fVAPtr;
598 fVACount = drawState->fVACount;
599 fDrawState->setDefaultVertexAttribs();
600}
601
602//////////////////////////////////////////////////////////////////////////////s
603
604void GrDrawState::AutoRestoreEffects::set(GrDrawState* ds) {
605 if (NULL != fDrawState) {
egdaniel776bdbd2014-08-06 11:07:02 -0700606 int m = fDrawState->numColorStages() - fColorEffectCnt;
bsalomon8f727332014-08-05 07:50:06 -0700607 SkASSERT(m >= 0);
egdaniel776bdbd2014-08-06 11:07:02 -0700608 fDrawState->fState.fColorStages.pop_back_n(m);
bsalomon8f727332014-08-05 07:50:06 -0700609
egdaniel776bdbd2014-08-06 11:07:02 -0700610 int n = fDrawState->numCoverageStages() - fCoverageEffectCnt;
bsalomon8f727332014-08-05 07:50:06 -0700611 SkASSERT(n >= 0);
egdaniel776bdbd2014-08-06 11:07:02 -0700612 fDrawState->fState.fCoverageStages.pop_back_n(n);
bsalomon8f727332014-08-05 07:50:06 -0700613 if (m + n > 0) {
614 fDrawState->invalidateBlendOptFlags();
615 }
616 SkDEBUGCODE(--fDrawState->fBlockEffectRemovalCnt;)
617 }
618 fDrawState = ds;
619 if (NULL != ds) {
egdaniel776bdbd2014-08-06 11:07:02 -0700620 fColorEffectCnt = ds->numColorStages();
621 fCoverageEffectCnt = ds->numCoverageStages();
bsalomon8f727332014-08-05 07:50:06 -0700622 SkDEBUGCODE(++ds->fBlockEffectRemovalCnt;)
623 }
624}
egdaniel02cafcc2014-07-21 11:37:28 -0700625
bsalomon@google.com2b446732013-02-12 16:47:41 +0000626////////////////////////////////////////////////////////////////////////////////
627
bsalomon@google.com2fdcdeb2012-10-08 17:15:55 +0000628void GrDrawState::AutoViewMatrixRestore::restore() {
629 if (NULL != fDrawState) {
commit-bot@chromium.org1acc3d72013-09-06 23:13:05 +0000630 SkDEBUGCODE(--fDrawState->fBlockEffectRemovalCnt;)
bsalomon2ed5ef82014-07-07 08:44:05 -0700631 fDrawState->fViewMatrix = fViewMatrix;
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000632 SkASSERT(fDrawState->numColorStages() >= fNumColorStages);
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000633 int numCoverageStages = fSavedCoordChanges.count() - fNumColorStages;
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000634 SkASSERT(fDrawState->numCoverageStages() >= numCoverageStages);
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000635
636 int i = 0;
637 for (int s = 0; s < fNumColorStages; ++s, ++i) {
egdaniel776bdbd2014-08-06 11:07:02 -0700638 fDrawState->fState.fColorStages[s].restoreCoordChange(fSavedCoordChanges[i]);
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000639 }
640 for (int s = 0; s < numCoverageStages; ++s, ++i) {
egdaniel776bdbd2014-08-06 11:07:02 -0700641 fDrawState->fState.fCoverageStages[s].restoreCoordChange(fSavedCoordChanges[i]);
bsalomon@google.com2fdcdeb2012-10-08 17:15:55 +0000642 }
bsalomon@google.com137f1342013-05-29 21:27:53 +0000643 fDrawState = NULL;
bsalomon@google.com2fdcdeb2012-10-08 17:15:55 +0000644 }
bsalomon@google.com2fdcdeb2012-10-08 17:15:55 +0000645}
646
647void GrDrawState::AutoViewMatrixRestore::set(GrDrawState* drawState,
bsalomon@google.comc7818882013-03-20 19:19:53 +0000648 const SkMatrix& preconcatMatrix) {
bsalomon@google.com2fdcdeb2012-10-08 17:15:55 +0000649 this->restore();
bsalomon@google.com5b3e8902012-10-05 20:13:28 +0000650
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000651 SkASSERT(NULL == fDrawState);
bsalomon@google.com137f1342013-05-29 21:27:53 +0000652 if (NULL == drawState || preconcatMatrix.isIdentity()) {
bsalomon@google.com2fdcdeb2012-10-08 17:15:55 +0000653 return;
654 }
bsalomon@google.com137f1342013-05-29 21:27:53 +0000655 fDrawState = drawState;
bsalomon@google.com2fdcdeb2012-10-08 17:15:55 +0000656
bsalomon@google.com2fdcdeb2012-10-08 17:15:55 +0000657 fViewMatrix = drawState->getViewMatrix();
bsalomon2ed5ef82014-07-07 08:44:05 -0700658 drawState->fViewMatrix.preConcat(preconcatMatrix);
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000659
660 this->doEffectCoordChanges(preconcatMatrix);
commit-bot@chromium.org1acc3d72013-09-06 23:13:05 +0000661 SkDEBUGCODE(++fDrawState->fBlockEffectRemovalCnt;)
bsalomon@google.com2fdcdeb2012-10-08 17:15:55 +0000662}
663
bsalomon@google.com137f1342013-05-29 21:27:53 +0000664bool GrDrawState::AutoViewMatrixRestore::setIdentity(GrDrawState* drawState) {
bsalomon@google.com2fdcdeb2012-10-08 17:15:55 +0000665 this->restore();
666
bsalomon@google.com137f1342013-05-29 21:27:53 +0000667 if (NULL == drawState) {
bsalomon@google.com2fdcdeb2012-10-08 17:15:55 +0000668 return false;
skia.committer@gmail.comf467ce72012-10-09 02:01:37 +0000669 }
bsalomon@google.com2fdcdeb2012-10-08 17:15:55 +0000670
bsalomon@google.com137f1342013-05-29 21:27:53 +0000671 if (drawState->getViewMatrix().isIdentity()) {
672 return true;
673 }
674
bsalomon@google.com5b3e8902012-10-05 20:13:28 +0000675 fViewMatrix = drawState->getViewMatrix();
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000676 if (0 == drawState->numTotalStages()) {
bsalomon2ed5ef82014-07-07 08:44:05 -0700677 drawState->fViewMatrix.reset();
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000678 fDrawState = drawState;
679 fNumColorStages = 0;
680 fSavedCoordChanges.reset(0);
commit-bot@chromium.org1acc3d72013-09-06 23:13:05 +0000681 SkDEBUGCODE(++fDrawState->fBlockEffectRemovalCnt;)
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000682 return true;
683 } else {
684 SkMatrix inv;
685 if (!fViewMatrix.invert(&inv)) {
686 return false;
bsalomon@google.com5b3e8902012-10-05 20:13:28 +0000687 }
bsalomon2ed5ef82014-07-07 08:44:05 -0700688 drawState->fViewMatrix.reset();
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000689 fDrawState = drawState;
690 this->doEffectCoordChanges(inv);
commit-bot@chromium.org1acc3d72013-09-06 23:13:05 +0000691 SkDEBUGCODE(++fDrawState->fBlockEffectRemovalCnt;)
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000692 return true;
bsalomon@google.com5b3e8902012-10-05 20:13:28 +0000693 }
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000694}
695
696void GrDrawState::AutoViewMatrixRestore::doEffectCoordChanges(const SkMatrix& coordChangeMatrix) {
697 fSavedCoordChanges.reset(fDrawState->numTotalStages());
698 int i = 0;
699
700 fNumColorStages = fDrawState->numColorStages();
701 for (int s = 0; s < fNumColorStages; ++s, ++i) {
egdaniel776bdbd2014-08-06 11:07:02 -0700702 fDrawState->getColorStage(s).saveCoordChange(&fSavedCoordChanges[i]);
703 fDrawState->fState.fColorStages[s].localCoordChange(coordChangeMatrix);
bsalomon@google.com137f1342013-05-29 21:27:53 +0000704 }
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000705
706 int numCoverageStages = fDrawState->numCoverageStages();
707 for (int s = 0; s < numCoverageStages; ++s, ++i) {
egdaniel776bdbd2014-08-06 11:07:02 -0700708 fDrawState->getCoverageStage(s).saveCoordChange(&fSavedCoordChanges[i]);
709 fDrawState->fState.fCoverageStages[s].localCoordChange(coordChangeMatrix);
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000710 }
bsalomon@google.com5b3e8902012-10-05 20:13:28 +0000711}