blob: d54d085d0ed24b74566e8e081e74d77a3b90ddb1 [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()) {
commit-bot@chromium.orge0a868c2013-11-22 07:02:11 +0000399 GrColor coverageColor = this->getCoverageColor();
jvanverth@google.comcc782382013-01-28 20:39:48 +0000400 GrColor oldColor = color;
401 color = 0;
402 for (int c = 0; c < 4; ++c) {
403 if (validComponentFlags & (1 << c)) {
404 U8CPU a = (oldColor >> (c * 8)) & 0xff;
405 U8CPU b = (coverageColor >> (c * 8)) & 0xff;
406 color |= (SkMulDiv255Round(a, b) << (c * 8));
407 }
408 }
egdaniel776bdbd2014-08-06 11:07:02 -0700409 for (int s = 0; s < this->numCoverageStages(); ++s) {
410 const GrEffect* effect = this->getCoverageStage(s).getEffect();
bsalomonf99f8842014-07-07 11:54:23 -0700411 effect->getConstantColorComponents(&color, &validComponentFlags);
jvanverth@google.comcc782382013-01-28 20:39:48 +0000412 }
413 }
bsalomon@google.comb8eb2e82013-03-28 13:46:42 +0000414 return (kA_GrColorComponentFlag & validComponentFlags) && 0xff == GrColorUnpackA(color);
jvanverth@google.comcc782382013-01-28 20:39:48 +0000415}
416
jvanverth@google.com054ae992013-04-01 20:06:51 +0000417bool GrDrawState::hasSolidCoverage() const {
bsalomon@google.comd62e88e2013-02-01 14:19:27 +0000418 // If we're drawing coverage directly then coverage is effectively treated as color.
419 if (this->isCoverageDrawing()) {
420 return true;
421 }
422
423 GrColor coverage;
424 uint32_t validComponentFlags;
425 // Initialize to an unknown starting coverage if per-vertex coverage is specified.
jvanverth@google.com054ae992013-04-01 20:06:51 +0000426 if (this->hasCoverageVertexAttribute()) {
bsalomon@google.comd62e88e2013-02-01 14:19:27 +0000427 validComponentFlags = 0;
428 } else {
bsalomon2ed5ef82014-07-07 08:44:05 -0700429 coverage = fCoverage;
bsalomon@google.comb8eb2e82013-03-28 13:46:42 +0000430 validComponentFlags = kRGBA_GrColorComponentFlags;
bsalomon@google.comd62e88e2013-02-01 14:19:27 +0000431 }
432
433 // Run through the coverage stages and see if the coverage will be all ones at the end.
egdaniel776bdbd2014-08-06 11:07:02 -0700434 for (int s = 0; s < this->numCoverageStages(); ++s) {
435 const GrEffect* effect = this->getCoverageStage(s).getEffect();
bsalomonf99f8842014-07-07 11:54:23 -0700436 effect->getConstantColorComponents(&coverage, &validComponentFlags);
bsalomon@google.comd62e88e2013-02-01 14:19:27 +0000437 }
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000438 return (kRGBA_GrColorComponentFlags == validComponentFlags) && (0xffffffff == coverage);
bsalomon@google.comd62e88e2013-02-01 14:19:27 +0000439}
440
jvanverth@google.comcc782382013-01-28 20:39:48 +0000441////////////////////////////////////////////////////////////////////////////////
442
bsalomon@google.com2b446732013-02-12 16:47:41 +0000443// Some blend modes allow folding a fractional coverage value into the color's alpha channel, while
444// others will blend incorrectly.
445bool GrDrawState::canTweakAlphaForCoverage() const {
446 /*
447 The fractional coverage is f.
448 The src and dst coeffs are Cs and Cd.
449 The dst and src colors are S and D.
450 We want the blend to compute: f*Cs*S + (f*Cd + (1-f))D. By tweaking the source color's alpha
451 we're replacing S with S'=fS. It's obvious that that first term will always be ok. The second
452 term can be rearranged as [1-(1-Cd)f]D. By substituting in the various possibilities for Cd we
453 find that only 1, ISA, and ISC produce the correct destination when applied to S' and D.
454 Also, if we're directly rendering coverage (isCoverageDrawing) then coverage is treated as
455 color by definition.
456 */
egdaniel776bdbd2014-08-06 11:07:02 -0700457 return kOne_GrBlendCoeff == fState.fDstBlend ||
458 kISA_GrBlendCoeff == fState.fDstBlend ||
459 kISC_GrBlendCoeff == fState.fDstBlend ||
bsalomon@google.com2b446732013-02-12 16:47:41 +0000460 this->isCoverageDrawing();
461}
462
463GrDrawState::BlendOptFlags GrDrawState::getBlendOpts(bool forceCoverage,
464 GrBlendCoeff* srcCoeff,
465 GrBlendCoeff* dstCoeff) const {
bsalomon@google.com2b446732013-02-12 16:47:41 +0000466 GrBlendCoeff bogusSrcCoeff, bogusDstCoeff;
467 if (NULL == srcCoeff) {
468 srcCoeff = &bogusSrcCoeff;
469 }
bsalomon@google.com2b446732013-02-12 16:47:41 +0000470 if (NULL == dstCoeff) {
471 dstCoeff = &bogusDstCoeff;
472 }
egdaniel9514d242014-07-18 06:15:43 -0700473
474 if (forceCoverage) {
475 return this->calcBlendOpts(true, srcCoeff, dstCoeff);
476 }
477
478 if (0 == (fBlendOptFlags & kInvalid_BlendOptFlag)) {
479 *srcCoeff = fOptSrcBlend;
480 *dstCoeff = fOptDstBlend;
481 return fBlendOptFlags;
482 }
483
484 fBlendOptFlags = this->calcBlendOpts(forceCoverage, srcCoeff, dstCoeff);
485 fOptSrcBlend = *srcCoeff;
486 fOptDstBlend = *dstCoeff;
487
488 return fBlendOptFlags;
489}
490
491GrDrawState::BlendOptFlags GrDrawState::calcBlendOpts(bool forceCoverage,
492 GrBlendCoeff* srcCoeff,
493 GrBlendCoeff* dstCoeff) const {
494 *srcCoeff = this->getSrcBlendCoeff();
bsalomon@google.com2b446732013-02-12 16:47:41 +0000495 *dstCoeff = this->getDstBlendCoeff();
496
497 if (this->isColorWriteDisabled()) {
498 *srcCoeff = kZero_GrBlendCoeff;
499 *dstCoeff = kOne_GrBlendCoeff;
500 }
501
jvanverth@google.com054ae992013-04-01 20:06:51 +0000502 bool srcAIsOne = this->srcAlphaWillBeOne();
bsalomon@google.com2b446732013-02-12 16:47:41 +0000503 bool dstCoeffIsOne = kOne_GrBlendCoeff == *dstCoeff ||
504 (kSA_GrBlendCoeff == *dstCoeff && srcAIsOne);
505 bool dstCoeffIsZero = kZero_GrBlendCoeff == *dstCoeff ||
506 (kISA_GrBlendCoeff == *dstCoeff && srcAIsOne);
507
bsalomon@google.com2b446732013-02-12 16:47:41 +0000508 // When coeffs are (0,1) there is no reason to draw at all, unless
509 // stenciling is enabled. Having color writes disabled is effectively
bsalomon62c447d2014-08-08 08:08:50 -0700510 // (0,1).
511 if ((kZero_GrBlendCoeff == *srcCoeff && dstCoeffIsOne)) {
bsalomon@google.com2b446732013-02-12 16:47:41 +0000512 if (this->getStencil().doesWrite()) {
egdaniel0f1a7c42014-07-30 13:18:32 -0700513 return kEmitCoverage_BlendOptFlag;
bsalomon@google.com2b446732013-02-12 16:47:41 +0000514 } else {
515 return kSkipDraw_BlendOptFlag;
516 }
517 }
518
bsalomon62c447d2014-08-08 08:08:50 -0700519 bool hasCoverage = forceCoverage || !this->hasSolidCoverage();
bsalomon@google.com2b446732013-02-12 16:47:41 +0000520
521 // if we don't have coverage we can check whether the dst
522 // has to read at all. If not, we'll disable blending.
523 if (!hasCoverage) {
524 if (dstCoeffIsZero) {
525 if (kOne_GrBlendCoeff == *srcCoeff) {
526 // if there is no coverage and coeffs are (1,0) then we
527 // won't need to read the dst at all, it gets replaced by src
egdaniel0f1a7c42014-07-30 13:18:32 -0700528 *dstCoeff = kZero_GrBlendCoeff;
529 return kNone_BlendOpt;
bsalomon@google.com2b446732013-02-12 16:47:41 +0000530 } else if (kZero_GrBlendCoeff == *srcCoeff) {
531 // if the op is "clear" then we don't need to emit a color
532 // or blend, just write transparent black into the dst.
533 *srcCoeff = kOne_GrBlendCoeff;
534 *dstCoeff = kZero_GrBlendCoeff;
egdaniel0f1a7c42014-07-30 13:18:32 -0700535 return kEmitTransBlack_BlendOptFlag;
bsalomon@google.com2b446732013-02-12 16:47:41 +0000536 }
537 }
538 } else if (this->isCoverageDrawing()) {
539 // we have coverage but we aren't distinguishing it from alpha by request.
540 return kCoverageAsAlpha_BlendOptFlag;
541 } else {
542 // check whether coverage can be safely rolled into alpha
543 // of if we can skip color computation and just emit coverage
544 if (this->canTweakAlphaForCoverage()) {
545 return kCoverageAsAlpha_BlendOptFlag;
546 }
547 if (dstCoeffIsZero) {
548 if (kZero_GrBlendCoeff == *srcCoeff) {
549 // the source color is not included in the blend
550 // the dst coeff is effectively zero so blend works out to:
551 // (c)(0)D + (1-c)D = (1-c)D.
552 *dstCoeff = kISA_GrBlendCoeff;
553 return kEmitCoverage_BlendOptFlag;
554 } else if (srcAIsOne) {
555 // the dst coeff is effectively zero so blend works out to:
556 // cS + (c)(0)D + (1-c)D = cS + (1-c)D.
557 // If Sa is 1 then we can replace Sa with c
558 // and set dst coeff to 1-Sa.
559 *dstCoeff = kISA_GrBlendCoeff;
560 return kCoverageAsAlpha_BlendOptFlag;
561 }
562 } else if (dstCoeffIsOne) {
563 // the dst coeff is effectively one so blend works out to:
564 // cS + (c)(1)D + (1-c)D = cS + D.
565 *dstCoeff = kOne_GrBlendCoeff;
566 return kCoverageAsAlpha_BlendOptFlag;
567 }
568 }
egdaniel0f1a7c42014-07-30 13:18:32 -0700569
bsalomon@google.com2b446732013-02-12 16:47:41 +0000570 return kNone_BlendOpt;
571}
572
egdaniel02cafcc2014-07-21 11:37:28 -0700573bool GrDrawState::canIgnoreColorAttribute() const {
574 if (fBlendOptFlags & kInvalid_BlendOptFlag) {
575 this->getBlendOpts();
576 }
577 return SkToBool(fBlendOptFlags & (GrDrawState::kEmitTransBlack_BlendOptFlag |
578 GrDrawState::kEmitCoverage_BlendOptFlag));
579}
580
bsalomon8f727332014-08-05 07:50:06 -0700581//////////////////////////////////////////////////////////////////////////////
582
583GrDrawState::AutoVertexAttribRestore::AutoVertexAttribRestore(
584 GrDrawState* drawState) {
585 SkASSERT(NULL != drawState);
586 fDrawState = drawState;
587 fVAPtr = drawState->fVAPtr;
588 fVACount = drawState->fVACount;
589 fDrawState->setDefaultVertexAttribs();
590}
591
592//////////////////////////////////////////////////////////////////////////////s
593
594void GrDrawState::AutoRestoreEffects::set(GrDrawState* ds) {
595 if (NULL != fDrawState) {
egdaniel776bdbd2014-08-06 11:07:02 -0700596 int m = fDrawState->numColorStages() - fColorEffectCnt;
bsalomon8f727332014-08-05 07:50:06 -0700597 SkASSERT(m >= 0);
egdaniel776bdbd2014-08-06 11:07:02 -0700598 fDrawState->fState.fColorStages.pop_back_n(m);
bsalomon8f727332014-08-05 07:50:06 -0700599
egdaniel776bdbd2014-08-06 11:07:02 -0700600 int n = fDrawState->numCoverageStages() - fCoverageEffectCnt;
bsalomon8f727332014-08-05 07:50:06 -0700601 SkASSERT(n >= 0);
egdaniel776bdbd2014-08-06 11:07:02 -0700602 fDrawState->fState.fCoverageStages.pop_back_n(n);
bsalomon8f727332014-08-05 07:50:06 -0700603 if (m + n > 0) {
604 fDrawState->invalidateBlendOptFlags();
605 }
606 SkDEBUGCODE(--fDrawState->fBlockEffectRemovalCnt;)
607 }
608 fDrawState = ds;
609 if (NULL != ds) {
egdaniel776bdbd2014-08-06 11:07:02 -0700610 fColorEffectCnt = ds->numColorStages();
611 fCoverageEffectCnt = ds->numCoverageStages();
bsalomon8f727332014-08-05 07:50:06 -0700612 SkDEBUGCODE(++ds->fBlockEffectRemovalCnt;)
613 }
614}
egdaniel02cafcc2014-07-21 11:37:28 -0700615
bsalomon@google.com2b446732013-02-12 16:47:41 +0000616////////////////////////////////////////////////////////////////////////////////
617
bsalomon@google.com2fdcdeb2012-10-08 17:15:55 +0000618void GrDrawState::AutoViewMatrixRestore::restore() {
619 if (NULL != fDrawState) {
commit-bot@chromium.org1acc3d72013-09-06 23:13:05 +0000620 SkDEBUGCODE(--fDrawState->fBlockEffectRemovalCnt;)
bsalomon2ed5ef82014-07-07 08:44:05 -0700621 fDrawState->fViewMatrix = fViewMatrix;
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000622 SkASSERT(fDrawState->numColorStages() >= fNumColorStages);
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000623 int numCoverageStages = fSavedCoordChanges.count() - fNumColorStages;
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000624 SkASSERT(fDrawState->numCoverageStages() >= numCoverageStages);
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000625
626 int i = 0;
627 for (int s = 0; s < fNumColorStages; ++s, ++i) {
egdaniel776bdbd2014-08-06 11:07:02 -0700628 fDrawState->fState.fColorStages[s].restoreCoordChange(fSavedCoordChanges[i]);
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000629 }
630 for (int s = 0; s < numCoverageStages; ++s, ++i) {
egdaniel776bdbd2014-08-06 11:07:02 -0700631 fDrawState->fState.fCoverageStages[s].restoreCoordChange(fSavedCoordChanges[i]);
bsalomon@google.com2fdcdeb2012-10-08 17:15:55 +0000632 }
bsalomon@google.com137f1342013-05-29 21:27:53 +0000633 fDrawState = NULL;
bsalomon@google.com2fdcdeb2012-10-08 17:15:55 +0000634 }
bsalomon@google.com2fdcdeb2012-10-08 17:15:55 +0000635}
636
637void GrDrawState::AutoViewMatrixRestore::set(GrDrawState* drawState,
bsalomon@google.comc7818882013-03-20 19:19:53 +0000638 const SkMatrix& preconcatMatrix) {
bsalomon@google.com2fdcdeb2012-10-08 17:15:55 +0000639 this->restore();
bsalomon@google.com5b3e8902012-10-05 20:13:28 +0000640
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000641 SkASSERT(NULL == fDrawState);
bsalomon@google.com137f1342013-05-29 21:27:53 +0000642 if (NULL == drawState || preconcatMatrix.isIdentity()) {
bsalomon@google.com2fdcdeb2012-10-08 17:15:55 +0000643 return;
644 }
bsalomon@google.com137f1342013-05-29 21:27:53 +0000645 fDrawState = drawState;
bsalomon@google.com2fdcdeb2012-10-08 17:15:55 +0000646
bsalomon@google.com2fdcdeb2012-10-08 17:15:55 +0000647 fViewMatrix = drawState->getViewMatrix();
bsalomon2ed5ef82014-07-07 08:44:05 -0700648 drawState->fViewMatrix.preConcat(preconcatMatrix);
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000649
650 this->doEffectCoordChanges(preconcatMatrix);
commit-bot@chromium.org1acc3d72013-09-06 23:13:05 +0000651 SkDEBUGCODE(++fDrawState->fBlockEffectRemovalCnt;)
bsalomon@google.com2fdcdeb2012-10-08 17:15:55 +0000652}
653
bsalomon@google.com137f1342013-05-29 21:27:53 +0000654bool GrDrawState::AutoViewMatrixRestore::setIdentity(GrDrawState* drawState) {
bsalomon@google.com2fdcdeb2012-10-08 17:15:55 +0000655 this->restore();
656
bsalomon@google.com137f1342013-05-29 21:27:53 +0000657 if (NULL == drawState) {
bsalomon@google.com2fdcdeb2012-10-08 17:15:55 +0000658 return false;
skia.committer@gmail.comf467ce72012-10-09 02:01:37 +0000659 }
bsalomon@google.com2fdcdeb2012-10-08 17:15:55 +0000660
bsalomon@google.com137f1342013-05-29 21:27:53 +0000661 if (drawState->getViewMatrix().isIdentity()) {
662 return true;
663 }
664
bsalomon@google.com5b3e8902012-10-05 20:13:28 +0000665 fViewMatrix = drawState->getViewMatrix();
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000666 if (0 == drawState->numTotalStages()) {
bsalomon2ed5ef82014-07-07 08:44:05 -0700667 drawState->fViewMatrix.reset();
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000668 fDrawState = drawState;
669 fNumColorStages = 0;
670 fSavedCoordChanges.reset(0);
commit-bot@chromium.org1acc3d72013-09-06 23:13:05 +0000671 SkDEBUGCODE(++fDrawState->fBlockEffectRemovalCnt;)
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000672 return true;
673 } else {
674 SkMatrix inv;
675 if (!fViewMatrix.invert(&inv)) {
676 return false;
bsalomon@google.com5b3e8902012-10-05 20:13:28 +0000677 }
bsalomon2ed5ef82014-07-07 08:44:05 -0700678 drawState->fViewMatrix.reset();
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000679 fDrawState = drawState;
680 this->doEffectCoordChanges(inv);
commit-bot@chromium.org1acc3d72013-09-06 23:13:05 +0000681 SkDEBUGCODE(++fDrawState->fBlockEffectRemovalCnt;)
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000682 return true;
bsalomon@google.com5b3e8902012-10-05 20:13:28 +0000683 }
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000684}
685
686void GrDrawState::AutoViewMatrixRestore::doEffectCoordChanges(const SkMatrix& coordChangeMatrix) {
687 fSavedCoordChanges.reset(fDrawState->numTotalStages());
688 int i = 0;
689
690 fNumColorStages = fDrawState->numColorStages();
691 for (int s = 0; s < fNumColorStages; ++s, ++i) {
egdaniel776bdbd2014-08-06 11:07:02 -0700692 fDrawState->getColorStage(s).saveCoordChange(&fSavedCoordChanges[i]);
693 fDrawState->fState.fColorStages[s].localCoordChange(coordChangeMatrix);
bsalomon@google.com137f1342013-05-29 21:27:53 +0000694 }
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000695
696 int numCoverageStages = fDrawState->numCoverageStages();
697 for (int s = 0; s < numCoverageStages; ++s, ++i) {
egdaniel776bdbd2014-08-06 11:07:02 -0700698 fDrawState->getCoverageStage(s).saveCoordChange(&fSavedCoordChanges[i]);
699 fDrawState->fState.fCoverageStages[s].localCoordChange(coordChangeMatrix);
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000700 }
bsalomon@google.com5b3e8902012-10-05 20:13:28 +0000701}