blob: ba5d62876c6936fdf5279e9dc2e5001e61090f68 [file] [log] [blame]
bsalomon@google.comaf84e742012-10-05 13:23:24 +00001/*
2 * Copyright 2012 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "GrDrawState.h"
bsalomon@google.comaf84e742012-10-05 13:23:24 +00009#include "GrPaint.h"
bsalomon62c447d2014-08-08 08:08:50 -070010#include "GrDrawTargetCaps.h"
bsalomon@google.comaf84e742012-10-05 13:23:24 +000011
bsalomon8f727332014-08-05 07:50:06 -070012//////////////////////////////////////////////////////////////////////////////s
13
14GrDrawState::CombinedState GrDrawState::CombineIfPossible(
bsalomon62c447d2014-08-08 08:08:50 -070015 const GrDrawState& a, const GrDrawState& b, const GrDrawTargetCaps& caps) {
bsalomon8f727332014-08-05 07:50:06 -070016
17 bool usingVertexColors = a.hasColorVertexAttribute();
18 if (!usingVertexColors && a.fColor != b.fColor) {
19 return kIncompatible_CombinedState;
20 }
21
22 if (a.fRenderTarget.get() != b.fRenderTarget.get() ||
egdaniel8cbf3d52014-08-21 06:27:22 -070023 a.fColorStages.count() != b.fColorStages.count() ||
24 a.fCoverageStages.count() != b.fCoverageStages.count() ||
bsalomon8f727332014-08-05 07:50:06 -070025 !a.fViewMatrix.cheapEqualTo(b.fViewMatrix) ||
egdaniel8cbf3d52014-08-21 06:27:22 -070026 a.fSrcBlend != b.fSrcBlend ||
27 a.fDstBlend != b.fDstBlend ||
bsalomon8f727332014-08-05 07:50:06 -070028 a.fBlendConstant != b.fBlendConstant ||
29 a.fFlagBits != b.fFlagBits ||
30 a.fVACount != b.fVACount ||
31 memcmp(a.fVAPtr, b.fVAPtr, a.fVACount * sizeof(GrVertexAttrib)) ||
32 a.fStencilSettings != b.fStencilSettings ||
33 a.fDrawFace != b.fDrawFace) {
34 return kIncompatible_CombinedState;
35 }
36
37 bool usingVertexCoverage = a.hasCoverageVertexAttribute();
38 if (!usingVertexCoverage && a.fCoverage != b.fCoverage) {
39 return kIncompatible_CombinedState;
40 }
41
42 bool explicitLocalCoords = a.hasLocalCoordAttribute();
egdaniel8cbf3d52014-08-21 06:27:22 -070043 for (int i = 0; i < a.numColorStages(); i++) {
44 if (!GrEffectStage::AreCompatible(a.getColorStage(i), b.getColorStage(i),
45 explicitLocalCoords)) {
46 return kIncompatible_CombinedState;
47 }
48 }
49 for (int i = 0; i < a.numCoverageStages(); i++) {
50 if (!GrEffectStage::AreCompatible(a.getCoverageStage(i), b.getCoverageStage(i),
51 explicitLocalCoords)) {
52 return kIncompatible_CombinedState;
53 }
54 }
egdaniel776bdbd2014-08-06 11:07:02 -070055
bsalomon8f727332014-08-05 07:50:06 -070056 SkASSERT(0 == memcmp(a.fFixedFunctionVertexAttribIndices,
57 b.fFixedFunctionVertexAttribIndices,
58 sizeof(a.fFixedFunctionVertexAttribIndices)));
bsalomon62c447d2014-08-08 08:08:50 -070059
60 if (usingVertexColors) {
61 // If one is opaque and the other is not then the combined state is not opaque. Moreover,
62 // if the opaqueness affects the ability to get color/coverage blending correct then we
63 // don't combine the draw states.
64 bool aIsOpaque = (kVertexColorsAreOpaque_Hint & a.fHints);
65 bool bIsOpaque = (kVertexColorsAreOpaque_Hint & b.fHints);
66 if (aIsOpaque != bIsOpaque) {
67 const GrDrawState* opaque;
68 const GrDrawState* nonOpaque;
69 if (aIsOpaque) {
70 opaque = &a;
71 nonOpaque = &b;
72 } else {
73 opaque = &b;
74 nonOpaque = &a;
75 }
76 if (!opaque->hasSolidCoverage() && opaque->couldApplyCoverage(caps)) {
77 SkASSERT(!nonOpaque->hasSolidCoverage());
78 if (!nonOpaque->couldApplyCoverage(caps)) {
79 return kIncompatible_CombinedState;
80 }
81 }
82 return aIsOpaque ? kB_CombinedState : kA_CombinedState;
83 }
84 }
bsalomon8f727332014-08-05 07:50:06 -070085 return kAOrB_CombinedState;
86}
87
bsalomon8f727332014-08-05 07:50:06 -070088//////////////////////////////////////////////////////////////////////////////s
89
90GrDrawState::GrDrawState(const GrDrawState& state, const SkMatrix& preConcatMatrix) {
91 SkDEBUGCODE(fBlockEffectRemovalCnt = 0;)
92 *this = state;
93 if (!preConcatMatrix.isIdentity()) {
egdaniel776bdbd2014-08-06 11:07:02 -070094 for (int i = 0; i < this->numColorStages(); ++i) {
egdaniel8cbf3d52014-08-21 06:27:22 -070095 fColorStages[i].localCoordChange(preConcatMatrix);
bsalomon8f727332014-08-05 07:50:06 -070096 }
egdaniel776bdbd2014-08-06 11:07:02 -070097 for (int i = 0; i < this->numCoverageStages(); ++i) {
egdaniel8cbf3d52014-08-21 06:27:22 -070098 fCoverageStages[i].localCoordChange(preConcatMatrix);
bsalomon8f727332014-08-05 07:50:06 -070099 }
100 this->invalidateBlendOptFlags();
101 }
102}
103
104GrDrawState& GrDrawState::operator=(const GrDrawState& that) {
105 SkASSERT(0 == fBlockEffectRemovalCnt || 0 == this->numTotalStages());
106 this->setRenderTarget(that.fRenderTarget.get());
107 fColor = that.fColor;
108 fViewMatrix = that.fViewMatrix;
egdaniel8cbf3d52014-08-21 06:27:22 -0700109 fSrcBlend = that.fSrcBlend;
110 fDstBlend = that.fDstBlend;
bsalomon8f727332014-08-05 07:50:06 -0700111 fBlendConstant = that.fBlendConstant;
112 fFlagBits = that.fFlagBits;
113 fVACount = that.fVACount;
114 fVAPtr = that.fVAPtr;
115 fStencilSettings = that.fStencilSettings;
116 fCoverage = that.fCoverage;
117 fDrawFace = that.fDrawFace;
egdaniel8cbf3d52014-08-21 06:27:22 -0700118 fColorStages = that.fColorStages;
119 fCoverageStages = that.fCoverageStages;
bsalomon8f727332014-08-05 07:50:06 -0700120 fOptSrcBlend = that.fOptSrcBlend;
121 fOptDstBlend = that.fOptDstBlend;
122 fBlendOptFlags = that.fBlendOptFlags;
123
bsalomon62c447d2014-08-08 08:08:50 -0700124 fHints = that.fHints;
egdaniel776bdbd2014-08-06 11:07:02 -0700125
bsalomon8f727332014-08-05 07:50:06 -0700126 memcpy(fFixedFunctionVertexAttribIndices,
127 that.fFixedFunctionVertexAttribIndices,
128 sizeof(fFixedFunctionVertexAttribIndices));
129 return *this;
130}
131
132void GrDrawState::onReset(const SkMatrix* initialViewMatrix) {
133 SkASSERT(0 == fBlockEffectRemovalCnt || 0 == this->numTotalStages());
egdaniel8cbf3d52014-08-21 06:27:22 -0700134 fColorStages.reset();
135 fCoverageStages.reset();
bsalomon8f727332014-08-05 07:50:06 -0700136
137 fRenderTarget.reset(NULL);
138
139 this->setDefaultVertexAttribs();
140
141 fColor = 0xffffffff;
142 if (NULL == initialViewMatrix) {
143 fViewMatrix.reset();
144 } else {
145 fViewMatrix = *initialViewMatrix;
146 }
egdaniel8cbf3d52014-08-21 06:27:22 -0700147 fSrcBlend = kOne_GrBlendCoeff;
148 fDstBlend = kZero_GrBlendCoeff;
bsalomon8f727332014-08-05 07:50:06 -0700149 fBlendConstant = 0x0;
150 fFlagBits = 0x0;
151 fStencilSettings.setDisabled();
egdaniel8cbf3d52014-08-21 06:27:22 -0700152 fCoverage = 0xff;
bsalomon8f727332014-08-05 07:50:06 -0700153 fDrawFace = kBoth_DrawFace;
154
bsalomon62c447d2014-08-08 08:08:50 -0700155 fHints = 0;
156
bsalomon8f727332014-08-05 07:50:06 -0700157 this->invalidateBlendOptFlags();
158}
159
bsalomon@google.com137f1342013-05-29 21:27:53 +0000160bool GrDrawState::setIdentityViewMatrix() {
egdaniel776bdbd2014-08-06 11:07:02 -0700161 if (this->numTotalStages()) {
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000162 SkMatrix invVM;
bsalomon2ed5ef82014-07-07 08:44:05 -0700163 if (!fViewMatrix.invert(&invVM)) {
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000164 // sad trombone sound
165 return false;
166 }
egdaniel776bdbd2014-08-06 11:07:02 -0700167 for (int s = 0; s < this->numColorStages(); ++s) {
egdaniel8cbf3d52014-08-21 06:27:22 -0700168 fColorStages[s].localCoordChange(invVM);
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000169 }
egdaniel776bdbd2014-08-06 11:07:02 -0700170 for (int s = 0; s < this->numCoverageStages(); ++s) {
egdaniel8cbf3d52014-08-21 06:27:22 -0700171 fCoverageStages[s].localCoordChange(invVM);
bsalomon@google.com137f1342013-05-29 21:27:53 +0000172 }
173 }
bsalomon2ed5ef82014-07-07 08:44:05 -0700174 fViewMatrix.reset();
bsalomon@google.com137f1342013-05-29 21:27:53 +0000175 return true;
176}
177
commit-bot@chromium.orgbb6a3172013-05-28 17:25:49 +0000178void GrDrawState::setFromPaint(const GrPaint& paint, const SkMatrix& vm, GrRenderTarget* rt) {
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000179 SkASSERT(0 == fBlockEffectRemovalCnt || 0 == this->numTotalStages());
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000180
egdaniel8cbf3d52014-08-21 06:27:22 -0700181 fColorStages.reset();
182 fCoverageStages.reset();
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000183
commit-bot@chromium.org42dacab2013-07-13 17:24:24 +0000184 for (int i = 0; i < paint.numColorStages(); ++i) {
egdaniel8cbf3d52014-08-21 06:27:22 -0700185 fColorStages.push_back(paint.getColorStage(i));
bsalomon@google.comaf84e742012-10-05 13:23:24 +0000186 }
187
commit-bot@chromium.org42dacab2013-07-13 17:24:24 +0000188 for (int i = 0; i < paint.numCoverageStages(); ++i) {
egdaniel8cbf3d52014-08-21 06:27:22 -0700189 fCoverageStages.push_back(paint.getCoverageStage(i));
bsalomon@google.comaf84e742012-10-05 13:23:24 +0000190 }
191
commit-bot@chromium.orgbb6a3172013-05-28 17:25:49 +0000192 this->setRenderTarget(rt);
bsalomon@google.comaf84e742012-10-05 13:23:24 +0000193
bsalomon2ed5ef82014-07-07 08:44:05 -0700194 fViewMatrix = vm;
commit-bot@chromium.orgbb6a3172013-05-28 17:25:49 +0000195
196 // These have no equivalent in GrPaint, set them to defaults
bsalomon2ed5ef82014-07-07 08:44:05 -0700197 fBlendConstant = 0x0;
198 fDrawFace = kBoth_DrawFace;
199 fStencilSettings.setDisabled();
commit-bot@chromium.orgbb6a3172013-05-28 17:25:49 +0000200 this->resetStateFlags();
bsalomon62c447d2014-08-08 08:08:50 -0700201 fHints = 0;
commit-bot@chromium.orgbb6a3172013-05-28 17:25:49 +0000202
bsalomon@google.com21c10c52013-06-13 17:44:07 +0000203 // Enable the clip bit
204 this->enableState(GrDrawState::kClip_StateBit);
205
commit-bot@chromium.orgbb6a3172013-05-28 17:25:49 +0000206 this->setColor(paint.getColor());
bsalomon@google.comc7448ce2012-10-05 19:04:13 +0000207 this->setState(GrDrawState::kDither_StateBit, paint.isDither());
208 this->setState(GrDrawState::kHWAntialias_StateBit, paint.isAntiAlias());
bsalomon@google.comaf84e742012-10-05 13:23:24 +0000209
bsalomon@google.comc7448ce2012-10-05 19:04:13 +0000210 this->setBlendFunc(paint.getSrcBlendCoeff(), paint.getDstBlendCoeff());
bsalomon@google.comc7448ce2012-10-05 19:04:13 +0000211 this->setCoverage(paint.getCoverage());
egdaniel9514d242014-07-18 06:15:43 -0700212 this->invalidateBlendOptFlags();
bsalomon@google.comaf84e742012-10-05 13:23:24 +0000213}
bsalomon@google.com5b3e8902012-10-05 20:13:28 +0000214
215////////////////////////////////////////////////////////////////////////////////
216
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000217static size_t vertex_size(const GrVertexAttrib* attribs, int count) {
218 // this works as long as we're 4 byte-aligned
commit-bot@chromium.org515dcd32013-08-28 14:17:03 +0000219#ifdef SK_DEBUG
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000220 uint32_t overlapCheck = 0;
221#endif
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000222 SkASSERT(count <= GrDrawState::kMaxVertexAttribCnt);
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000223 size_t size = 0;
224 for (int index = 0; index < count; ++index) {
jvanverth@google.com054ae992013-04-01 20:06:51 +0000225 size_t attribSize = GrVertexAttribTypeSize(attribs[index].fType);
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000226 size += attribSize;
commit-bot@chromium.org515dcd32013-08-28 14:17:03 +0000227#ifdef SK_DEBUG
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000228 size_t dwordCount = attribSize >> 2;
229 uint32_t mask = (1 << dwordCount)-1;
230 size_t offsetShift = attribs[index].fOffset >> 2;
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000231 SkASSERT(!(overlapCheck & (mask << offsetShift)));
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000232 overlapCheck |= (mask << offsetShift);
233#endif
jvanverth@google.comcc782382013-01-28 20:39:48 +0000234 }
235 return size;
236}
237
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000238size_t GrDrawState::getVertexSize() const {
bsalomon2ed5ef82014-07-07 08:44:05 -0700239 return vertex_size(fVAPtr, fVACount);
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000240}
241
jvanverth@google.comcc782382013-01-28 20:39:48 +0000242////////////////////////////////////////////////////////////////////////////////
243
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000244void GrDrawState::setVertexAttribs(const GrVertexAttrib* attribs, int count) {
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000245 SkASSERT(count <= kMaxVertexAttribCnt);
robertphillips@google.com42903302013-04-20 12:26:07 +0000246
bsalomon2ed5ef82014-07-07 08:44:05 -0700247 fVAPtr = attribs;
248 fVACount = count;
jvanverth@google.com054ae992013-04-01 20:06:51 +0000249
250 // Set all the indices to -1
bsalomon2ed5ef82014-07-07 08:44:05 -0700251 memset(fFixedFunctionVertexAttribIndices,
jvanverth@google.com054ae992013-04-01 20:06:51 +0000252 0xff,
bsalomon2ed5ef82014-07-07 08:44:05 -0700253 sizeof(fFixedFunctionVertexAttribIndices));
commit-bot@chromium.org515dcd32013-08-28 14:17:03 +0000254#ifdef SK_DEBUG
jvanverth@google.com054ae992013-04-01 20:06:51 +0000255 uint32_t overlapCheck = 0;
256#endif
257 for (int i = 0; i < count; ++i) {
258 if (attribs[i].fBinding < kGrFixedFunctionVertexAttribBindingCnt) {
259 // The fixed function attribs can only be specified once
bsalomon2ed5ef82014-07-07 08:44:05 -0700260 SkASSERT(-1 == fFixedFunctionVertexAttribIndices[attribs[i].fBinding]);
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000261 SkASSERT(GrFixedFunctionVertexAttribVectorCount(attribs[i].fBinding) ==
jvanverth@google.com054ae992013-04-01 20:06:51 +0000262 GrVertexAttribTypeVectorCount(attribs[i].fType));
bsalomon2ed5ef82014-07-07 08:44:05 -0700263 fFixedFunctionVertexAttribIndices[attribs[i].fBinding] = i;
jvanverth@google.com054ae992013-04-01 20:06:51 +0000264 }
commit-bot@chromium.org515dcd32013-08-28 14:17:03 +0000265#ifdef SK_DEBUG
jvanverth@google.com054ae992013-04-01 20:06:51 +0000266 size_t dwordCount = GrVertexAttribTypeSize(attribs[i].fType) >> 2;
267 uint32_t mask = (1 << dwordCount)-1;
268 size_t offsetShift = attribs[i].fOffset >> 2;
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000269 SkASSERT(!(overlapCheck & (mask << offsetShift)));
jvanverth@google.com054ae992013-04-01 20:06:51 +0000270 overlapCheck |= (mask << offsetShift);
271#endif
jvanverth@google.comcc782382013-01-28 20:39:48 +0000272 }
egdaniel9514d242014-07-18 06:15:43 -0700273 this->invalidateBlendOptFlags();
jvanverth@google.com054ae992013-04-01 20:06:51 +0000274 // Positions must be specified.
bsalomon2ed5ef82014-07-07 08:44:05 -0700275 SkASSERT(-1 != fFixedFunctionVertexAttribIndices[kPosition_GrVertexAttribBinding]);
jvanverth@google.comcc782382013-01-28 20:39:48 +0000276}
277
278////////////////////////////////////////////////////////////////////////////////
279
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000280void GrDrawState::setDefaultVertexAttribs() {
jvanverth@google.com054ae992013-04-01 20:06:51 +0000281 static const GrVertexAttrib kPositionAttrib =
282 {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding};
robertphillips@google.com42903302013-04-20 12:26:07 +0000283
bsalomon2ed5ef82014-07-07 08:44:05 -0700284 fVAPtr = &kPositionAttrib;
285 fVACount = 1;
robertphillips@google.com42903302013-04-20 12:26:07 +0000286
jvanverth@google.com054ae992013-04-01 20:06:51 +0000287 // set all the fixed function indices to -1 except position.
bsalomon2ed5ef82014-07-07 08:44:05 -0700288 memset(fFixedFunctionVertexAttribIndices,
jvanverth@google.com054ae992013-04-01 20:06:51 +0000289 0xff,
bsalomon2ed5ef82014-07-07 08:44:05 -0700290 sizeof(fFixedFunctionVertexAttribIndices));
291 fFixedFunctionVertexAttribIndices[kPosition_GrVertexAttribBinding] = 0;
egdaniel9514d242014-07-18 06:15:43 -0700292 this->invalidateBlendOptFlags();
jvanverth@google.comcc782382013-01-28 20:39:48 +0000293}
294
295////////////////////////////////////////////////////////////////////////////////
296
commit-bot@chromium.orgff6ea262013-03-12 12:26:08 +0000297bool GrDrawState::validateVertexAttribs() const {
jvanverth@google.com054ae992013-04-01 20:06:51 +0000298 // check consistency of effects and attributes
299 GrSLType slTypes[kMaxVertexAttribCnt];
300 for (int i = 0; i < kMaxVertexAttribCnt; ++i) {
301 slTypes[i] = static_cast<GrSLType>(-1);
commit-bot@chromium.orgff6ea262013-03-12 12:26:08 +0000302 }
egdaniel776bdbd2014-08-06 11:07:02 -0700303 int totalStages = this->numTotalStages();
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000304 for (int s = 0; s < totalStages; ++s) {
egdaniel776bdbd2014-08-06 11:07:02 -0700305 int covIdx = s - this->numColorStages();
306 const GrEffectStage& stage = covIdx < 0 ? this->getColorStage(s) :
307 this->getCoverageStage(covIdx);
bsalomonf99f8842014-07-07 11:54:23 -0700308 const GrEffect* effect = stage.getEffect();
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000309 SkASSERT(NULL != effect);
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000310 // make sure that any attribute indices have the correct binding type, that the attrib
311 // type and effect's shader lang type are compatible, and that attributes shared by
312 // multiple effects use the same shader lang type.
313 const int* attributeIndices = stage.getVertexAttribIndices();
314 int numAttributes = stage.getVertexAttribIndexCount();
315 for (int i = 0; i < numAttributes; ++i) {
316 int attribIndex = attributeIndices[i];
bsalomon2ed5ef82014-07-07 08:44:05 -0700317 if (attribIndex >= fVACount ||
318 kEffect_GrVertexAttribBinding != fVAPtr[attribIndex].fBinding) {
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000319 return false;
jvanverth@google.comc7bf2962013-04-01 19:29:32 +0000320 }
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000321
bsalomonf99f8842014-07-07 11:54:23 -0700322 GrSLType effectSLType = effect->vertexAttribType(i);
bsalomon2ed5ef82014-07-07 08:44:05 -0700323 GrVertexAttribType attribType = fVAPtr[attribIndex].fType;
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000324 int slVecCount = GrSLTypeVectorCount(effectSLType);
325 int attribVecCount = GrVertexAttribTypeVectorCount(attribType);
326 if (slVecCount != attribVecCount ||
327 (static_cast<GrSLType>(-1) != slTypes[attribIndex] &&
328 slTypes[attribIndex] != effectSLType)) {
329 return false;
330 }
331 slTypes[attribIndex] = effectSLType;
commit-bot@chromium.orgff6ea262013-03-12 12:26:08 +0000332 }
333 }
334
335 return true;
336}
337
bsalomon@google.comd09ab842013-05-15 17:30:26 +0000338bool GrDrawState::willEffectReadDstColor() const {
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000339 if (!this->isColorWriteDisabled()) {
egdaniel776bdbd2014-08-06 11:07:02 -0700340 for (int s = 0; s < this->numColorStages(); ++s) {
341 if (this->getColorStage(s).getEffect()->willReadDstColor()) {
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000342 return true;
343 }
344 }
345 }
egdaniel776bdbd2014-08-06 11:07:02 -0700346 for (int s = 0; s < this->numCoverageStages(); ++s) {
347 if (this->getCoverageStage(s).getEffect()->willReadDstColor()) {
bsalomon@google.comd09ab842013-05-15 17:30:26 +0000348 return true;
349 }
350 }
351 return false;
352}
353
jvanverth@google.comcc782382013-01-28 20:39:48 +0000354////////////////////////////////////////////////////////////////////////////////
355
bsalomon62c447d2014-08-08 08:08:50 -0700356bool GrDrawState::couldApplyCoverage(const GrDrawTargetCaps& caps) const {
357 if (caps.dualSourceBlendingSupport()) {
358 return true;
359 }
360 // we can correctly apply coverage if a) we have dual source blending
361 // or b) one of our blend optimizations applies
362 // or c) the src, dst blend coeffs are 1,0 and we will read Dst Color
363 GrBlendCoeff srcCoeff;
364 GrBlendCoeff dstCoeff;
365 GrDrawState::BlendOptFlags flag = this->getBlendOpts(true, &srcCoeff, &dstCoeff);
366 return GrDrawState::kNone_BlendOpt != flag ||
367 (this->willEffectReadDstColor() &&
368 kOne_GrBlendCoeff == srcCoeff && kZero_GrBlendCoeff == dstCoeff);
369}
370
jvanverth@google.com054ae992013-04-01 20:06:51 +0000371bool GrDrawState::srcAlphaWillBeOne() const {
jvanverth@google.comcc782382013-01-28 20:39:48 +0000372 uint32_t validComponentFlags;
bsalomon@google.com89e6f5b2013-02-27 18:43:47 +0000373 GrColor color;
jvanverth@google.comcc782382013-01-28 20:39:48 +0000374 // Check if per-vertex or constant color may have partial alpha
jvanverth@google.com054ae992013-04-01 20:06:51 +0000375 if (this->hasColorVertexAttribute()) {
bsalomon62c447d2014-08-08 08:08:50 -0700376 if (fHints & kVertexColorsAreOpaque_Hint) {
377 validComponentFlags = kA_GrColorComponentFlag;
378 color = 0xFF << GrColor_SHIFT_A;
379 } else {
380 validComponentFlags = 0;
381 color = 0; // not strictly necessary but we get false alarms from tools about uninit.
382 }
jvanverth@google.comcc782382013-01-28 20:39:48 +0000383 } else {
bsalomon@google.comb8eb2e82013-03-28 13:46:42 +0000384 validComponentFlags = kRGBA_GrColorComponentFlags;
jvanverth@google.comcc782382013-01-28 20:39:48 +0000385 color = this->getColor();
386 }
387
388 // Run through the color stages
egdaniel776bdbd2014-08-06 11:07:02 -0700389 for (int s = 0; s < this->numColorStages(); ++s) {
390 const GrEffect* effect = this->getColorStage(s).getEffect();
bsalomonf99f8842014-07-07 11:54:23 -0700391 effect->getConstantColorComponents(&color, &validComponentFlags);
jvanverth@google.comcc782382013-01-28 20:39:48 +0000392 }
393
jvanverth@google.comcc782382013-01-28 20:39:48 +0000394 // Check whether coverage is treated as color. If so we run through the coverage computation.
395 if (this->isCoverageDrawing()) {
bsalomon637e57e2014-08-18 11:49:37 -0700396 // The shader generated for coverage drawing runs the full coverage computation and then
397 // makes the shader output be the multiplication of color and coverage. We mirror that here.
398 GrColor coverage;
399 uint32_t coverageComponentFlags;
400 if (this->hasCoverageVertexAttribute()) {
401 coverageComponentFlags = 0;
402 coverage = 0; // suppresses any warnings.
403 } else {
404 coverageComponentFlags = kRGBA_GrColorComponentFlags;
405 coverage = this->getCoverageColor();
jvanverth@google.comcc782382013-01-28 20:39:48 +0000406 }
bsalomon637e57e2014-08-18 11:49:37 -0700407
408 // Run through the coverage stages
egdaniel776bdbd2014-08-06 11:07:02 -0700409 for (int s = 0; s < this->numCoverageStages(); ++s) {
410 const GrEffect* effect = this->getCoverageStage(s).getEffect();
bsalomon637e57e2014-08-18 11:49:37 -0700411 effect->getConstantColorComponents(&coverage, &coverageComponentFlags);
jvanverth@google.comcc782382013-01-28 20:39:48 +0000412 }
bsalomon637e57e2014-08-18 11:49:37 -0700413
414 // Since the shader will multiply coverage and color, the only way the final A==1 is if
415 // coverage and color both have A==1.
416 return (kA_GrColorComponentFlag & validComponentFlags & coverageComponentFlags) &&
417 0xFF == GrColorUnpackA(color) && 0xFF == GrColorUnpackA(coverage);
418
jvanverth@google.comcc782382013-01-28 20:39:48 +0000419 }
bsalomon637e57e2014-08-18 11:49:37 -0700420
421 return (kA_GrColorComponentFlag & validComponentFlags) && 0xFF == GrColorUnpackA(color);
jvanverth@google.comcc782382013-01-28 20:39:48 +0000422}
423
jvanverth@google.com054ae992013-04-01 20:06:51 +0000424bool GrDrawState::hasSolidCoverage() const {
bsalomon@google.comd62e88e2013-02-01 14:19:27 +0000425 // If we're drawing coverage directly then coverage is effectively treated as color.
426 if (this->isCoverageDrawing()) {
427 return true;
428 }
429
430 GrColor coverage;
431 uint32_t validComponentFlags;
432 // Initialize to an unknown starting coverage if per-vertex coverage is specified.
jvanverth@google.com054ae992013-04-01 20:06:51 +0000433 if (this->hasCoverageVertexAttribute()) {
bsalomon@google.comd62e88e2013-02-01 14:19:27 +0000434 validComponentFlags = 0;
435 } else {
egdaniel8cbf3d52014-08-21 06:27:22 -0700436 coverage = this->getCoverageColor();
bsalomon@google.comb8eb2e82013-03-28 13:46:42 +0000437 validComponentFlags = kRGBA_GrColorComponentFlags;
bsalomon@google.comd62e88e2013-02-01 14:19:27 +0000438 }
439
440 // Run through the coverage stages and see if the coverage will be all ones at the end.
egdaniel776bdbd2014-08-06 11:07:02 -0700441 for (int s = 0; s < this->numCoverageStages(); ++s) {
442 const GrEffect* effect = this->getCoverageStage(s).getEffect();
bsalomonf99f8842014-07-07 11:54:23 -0700443 effect->getConstantColorComponents(&coverage, &validComponentFlags);
bsalomon@google.comd62e88e2013-02-01 14:19:27 +0000444 }
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000445 return (kRGBA_GrColorComponentFlags == validComponentFlags) && (0xffffffff == coverage);
bsalomon@google.comd62e88e2013-02-01 14:19:27 +0000446}
447
jvanverth@google.comcc782382013-01-28 20:39:48 +0000448////////////////////////////////////////////////////////////////////////////////
449
bsalomon@google.com2b446732013-02-12 16:47:41 +0000450// Some blend modes allow folding a fractional coverage value into the color's alpha channel, while
451// others will blend incorrectly.
452bool GrDrawState::canTweakAlphaForCoverage() const {
453 /*
454 The fractional coverage is f.
455 The src and dst coeffs are Cs and Cd.
456 The dst and src colors are S and D.
457 We want the blend to compute: f*Cs*S + (f*Cd + (1-f))D. By tweaking the source color's alpha
458 we're replacing S with S'=fS. It's obvious that that first term will always be ok. The second
459 term can be rearranged as [1-(1-Cd)f]D. By substituting in the various possibilities for Cd we
460 find that only 1, ISA, and ISC produce the correct destination when applied to S' and D.
461 Also, if we're directly rendering coverage (isCoverageDrawing) then coverage is treated as
462 color by definition.
463 */
egdaniel8cbf3d52014-08-21 06:27:22 -0700464 return kOne_GrBlendCoeff == fDstBlend ||
465 kISA_GrBlendCoeff == fDstBlend ||
466 kISC_GrBlendCoeff == fDstBlend ||
bsalomon@google.com2b446732013-02-12 16:47:41 +0000467 this->isCoverageDrawing();
468}
469
470GrDrawState::BlendOptFlags GrDrawState::getBlendOpts(bool forceCoverage,
471 GrBlendCoeff* srcCoeff,
472 GrBlendCoeff* dstCoeff) const {
bsalomon@google.com2b446732013-02-12 16:47:41 +0000473 GrBlendCoeff bogusSrcCoeff, bogusDstCoeff;
474 if (NULL == srcCoeff) {
475 srcCoeff = &bogusSrcCoeff;
476 }
bsalomon@google.com2b446732013-02-12 16:47:41 +0000477 if (NULL == dstCoeff) {
478 dstCoeff = &bogusDstCoeff;
479 }
egdaniel9514d242014-07-18 06:15:43 -0700480
481 if (forceCoverage) {
482 return this->calcBlendOpts(true, srcCoeff, dstCoeff);
483 }
484
485 if (0 == (fBlendOptFlags & kInvalid_BlendOptFlag)) {
486 *srcCoeff = fOptSrcBlend;
487 *dstCoeff = fOptDstBlend;
488 return fBlendOptFlags;
489 }
490
491 fBlendOptFlags = this->calcBlendOpts(forceCoverage, srcCoeff, dstCoeff);
492 fOptSrcBlend = *srcCoeff;
493 fOptDstBlend = *dstCoeff;
494
495 return fBlendOptFlags;
496}
497
498GrDrawState::BlendOptFlags GrDrawState::calcBlendOpts(bool forceCoverage,
499 GrBlendCoeff* srcCoeff,
500 GrBlendCoeff* dstCoeff) const {
501 *srcCoeff = this->getSrcBlendCoeff();
bsalomon@google.com2b446732013-02-12 16:47:41 +0000502 *dstCoeff = this->getDstBlendCoeff();
503
504 if (this->isColorWriteDisabled()) {
505 *srcCoeff = kZero_GrBlendCoeff;
506 *dstCoeff = kOne_GrBlendCoeff;
507 }
508
jvanverth@google.com054ae992013-04-01 20:06:51 +0000509 bool srcAIsOne = this->srcAlphaWillBeOne();
bsalomon@google.com2b446732013-02-12 16:47:41 +0000510 bool dstCoeffIsOne = kOne_GrBlendCoeff == *dstCoeff ||
511 (kSA_GrBlendCoeff == *dstCoeff && srcAIsOne);
512 bool dstCoeffIsZero = kZero_GrBlendCoeff == *dstCoeff ||
513 (kISA_GrBlendCoeff == *dstCoeff && srcAIsOne);
514
bsalomon@google.com2b446732013-02-12 16:47:41 +0000515 // When coeffs are (0,1) there is no reason to draw at all, unless
516 // stenciling is enabled. Having color writes disabled is effectively
bsalomon62c447d2014-08-08 08:08:50 -0700517 // (0,1).
518 if ((kZero_GrBlendCoeff == *srcCoeff && dstCoeffIsOne)) {
bsalomon@google.com2b446732013-02-12 16:47:41 +0000519 if (this->getStencil().doesWrite()) {
egdaniel0f1a7c42014-07-30 13:18:32 -0700520 return kEmitCoverage_BlendOptFlag;
bsalomon@google.com2b446732013-02-12 16:47:41 +0000521 } else {
522 return kSkipDraw_BlendOptFlag;
523 }
524 }
525
bsalomon62c447d2014-08-08 08:08:50 -0700526 bool hasCoverage = forceCoverage || !this->hasSolidCoverage();
bsalomon@google.com2b446732013-02-12 16:47:41 +0000527
528 // if we don't have coverage we can check whether the dst
529 // has to read at all. If not, we'll disable blending.
530 if (!hasCoverage) {
531 if (dstCoeffIsZero) {
532 if (kOne_GrBlendCoeff == *srcCoeff) {
533 // if there is no coverage and coeffs are (1,0) then we
534 // won't need to read the dst at all, it gets replaced by src
egdaniel0f1a7c42014-07-30 13:18:32 -0700535 *dstCoeff = kZero_GrBlendCoeff;
536 return kNone_BlendOpt;
bsalomon@google.com2b446732013-02-12 16:47:41 +0000537 } else if (kZero_GrBlendCoeff == *srcCoeff) {
538 // if the op is "clear" then we don't need to emit a color
539 // or blend, just write transparent black into the dst.
540 *srcCoeff = kOne_GrBlendCoeff;
541 *dstCoeff = kZero_GrBlendCoeff;
egdaniel0f1a7c42014-07-30 13:18:32 -0700542 return kEmitTransBlack_BlendOptFlag;
bsalomon@google.com2b446732013-02-12 16:47:41 +0000543 }
544 }
545 } else if (this->isCoverageDrawing()) {
546 // we have coverage but we aren't distinguishing it from alpha by request.
547 return kCoverageAsAlpha_BlendOptFlag;
548 } else {
549 // check whether coverage can be safely rolled into alpha
550 // of if we can skip color computation and just emit coverage
551 if (this->canTweakAlphaForCoverage()) {
552 return kCoverageAsAlpha_BlendOptFlag;
553 }
554 if (dstCoeffIsZero) {
555 if (kZero_GrBlendCoeff == *srcCoeff) {
556 // the source color is not included in the blend
557 // the dst coeff is effectively zero so blend works out to:
558 // (c)(0)D + (1-c)D = (1-c)D.
559 *dstCoeff = kISA_GrBlendCoeff;
560 return kEmitCoverage_BlendOptFlag;
561 } else if (srcAIsOne) {
562 // the dst coeff is effectively zero so blend works out to:
563 // cS + (c)(0)D + (1-c)D = cS + (1-c)D.
564 // If Sa is 1 then we can replace Sa with c
565 // and set dst coeff to 1-Sa.
566 *dstCoeff = kISA_GrBlendCoeff;
567 return kCoverageAsAlpha_BlendOptFlag;
568 }
569 } else if (dstCoeffIsOne) {
570 // the dst coeff is effectively one so blend works out to:
571 // cS + (c)(1)D + (1-c)D = cS + D.
572 *dstCoeff = kOne_GrBlendCoeff;
573 return kCoverageAsAlpha_BlendOptFlag;
574 }
575 }
egdaniel0f1a7c42014-07-30 13:18:32 -0700576
bsalomon@google.com2b446732013-02-12 16:47:41 +0000577 return kNone_BlendOpt;
578}
579
egdaniel02cafcc2014-07-21 11:37:28 -0700580bool GrDrawState::canIgnoreColorAttribute() const {
581 if (fBlendOptFlags & kInvalid_BlendOptFlag) {
582 this->getBlendOpts();
583 }
584 return SkToBool(fBlendOptFlags & (GrDrawState::kEmitTransBlack_BlendOptFlag |
585 GrDrawState::kEmitCoverage_BlendOptFlag));
586}
587
bsalomon8f727332014-08-05 07:50:06 -0700588//////////////////////////////////////////////////////////////////////////////
589
590GrDrawState::AutoVertexAttribRestore::AutoVertexAttribRestore(
591 GrDrawState* drawState) {
592 SkASSERT(NULL != drawState);
593 fDrawState = drawState;
594 fVAPtr = drawState->fVAPtr;
595 fVACount = drawState->fVACount;
596 fDrawState->setDefaultVertexAttribs();
597}
598
599//////////////////////////////////////////////////////////////////////////////s
600
601void GrDrawState::AutoRestoreEffects::set(GrDrawState* ds) {
602 if (NULL != fDrawState) {
egdaniel776bdbd2014-08-06 11:07:02 -0700603 int m = fDrawState->numColorStages() - fColorEffectCnt;
bsalomon8f727332014-08-05 07:50:06 -0700604 SkASSERT(m >= 0);
egdaniel8cbf3d52014-08-21 06:27:22 -0700605 fDrawState->fColorStages.pop_back_n(m);
bsalomon8f727332014-08-05 07:50:06 -0700606
egdaniel776bdbd2014-08-06 11:07:02 -0700607 int n = fDrawState->numCoverageStages() - fCoverageEffectCnt;
bsalomon8f727332014-08-05 07:50:06 -0700608 SkASSERT(n >= 0);
egdaniel8cbf3d52014-08-21 06:27:22 -0700609 fDrawState->fCoverageStages.pop_back_n(n);
bsalomon8f727332014-08-05 07:50:06 -0700610 if (m + n > 0) {
611 fDrawState->invalidateBlendOptFlags();
612 }
613 SkDEBUGCODE(--fDrawState->fBlockEffectRemovalCnt;)
614 }
615 fDrawState = ds;
616 if (NULL != ds) {
egdaniel776bdbd2014-08-06 11:07:02 -0700617 fColorEffectCnt = ds->numColorStages();
618 fCoverageEffectCnt = ds->numCoverageStages();
bsalomon8f727332014-08-05 07:50:06 -0700619 SkDEBUGCODE(++ds->fBlockEffectRemovalCnt;)
620 }
621}
egdaniel02cafcc2014-07-21 11:37:28 -0700622
bsalomon@google.com2b446732013-02-12 16:47:41 +0000623////////////////////////////////////////////////////////////////////////////////
624
bsalomon@google.com2fdcdeb2012-10-08 17:15:55 +0000625void GrDrawState::AutoViewMatrixRestore::restore() {
626 if (NULL != fDrawState) {
commit-bot@chromium.org1acc3d72013-09-06 23:13:05 +0000627 SkDEBUGCODE(--fDrawState->fBlockEffectRemovalCnt;)
bsalomon2ed5ef82014-07-07 08:44:05 -0700628 fDrawState->fViewMatrix = fViewMatrix;
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000629 SkASSERT(fDrawState->numColorStages() >= fNumColorStages);
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000630 int numCoverageStages = fSavedCoordChanges.count() - fNumColorStages;
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000631 SkASSERT(fDrawState->numCoverageStages() >= numCoverageStages);
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000632
633 int i = 0;
634 for (int s = 0; s < fNumColorStages; ++s, ++i) {
egdaniel8cbf3d52014-08-21 06:27:22 -0700635 fDrawState->fColorStages[s].restoreCoordChange(fSavedCoordChanges[i]);
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000636 }
637 for (int s = 0; s < numCoverageStages; ++s, ++i) {
egdaniel8cbf3d52014-08-21 06:27:22 -0700638 fDrawState->fCoverageStages[s].restoreCoordChange(fSavedCoordChanges[i]);
bsalomon@google.com2fdcdeb2012-10-08 17:15:55 +0000639 }
bsalomon@google.com137f1342013-05-29 21:27:53 +0000640 fDrawState = NULL;
bsalomon@google.com2fdcdeb2012-10-08 17:15:55 +0000641 }
bsalomon@google.com2fdcdeb2012-10-08 17:15:55 +0000642}
643
644void GrDrawState::AutoViewMatrixRestore::set(GrDrawState* drawState,
bsalomon@google.comc7818882013-03-20 19:19:53 +0000645 const SkMatrix& preconcatMatrix) {
bsalomon@google.com2fdcdeb2012-10-08 17:15:55 +0000646 this->restore();
bsalomon@google.com5b3e8902012-10-05 20:13:28 +0000647
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000648 SkASSERT(NULL == fDrawState);
bsalomon@google.com137f1342013-05-29 21:27:53 +0000649 if (NULL == drawState || preconcatMatrix.isIdentity()) {
bsalomon@google.com2fdcdeb2012-10-08 17:15:55 +0000650 return;
651 }
bsalomon@google.com137f1342013-05-29 21:27:53 +0000652 fDrawState = drawState;
bsalomon@google.com2fdcdeb2012-10-08 17:15:55 +0000653
bsalomon@google.com2fdcdeb2012-10-08 17:15:55 +0000654 fViewMatrix = drawState->getViewMatrix();
bsalomon2ed5ef82014-07-07 08:44:05 -0700655 drawState->fViewMatrix.preConcat(preconcatMatrix);
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000656
657 this->doEffectCoordChanges(preconcatMatrix);
commit-bot@chromium.org1acc3d72013-09-06 23:13:05 +0000658 SkDEBUGCODE(++fDrawState->fBlockEffectRemovalCnt;)
bsalomon@google.com2fdcdeb2012-10-08 17:15:55 +0000659}
660
bsalomon@google.com137f1342013-05-29 21:27:53 +0000661bool GrDrawState::AutoViewMatrixRestore::setIdentity(GrDrawState* drawState) {
bsalomon@google.com2fdcdeb2012-10-08 17:15:55 +0000662 this->restore();
663
bsalomon@google.com137f1342013-05-29 21:27:53 +0000664 if (NULL == drawState) {
bsalomon@google.com2fdcdeb2012-10-08 17:15:55 +0000665 return false;
skia.committer@gmail.comf467ce72012-10-09 02:01:37 +0000666 }
bsalomon@google.com2fdcdeb2012-10-08 17:15:55 +0000667
bsalomon@google.com137f1342013-05-29 21:27:53 +0000668 if (drawState->getViewMatrix().isIdentity()) {
669 return true;
670 }
671
bsalomon@google.com5b3e8902012-10-05 20:13:28 +0000672 fViewMatrix = drawState->getViewMatrix();
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000673 if (0 == drawState->numTotalStages()) {
bsalomon2ed5ef82014-07-07 08:44:05 -0700674 drawState->fViewMatrix.reset();
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000675 fDrawState = drawState;
676 fNumColorStages = 0;
677 fSavedCoordChanges.reset(0);
commit-bot@chromium.org1acc3d72013-09-06 23:13:05 +0000678 SkDEBUGCODE(++fDrawState->fBlockEffectRemovalCnt;)
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000679 return true;
680 } else {
681 SkMatrix inv;
682 if (!fViewMatrix.invert(&inv)) {
683 return false;
bsalomon@google.com5b3e8902012-10-05 20:13:28 +0000684 }
bsalomon2ed5ef82014-07-07 08:44:05 -0700685 drawState->fViewMatrix.reset();
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000686 fDrawState = drawState;
687 this->doEffectCoordChanges(inv);
commit-bot@chromium.org1acc3d72013-09-06 23:13:05 +0000688 SkDEBUGCODE(++fDrawState->fBlockEffectRemovalCnt;)
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000689 return true;
bsalomon@google.com5b3e8902012-10-05 20:13:28 +0000690 }
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000691}
692
693void GrDrawState::AutoViewMatrixRestore::doEffectCoordChanges(const SkMatrix& coordChangeMatrix) {
694 fSavedCoordChanges.reset(fDrawState->numTotalStages());
695 int i = 0;
696
697 fNumColorStages = fDrawState->numColorStages();
698 for (int s = 0; s < fNumColorStages; ++s, ++i) {
egdaniel776bdbd2014-08-06 11:07:02 -0700699 fDrawState->getColorStage(s).saveCoordChange(&fSavedCoordChanges[i]);
egdaniel8cbf3d52014-08-21 06:27:22 -0700700 fDrawState->fColorStages[s].localCoordChange(coordChangeMatrix);
bsalomon@google.com137f1342013-05-29 21:27:53 +0000701 }
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000702
703 int numCoverageStages = fDrawState->numCoverageStages();
704 for (int s = 0; s < numCoverageStages; ++s, ++i) {
egdaniel776bdbd2014-08-06 11:07:02 -0700705 fDrawState->getCoverageStage(s).saveCoordChange(&fSavedCoordChanges[i]);
egdaniel8cbf3d52014-08-21 06:27:22 -0700706 fDrawState->fCoverageStages[s].localCoordChange(coordChangeMatrix);
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000707 }
bsalomon@google.com5b3e8902012-10-05 20:13:28 +0000708}