blob: fef549463a327d0236f647a18243f6d01ecd5e4b [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"
egdaniel3658f382014-09-15 07:01:59 -07009
egdanielb1cff032014-11-13 06:19:25 -080010#include "GrBlend.h"
egdaniel3658f382014-09-15 07:01:59 -070011#include "GrOptDrawState.h"
12#include "GrPaint.h"
egdanielb6cbc382014-11-13 11:00:34 -080013#include "GrProcOptInfo.h"
egdaniel3658f382014-09-15 07:01:59 -070014
15//////////////////////////////////////////////////////////////////////////////s
16
egdaniel89af44a2014-09-26 06:15:04 -070017bool GrDrawState::isEqual(const GrDrawState& that) const {
18 bool usingVertexColors = this->hasColorVertexAttribute();
19 if (!usingVertexColors && this->fColor != that.fColor) {
20 return false;
21 }
22
23 if (this->getRenderTarget() != that.getRenderTarget() ||
24 this->fColorStages.count() != that.fColorStages.count() ||
25 this->fCoverageStages.count() != that.fCoverageStages.count() ||
26 !this->fViewMatrix.cheapEqualTo(that.fViewMatrix) ||
27 this->fSrcBlend != that.fSrcBlend ||
28 this->fDstBlend != that.fDstBlend ||
29 this->fBlendConstant != that.fBlendConstant ||
30 this->fFlagBits != that.fFlagBits ||
31 this->fVACount != that.fVACount ||
32 this->fVAStride != that.fVAStride ||
33 memcmp(this->fVAPtr, that.fVAPtr, this->fVACount * sizeof(GrVertexAttrib)) ||
34 this->fStencilSettings != that.fStencilSettings ||
35 this->fDrawFace != that.fDrawFace) {
36 return false;
37 }
38
39 bool usingVertexCoverage = this->hasCoverageVertexAttribute();
40 if (!usingVertexCoverage && this->fCoverage != that.fCoverage) {
41 return false;
42 }
43
44 bool explicitLocalCoords = this->hasLocalCoordAttribute();
45 if (this->hasGeometryProcessor()) {
46 if (!that.hasGeometryProcessor()) {
47 return false;
joshualitta5305a12014-10-10 17:47:00 -070048 } else if (!this->getGeometryProcessor()->isEqual(*that.getGeometryProcessor())) {
egdaniel89af44a2014-09-26 06:15:04 -070049 return false;
50 }
51 } else if (that.hasGeometryProcessor()) {
52 return false;
53 }
54
55 for (int i = 0; i < this->numColorStages(); i++) {
joshualitta5305a12014-10-10 17:47:00 -070056 if (!GrFragmentStage::AreCompatible(this->getColorStage(i), that.getColorStage(i),
egdaniel89af44a2014-09-26 06:15:04 -070057 explicitLocalCoords)) {
58 return false;
59 }
60 }
61 for (int i = 0; i < this->numCoverageStages(); i++) {
joshualitta5305a12014-10-10 17:47:00 -070062 if (!GrFragmentStage::AreCompatible(this->getCoverageStage(i), that.getCoverageStage(i),
egdaniel89af44a2014-09-26 06:15:04 -070063 explicitLocalCoords)) {
64 return false;
65 }
66 }
67
68 SkASSERT(0 == memcmp(this->fFixedFunctionVertexAttribIndices,
69 that.fFixedFunctionVertexAttribIndices,
70 sizeof(this->fFixedFunctionVertexAttribIndices)));
71
72 return true;
73}
74
bsalomon8f727332014-08-05 07:50:06 -070075//////////////////////////////////////////////////////////////////////////////s
76
egdaniel69bb90c2014-11-11 07:32:45 -080077GrDrawState::GrDrawState(const GrDrawState& state, const SkMatrix& preConcatMatrix) {
bsalomon8f727332014-08-05 07:50:06 -070078 SkDEBUGCODE(fBlockEffectRemovalCnt = 0;)
79 *this = state;
80 if (!preConcatMatrix.isIdentity()) {
egdaniel776bdbd2014-08-06 11:07:02 -070081 for (int i = 0; i < this->numColorStages(); ++i) {
egdaniel8cbf3d52014-08-21 06:27:22 -070082 fColorStages[i].localCoordChange(preConcatMatrix);
bsalomon8f727332014-08-05 07:50:06 -070083 }
egdaniel776bdbd2014-08-06 11:07:02 -070084 for (int i = 0; i < this->numCoverageStages(); ++i) {
egdaniel8cbf3d52014-08-21 06:27:22 -070085 fCoverageStages[i].localCoordChange(preConcatMatrix);
bsalomon8f727332014-08-05 07:50:06 -070086 }
bsalomon8f727332014-08-05 07:50:06 -070087 }
88}
89
90GrDrawState& GrDrawState::operator=(const GrDrawState& that) {
bsalomonae59b772014-11-19 08:23:49 -080091 fRenderTarget.reset(SkSafeRef(that.fRenderTarget.get()));
bsalomon8f727332014-08-05 07:50:06 -070092 fColor = that.fColor;
93 fViewMatrix = that.fViewMatrix;
egdaniel8cbf3d52014-08-21 06:27:22 -070094 fSrcBlend = that.fSrcBlend;
95 fDstBlend = that.fDstBlend;
bsalomon8f727332014-08-05 07:50:06 -070096 fBlendConstant = that.fBlendConstant;
97 fFlagBits = that.fFlagBits;
98 fVACount = that.fVACount;
99 fVAPtr = that.fVAPtr;
egdaniel7b3d5ee2014-08-28 05:41:14 -0700100 fVAStride = that.fVAStride;
bsalomon8f727332014-08-05 07:50:06 -0700101 fStencilSettings = that.fStencilSettings;
102 fCoverage = that.fCoverage;
103 fDrawFace = that.fDrawFace;
bsalomonae59b772014-11-19 08:23:49 -0800104 fGeometryProcessor.reset(SkSafeRef(that.fGeometryProcessor.get()));
egdaniel8cbf3d52014-08-21 06:27:22 -0700105 fColorStages = that.fColorStages;
106 fCoverageStages = that.fCoverageStages;
bsalomon8f727332014-08-05 07:50:06 -0700107
bsalomon62c447d2014-08-08 08:08:50 -0700108 fHints = that.fHints;
egdaniel776bdbd2014-08-06 11:07:02 -0700109
egdanielb6cbc382014-11-13 11:00:34 -0800110 fColorProcInfoValid = that.fColorProcInfoValid;
111 fCoverageProcInfoValid = that.fCoverageProcInfoValid;
112 if (fColorProcInfoValid) {
113 fColorProcInfo = that.fColorProcInfo;
114 }
115 if (fCoverageProcInfoValid) {
116 fCoverageProcInfo = that.fCoverageProcInfo;
117 }
118
bsalomon8f727332014-08-05 07:50:06 -0700119 memcpy(fFixedFunctionVertexAttribIndices,
120 that.fFixedFunctionVertexAttribIndices,
121 sizeof(fFixedFunctionVertexAttribIndices));
122 return *this;
123}
124
125void GrDrawState::onReset(const SkMatrix* initialViewMatrix) {
126 SkASSERT(0 == fBlockEffectRemovalCnt || 0 == this->numTotalStages());
bsalomonae59b772014-11-19 08:23:49 -0800127 fRenderTarget.reset(NULL);
bsalomon2a9ca782014-09-05 14:27:43 -0700128
joshualittbd769d02014-09-04 08:56:46 -0700129 fGeometryProcessor.reset(NULL);
egdaniel8cbf3d52014-08-21 06:27:22 -0700130 fColorStages.reset();
131 fCoverageStages.reset();
bsalomon8f727332014-08-05 07:50:06 -0700132
bsalomon8f727332014-08-05 07:50:06 -0700133
134 this->setDefaultVertexAttribs();
135
136 fColor = 0xffffffff;
137 if (NULL == initialViewMatrix) {
138 fViewMatrix.reset();
139 } else {
140 fViewMatrix = *initialViewMatrix;
141 }
egdaniel8cbf3d52014-08-21 06:27:22 -0700142 fSrcBlend = kOne_GrBlendCoeff;
143 fDstBlend = kZero_GrBlendCoeff;
bsalomon8f727332014-08-05 07:50:06 -0700144 fBlendConstant = 0x0;
145 fFlagBits = 0x0;
146 fStencilSettings.setDisabled();
egdaniel8cbf3d52014-08-21 06:27:22 -0700147 fCoverage = 0xff;
bsalomon8f727332014-08-05 07:50:06 -0700148 fDrawFace = kBoth_DrawFace;
149
bsalomon62c447d2014-08-08 08:08:50 -0700150 fHints = 0;
egdanielb6cbc382014-11-13 11:00:34 -0800151
152 fColorProcInfoValid = false;
153 fCoverageProcInfoValid = false;
bsalomon8f727332014-08-05 07:50:06 -0700154}
155
bsalomon@google.com137f1342013-05-29 21:27:53 +0000156bool GrDrawState::setIdentityViewMatrix() {
joshualitt4dd99882014-11-11 08:51:30 -0800157 if (this->numFragmentStages()) {
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000158 SkMatrix invVM;
bsalomon2ed5ef82014-07-07 08:44:05 -0700159 if (!fViewMatrix.invert(&invVM)) {
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000160 // sad trombone sound
161 return false;
162 }
egdaniel776bdbd2014-08-06 11:07:02 -0700163 for (int s = 0; s < this->numColorStages(); ++s) {
egdaniel8cbf3d52014-08-21 06:27:22 -0700164 fColorStages[s].localCoordChange(invVM);
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000165 }
egdaniel776bdbd2014-08-06 11:07:02 -0700166 for (int s = 0; s < this->numCoverageStages(); ++s) {
egdaniel8cbf3d52014-08-21 06:27:22 -0700167 fCoverageStages[s].localCoordChange(invVM);
bsalomon@google.com137f1342013-05-29 21:27:53 +0000168 }
169 }
bsalomon2ed5ef82014-07-07 08:44:05 -0700170 fViewMatrix.reset();
bsalomon@google.com137f1342013-05-29 21:27:53 +0000171 return true;
172}
173
commit-bot@chromium.orgbb6a3172013-05-28 17:25:49 +0000174void GrDrawState::setFromPaint(const GrPaint& paint, const SkMatrix& vm, GrRenderTarget* rt) {
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000175 SkASSERT(0 == fBlockEffectRemovalCnt || 0 == this->numTotalStages());
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000176
joshualittbd769d02014-09-04 08:56:46 -0700177 fGeometryProcessor.reset(NULL);
egdaniel8cbf3d52014-08-21 06:27:22 -0700178 fColorStages.reset();
179 fCoverageStages.reset();
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000180
commit-bot@chromium.org42dacab2013-07-13 17:24:24 +0000181 for (int i = 0; i < paint.numColorStages(); ++i) {
egdaniel8cbf3d52014-08-21 06:27:22 -0700182 fColorStages.push_back(paint.getColorStage(i));
bsalomon@google.comaf84e742012-10-05 13:23:24 +0000183 }
184
commit-bot@chromium.org42dacab2013-07-13 17:24:24 +0000185 for (int i = 0; i < paint.numCoverageStages(); ++i) {
egdaniel8cbf3d52014-08-21 06:27:22 -0700186 fCoverageStages.push_back(paint.getCoverageStage(i));
bsalomon@google.comaf84e742012-10-05 13:23:24 +0000187 }
188
commit-bot@chromium.orgbb6a3172013-05-28 17:25:49 +0000189 this->setRenderTarget(rt);
bsalomon@google.comaf84e742012-10-05 13:23:24 +0000190
bsalomon2ed5ef82014-07-07 08:44:05 -0700191 fViewMatrix = vm;
commit-bot@chromium.orgbb6a3172013-05-28 17:25:49 +0000192
193 // These have no equivalent in GrPaint, set them to defaults
bsalomon2ed5ef82014-07-07 08:44:05 -0700194 fBlendConstant = 0x0;
195 fDrawFace = kBoth_DrawFace;
196 fStencilSettings.setDisabled();
commit-bot@chromium.orgbb6a3172013-05-28 17:25:49 +0000197 this->resetStateFlags();
bsalomon62c447d2014-08-08 08:08:50 -0700198 fHints = 0;
commit-bot@chromium.orgbb6a3172013-05-28 17:25:49 +0000199
bsalomon@google.com21c10c52013-06-13 17:44:07 +0000200 // Enable the clip bit
201 this->enableState(GrDrawState::kClip_StateBit);
202
commit-bot@chromium.orgbb6a3172013-05-28 17:25:49 +0000203 this->setColor(paint.getColor());
bsalomon@google.comc7448ce2012-10-05 19:04:13 +0000204 this->setState(GrDrawState::kDither_StateBit, paint.isDither());
205 this->setState(GrDrawState::kHWAntialias_StateBit, paint.isAntiAlias());
bsalomon@google.comaf84e742012-10-05 13:23:24 +0000206
bsalomon@google.comc7448ce2012-10-05 19:04:13 +0000207 this->setBlendFunc(paint.getSrcBlendCoeff(), paint.getDstBlendCoeff());
joshualitt4052a8e2014-11-11 13:46:30 -0800208 this->setCoverage(0xFF);
egdanielb6cbc382014-11-13 11:00:34 -0800209 fColorProcInfoValid = false;
210 fCoverageProcInfoValid = false;
bsalomon@google.comaf84e742012-10-05 13:23:24 +0000211}
bsalomon@google.com5b3e8902012-10-05 20:13:28 +0000212
213////////////////////////////////////////////////////////////////////////////////
214
egdaniel89af44a2014-09-26 06:15:04 -0700215bool GrDrawState::validateVertexAttribs() const {
216 // check consistency of effects and attributes
217 GrSLType slTypes[kMaxVertexAttribCnt];
218 for (int i = 0; i < kMaxVertexAttribCnt; ++i) {
219 slTypes[i] = static_cast<GrSLType>(-1);
220 }
221
222 if (this->hasGeometryProcessor()) {
joshualitta5305a12014-10-10 17:47:00 -0700223 const GrGeometryProcessor* gp = this->getGeometryProcessor();
egdaniel89af44a2014-09-26 06:15:04 -0700224 // make sure that any attribute indices have the correct binding type, that the attrib
225 // type and effect's shader lang type are compatible, and that attributes shared by
226 // multiple effects use the same shader lang type.
227 const GrGeometryProcessor::VertexAttribArray& s = gp->getVertexAttribs();
228
229 int effectIndex = 0;
230 for (int index = 0; index < fVACount; index++) {
231 if (kGeometryProcessor_GrVertexAttribBinding != fVAPtr[index].fBinding) {
232 // we only care about effect bindings
233 continue;
234 }
235 SkASSERT(effectIndex < s.count());
236 GrSLType effectSLType = s[effectIndex].getType();
237 GrVertexAttribType attribType = fVAPtr[index].fType;
238 int slVecCount = GrSLTypeVectorCount(effectSLType);
239 int attribVecCount = GrVertexAttribTypeVectorCount(attribType);
240 if (slVecCount != attribVecCount ||
241 (static_cast<GrSLType>(-1) != slTypes[index] && slTypes[index] != effectSLType)) {
242 return false;
243 }
244 slTypes[index] = effectSLType;
245 effectIndex++;
246 }
247 // Make sure all attributes are consumed and we were able to find everything
248 SkASSERT(s.count() == effectIndex);
249 }
250
251 return true;
252}
253
254////////////////////////////////////////////////////////////////////////////////
255
egdaniel7b3d5ee2014-08-28 05:41:14 -0700256static void validate_vertex_attribs(const GrVertexAttrib* attribs, int count, size_t stride) {
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000257 // this works as long as we're 4 byte-aligned
commit-bot@chromium.org515dcd32013-08-28 14:17:03 +0000258#ifdef SK_DEBUG
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000259 uint32_t overlapCheck = 0;
egdaniel89af44a2014-09-26 06:15:04 -0700260 SkASSERT(count <= GrDrawState::kMaxVertexAttribCnt);
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000261 for (int index = 0; index < count; ++index) {
jvanverth@google.com054ae992013-04-01 20:06:51 +0000262 size_t attribSize = GrVertexAttribTypeSize(attribs[index].fType);
egdaniel7b3d5ee2014-08-28 05:41:14 -0700263 size_t attribOffset = attribs[index].fOffset;
264 SkASSERT(attribOffset + attribSize <= stride);
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000265 size_t dwordCount = attribSize >> 2;
266 uint32_t mask = (1 << dwordCount)-1;
egdaniel7b3d5ee2014-08-28 05:41:14 -0700267 size_t offsetShift = attribOffset >> 2;
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000268 SkASSERT(!(overlapCheck & (mask << offsetShift)));
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000269 overlapCheck |= (mask << offsetShift);
djsollenea81ced2014-08-27 13:07:34 -0700270 }
egdaniel7b3d5ee2014-08-28 05:41:14 -0700271#endif
jvanverth@google.comcc782382013-01-28 20:39:48 +0000272}
273
274////////////////////////////////////////////////////////////////////////////////
275
egdaniel7b3d5ee2014-08-28 05:41:14 -0700276void GrDrawState::internalSetVertexAttribs(const GrVertexAttrib* attribs, int count,
277 size_t stride) {
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000278 SkASSERT(count <= kMaxVertexAttribCnt);
robertphillips@google.com42903302013-04-20 12:26:07 +0000279
bsalomon2ed5ef82014-07-07 08:44:05 -0700280 fVAPtr = attribs;
281 fVACount = count;
egdaniel7b3d5ee2014-08-28 05:41:14 -0700282 fVAStride = stride;
283 validate_vertex_attribs(fVAPtr, fVACount, fVAStride);
jvanverth@google.com054ae992013-04-01 20:06:51 +0000284
285 // Set all the indices to -1
bsalomon2ed5ef82014-07-07 08:44:05 -0700286 memset(fFixedFunctionVertexAttribIndices,
jvanverth@google.com054ae992013-04-01 20:06:51 +0000287 0xff,
bsalomon2ed5ef82014-07-07 08:44:05 -0700288 sizeof(fFixedFunctionVertexAttribIndices));
commit-bot@chromium.org515dcd32013-08-28 14:17:03 +0000289#ifdef SK_DEBUG
jvanverth@google.com054ae992013-04-01 20:06:51 +0000290 uint32_t overlapCheck = 0;
291#endif
292 for (int i = 0; i < count; ++i) {
293 if (attribs[i].fBinding < kGrFixedFunctionVertexAttribBindingCnt) {
294 // The fixed function attribs can only be specified once
bsalomon2ed5ef82014-07-07 08:44:05 -0700295 SkASSERT(-1 == fFixedFunctionVertexAttribIndices[attribs[i].fBinding]);
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000296 SkASSERT(GrFixedFunctionVertexAttribVectorCount(attribs[i].fBinding) ==
jvanverth@google.com054ae992013-04-01 20:06:51 +0000297 GrVertexAttribTypeVectorCount(attribs[i].fType));
bsalomon2ed5ef82014-07-07 08:44:05 -0700298 fFixedFunctionVertexAttribIndices[attribs[i].fBinding] = i;
jvanverth@google.com054ae992013-04-01 20:06:51 +0000299 }
commit-bot@chromium.org515dcd32013-08-28 14:17:03 +0000300#ifdef SK_DEBUG
jvanverth@google.com054ae992013-04-01 20:06:51 +0000301 size_t dwordCount = GrVertexAttribTypeSize(attribs[i].fType) >> 2;
302 uint32_t mask = (1 << dwordCount)-1;
303 size_t offsetShift = attribs[i].fOffset >> 2;
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000304 SkASSERT(!(overlapCheck & (mask << offsetShift)));
jvanverth@google.com054ae992013-04-01 20:06:51 +0000305 overlapCheck |= (mask << offsetShift);
306#endif
jvanverth@google.comcc782382013-01-28 20:39:48 +0000307 }
egdanielb6cbc382014-11-13 11:00:34 -0800308 fColorProcInfoValid = false;
309 fCoverageProcInfoValid = false;
jvanverth@google.com054ae992013-04-01 20:06:51 +0000310 // Positions must be specified.
bsalomon2ed5ef82014-07-07 08:44:05 -0700311 SkASSERT(-1 != fFixedFunctionVertexAttribIndices[kPosition_GrVertexAttribBinding]);
jvanverth@google.comcc782382013-01-28 20:39:48 +0000312}
313
314////////////////////////////////////////////////////////////////////////////////
315
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000316void GrDrawState::setDefaultVertexAttribs() {
jvanverth@google.com054ae992013-04-01 20:06:51 +0000317 static const GrVertexAttrib kPositionAttrib =
318 {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding};
robertphillips@google.com42903302013-04-20 12:26:07 +0000319
bsalomon2ed5ef82014-07-07 08:44:05 -0700320 fVAPtr = &kPositionAttrib;
321 fVACount = 1;
egdaniel7b3d5ee2014-08-28 05:41:14 -0700322 fVAStride = GrVertexAttribTypeSize(kVec2f_GrVertexAttribType);
robertphillips@google.com42903302013-04-20 12:26:07 +0000323
jvanverth@google.com054ae992013-04-01 20:06:51 +0000324 // set all the fixed function indices to -1 except position.
bsalomon2ed5ef82014-07-07 08:44:05 -0700325 memset(fFixedFunctionVertexAttribIndices,
jvanverth@google.com054ae992013-04-01 20:06:51 +0000326 0xff,
bsalomon2ed5ef82014-07-07 08:44:05 -0700327 sizeof(fFixedFunctionVertexAttribIndices));
328 fFixedFunctionVertexAttribIndices[kPosition_GrVertexAttribBinding] = 0;
egdanielb6cbc382014-11-13 11:00:34 -0800329 fColorProcInfoValid = false;
330 fCoverageProcInfoValid = false;
jvanverth@google.comcc782382013-01-28 20:39:48 +0000331}
332
333////////////////////////////////////////////////////////////////////////////////
334
bsalomon62c447d2014-08-08 08:08:50 -0700335bool GrDrawState::couldApplyCoverage(const GrDrawTargetCaps& caps) const {
336 if (caps.dualSourceBlendingSupport()) {
337 return true;
338 }
339 // we can correctly apply coverage if a) we have dual source blending
340 // or b) one of our blend optimizations applies
341 // or c) the src, dst blend coeffs are 1,0 and we will read Dst Color
342 GrBlendCoeff srcCoeff;
343 GrBlendCoeff dstCoeff;
egdaniel170f90b2014-09-16 12:54:40 -0700344 BlendOptFlags flag = this->getBlendOpts(true, &srcCoeff, &dstCoeff);
egdaniel89af44a2014-09-26 06:15:04 -0700345 return GrDrawState::kNone_BlendOpt != flag ||
bsalomon62c447d2014-08-08 08:08:50 -0700346 (this->willEffectReadDstColor() &&
347 kOne_GrBlendCoeff == srcCoeff && kZero_GrBlendCoeff == dstCoeff);
348}
349
egdaniel89af44a2014-09-26 06:15:04 -0700350bool GrDrawState::hasSolidCoverage() const {
351 // If we're drawing coverage directly then coverage is effectively treated as color.
352 if (this->isCoverageDrawing()) {
353 return true;
354 }
355
joshualitt4dd99882014-11-11 08:51:30 -0800356 if (this->numCoverageStages() > 0) {
357 return false;
358 }
359
egdanielb6cbc382014-11-13 11:00:34 -0800360 this->calcCoverageInvariantOutput();
361 return fCoverageProcInfo.isSolidWhite();
egdaniel89af44a2014-09-26 06:15:04 -0700362}
363
egdaniel21aed572014-08-26 12:24:06 -0700364//////////////////////////////////////////////////////////////////////////////
jvanverth@google.comcc782382013-01-28 20:39:48 +0000365
egdaniel3658f382014-09-15 07:01:59 -0700366GrDrawState::AutoVertexAttribRestore::AutoVertexAttribRestore(GrDrawState* drawState) {
bsalomon49f085d2014-09-05 13:34:00 -0700367 SkASSERT(drawState);
egdaniel21aed572014-08-26 12:24:06 -0700368 fDrawState = drawState;
369 fVAPtr = drawState->fVAPtr;
370 fVACount = drawState->fVACount;
egdaniel7b3d5ee2014-08-28 05:41:14 -0700371 fVAStride = drawState->fVAStride;
egdaniel21aed572014-08-26 12:24:06 -0700372 fDrawState->setDefaultVertexAttribs();
jvanverth@google.comcc782382013-01-28 20:39:48 +0000373}
374
egdaniel21aed572014-08-26 12:24:06 -0700375//////////////////////////////////////////////////////////////////////////////s
bsalomon@google.comd62e88e2013-02-01 14:19:27 +0000376
egdaniel89af44a2014-09-26 06:15:04 -0700377bool GrDrawState::willEffectReadDstColor() const {
378 if (!this->isColorWriteDisabled()) {
egdanielb6cbc382014-11-13 11:00:34 -0800379 this->calcColorInvariantOutput();
380 if (fColorProcInfo.readsDst()) {
egdaniel89af44a2014-09-26 06:15:04 -0700381 return true;
382 }
383 }
egdanielb6cbc382014-11-13 11:00:34 -0800384 this->calcCoverageInvariantOutput();
385 return fCoverageProcInfo.readsDst();
egdaniel89af44a2014-09-26 06:15:04 -0700386}
387
egdaniel21aed572014-08-26 12:24:06 -0700388void GrDrawState::AutoRestoreEffects::set(GrDrawState* ds) {
bsalomon49f085d2014-09-05 13:34:00 -0700389 if (fDrawState) {
bsalomon9b536522014-09-05 09:18:51 -0700390 // See the big comment on the class definition about GPs.
bsalomon52e9d632014-09-05 12:23:12 -0700391 if (SK_InvalidUniqueID == fOriginalGPID) {
bsalomon9b536522014-09-05 09:18:51 -0700392 fDrawState->fGeometryProcessor.reset(NULL);
bsalomon52e9d632014-09-05 12:23:12 -0700393 } else {
joshualitta5305a12014-10-10 17:47:00 -0700394 SkASSERT(fDrawState->getGeometryProcessor()->getUniqueID() ==
bsalomon52e9d632014-09-05 12:23:12 -0700395 fOriginalGPID);
396 fOriginalGPID = SK_InvalidUniqueID;
bsalomon9b536522014-09-05 09:18:51 -0700397 }
joshualittbd769d02014-09-04 08:56:46 -0700398
egdaniel21aed572014-08-26 12:24:06 -0700399 int m = fDrawState->numColorStages() - fColorEffectCnt;
400 SkASSERT(m >= 0);
401 fDrawState->fColorStages.pop_back_n(m);
bsalomon@google.comd62e88e2013-02-01 14:19:27 +0000402
egdaniel21aed572014-08-26 12:24:06 -0700403 int n = fDrawState->numCoverageStages() - fCoverageEffectCnt;
404 SkASSERT(n >= 0);
405 fDrawState->fCoverageStages.pop_back_n(n);
egdanielb6cbc382014-11-13 11:00:34 -0800406 if (m + n > 0) {
407 fDrawState->fColorProcInfoValid = false;
408 fDrawState->fCoverageProcInfoValid = false;
409 }
egdaniel21aed572014-08-26 12:24:06 -0700410 SkDEBUGCODE(--fDrawState->fBlockEffectRemovalCnt;)
bsalomon@google.comd62e88e2013-02-01 14:19:27 +0000411 }
egdaniel21aed572014-08-26 12:24:06 -0700412 fDrawState = ds;
413 if (NULL != ds) {
bsalomon52e9d632014-09-05 12:23:12 -0700414 SkASSERT(SK_InvalidUniqueID == fOriginalGPID);
bsalomon9b536522014-09-05 09:18:51 -0700415 if (NULL != ds->getGeometryProcessor()) {
joshualitta5305a12014-10-10 17:47:00 -0700416 fOriginalGPID = ds->getGeometryProcessor()->getUniqueID();
joshualittbd769d02014-09-04 08:56:46 -0700417 }
egdaniel21aed572014-08-26 12:24:06 -0700418 fColorEffectCnt = ds->numColorStages();
419 fCoverageEffectCnt = ds->numCoverageStages();
420 SkDEBUGCODE(++ds->fBlockEffectRemovalCnt;)
421 }
bsalomon@google.comd62e88e2013-02-01 14:19:27 +0000422}
423
jvanverth@google.comcc782382013-01-28 20:39:48 +0000424////////////////////////////////////////////////////////////////////////////////
425
egdaniel89af44a2014-09-26 06:15:04 -0700426// Some blend modes allow folding a fractional coverage value into the color's alpha channel, while
427// others will blend incorrectly.
428bool GrDrawState::canTweakAlphaForCoverage() const {
429 /*
430 The fractional coverage is f.
431 The src and dst coeffs are Cs and Cd.
432 The dst and src colors are S and D.
433 We want the blend to compute: f*Cs*S + (f*Cd + (1-f))D. By tweaking the source color's alpha
434 we're replacing S with S'=fS. It's obvious that that first term will always be ok. The second
435 term can be rearranged as [1-(1-Cd)f]D. By substituting in the various possibilities for Cd we
436 find that only 1, ISA, and ISC produce the correct destination when applied to S' and D.
437 Also, if we're directly rendering coverage (isCoverageDrawing) then coverage is treated as
438 color by definition.
439 */
440 return kOne_GrBlendCoeff == fDstBlend ||
441 kISA_GrBlendCoeff == fDstBlend ||
442 kISC_GrBlendCoeff == fDstBlend ||
443 this->isCoverageDrawing();
444}
445
446////////////////////////////////////////////////////////////////////////////////
447
bsalomon@google.com2fdcdeb2012-10-08 17:15:55 +0000448void GrDrawState::AutoViewMatrixRestore::restore() {
bsalomon49f085d2014-09-05 13:34:00 -0700449 if (fDrawState) {
commit-bot@chromium.org1acc3d72013-09-06 23:13:05 +0000450 SkDEBUGCODE(--fDrawState->fBlockEffectRemovalCnt;)
bsalomon2ed5ef82014-07-07 08:44:05 -0700451 fDrawState->fViewMatrix = fViewMatrix;
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000452 SkASSERT(fDrawState->numColorStages() >= fNumColorStages);
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000453 int numCoverageStages = fSavedCoordChanges.count() - fNumColorStages;
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000454 SkASSERT(fDrawState->numCoverageStages() >= numCoverageStages);
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000455
456 int i = 0;
457 for (int s = 0; s < fNumColorStages; ++s, ++i) {
egdaniel8cbf3d52014-08-21 06:27:22 -0700458 fDrawState->fColorStages[s].restoreCoordChange(fSavedCoordChanges[i]);
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000459 }
460 for (int s = 0; s < numCoverageStages; ++s, ++i) {
egdaniel8cbf3d52014-08-21 06:27:22 -0700461 fDrawState->fCoverageStages[s].restoreCoordChange(fSavedCoordChanges[i]);
bsalomon@google.com2fdcdeb2012-10-08 17:15:55 +0000462 }
bsalomon@google.com137f1342013-05-29 21:27:53 +0000463 fDrawState = NULL;
bsalomon@google.com2fdcdeb2012-10-08 17:15:55 +0000464 }
bsalomon@google.com2fdcdeb2012-10-08 17:15:55 +0000465}
466
467void GrDrawState::AutoViewMatrixRestore::set(GrDrawState* drawState,
bsalomon@google.comc7818882013-03-20 19:19:53 +0000468 const SkMatrix& preconcatMatrix) {
bsalomon@google.com2fdcdeb2012-10-08 17:15:55 +0000469 this->restore();
bsalomon@google.com5b3e8902012-10-05 20:13:28 +0000470
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000471 SkASSERT(NULL == fDrawState);
bsalomon@google.com137f1342013-05-29 21:27:53 +0000472 if (NULL == drawState || preconcatMatrix.isIdentity()) {
bsalomon@google.com2fdcdeb2012-10-08 17:15:55 +0000473 return;
474 }
bsalomon@google.com137f1342013-05-29 21:27:53 +0000475 fDrawState = drawState;
bsalomon@google.com2fdcdeb2012-10-08 17:15:55 +0000476
bsalomon@google.com2fdcdeb2012-10-08 17:15:55 +0000477 fViewMatrix = drawState->getViewMatrix();
bsalomon2ed5ef82014-07-07 08:44:05 -0700478 drawState->fViewMatrix.preConcat(preconcatMatrix);
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000479
480 this->doEffectCoordChanges(preconcatMatrix);
commit-bot@chromium.org1acc3d72013-09-06 23:13:05 +0000481 SkDEBUGCODE(++fDrawState->fBlockEffectRemovalCnt;)
bsalomon@google.com2fdcdeb2012-10-08 17:15:55 +0000482}
483
bsalomon@google.com137f1342013-05-29 21:27:53 +0000484bool GrDrawState::AutoViewMatrixRestore::setIdentity(GrDrawState* drawState) {
bsalomon@google.com2fdcdeb2012-10-08 17:15:55 +0000485 this->restore();
486
bsalomon@google.com137f1342013-05-29 21:27:53 +0000487 if (NULL == drawState) {
bsalomon@google.com2fdcdeb2012-10-08 17:15:55 +0000488 return false;
skia.committer@gmail.comf467ce72012-10-09 02:01:37 +0000489 }
bsalomon@google.com2fdcdeb2012-10-08 17:15:55 +0000490
bsalomon@google.com137f1342013-05-29 21:27:53 +0000491 if (drawState->getViewMatrix().isIdentity()) {
492 return true;
493 }
494
bsalomon@google.com5b3e8902012-10-05 20:13:28 +0000495 fViewMatrix = drawState->getViewMatrix();
joshualitt4dd99882014-11-11 08:51:30 -0800496 if (0 == drawState->numFragmentStages()) {
bsalomon2ed5ef82014-07-07 08:44:05 -0700497 drawState->fViewMatrix.reset();
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000498 fDrawState = drawState;
499 fNumColorStages = 0;
500 fSavedCoordChanges.reset(0);
commit-bot@chromium.org1acc3d72013-09-06 23:13:05 +0000501 SkDEBUGCODE(++fDrawState->fBlockEffectRemovalCnt;)
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000502 return true;
503 } else {
504 SkMatrix inv;
505 if (!fViewMatrix.invert(&inv)) {
506 return false;
bsalomon@google.com5b3e8902012-10-05 20:13:28 +0000507 }
bsalomon2ed5ef82014-07-07 08:44:05 -0700508 drawState->fViewMatrix.reset();
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000509 fDrawState = drawState;
510 this->doEffectCoordChanges(inv);
commit-bot@chromium.org1acc3d72013-09-06 23:13:05 +0000511 SkDEBUGCODE(++fDrawState->fBlockEffectRemovalCnt;)
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000512 return true;
bsalomon@google.com5b3e8902012-10-05 20:13:28 +0000513 }
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000514}
515
516void GrDrawState::AutoViewMatrixRestore::doEffectCoordChanges(const SkMatrix& coordChangeMatrix) {
joshualitt4dd99882014-11-11 08:51:30 -0800517 fSavedCoordChanges.reset(fDrawState->numFragmentStages());
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000518 int i = 0;
519
520 fNumColorStages = fDrawState->numColorStages();
521 for (int s = 0; s < fNumColorStages; ++s, ++i) {
egdaniel776bdbd2014-08-06 11:07:02 -0700522 fDrawState->getColorStage(s).saveCoordChange(&fSavedCoordChanges[i]);
egdaniel8cbf3d52014-08-21 06:27:22 -0700523 fDrawState->fColorStages[s].localCoordChange(coordChangeMatrix);
bsalomon@google.com137f1342013-05-29 21:27:53 +0000524 }
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000525
526 int numCoverageStages = fDrawState->numCoverageStages();
527 for (int s = 0; s < numCoverageStages; ++s, ++i) {
egdaniel776bdbd2014-08-06 11:07:02 -0700528 fDrawState->getCoverageStage(s).saveCoordChange(&fSavedCoordChanges[i]);
egdaniel8cbf3d52014-08-21 06:27:22 -0700529 fDrawState->fCoverageStages[s].localCoordChange(coordChangeMatrix);
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000530 }
bsalomon@google.com5b3e8902012-10-05 20:13:28 +0000531}
egdaniel21aed572014-08-26 12:24:06 -0700532
egdaniel170f90b2014-09-16 12:54:40 -0700533////////////////////////////////////////////////////////////////////////////////
534
egdaniel170f90b2014-09-16 12:54:40 -0700535GrDrawState::~GrDrawState() {
egdaniel170f90b2014-09-16 12:54:40 -0700536 SkASSERT(0 == fBlockEffectRemovalCnt);
537}
538
egdaniel89af44a2014-09-26 06:15:04 -0700539////////////////////////////////////////////////////////////////////////////////
540
541GrDrawState::BlendOptFlags GrDrawState::getBlendOpts(bool forceCoverage,
joshualitt65171342014-10-09 07:25:36 -0700542 GrBlendCoeff* srcCoeff,
543 GrBlendCoeff* dstCoeff) const {
egdaniel89af44a2014-09-26 06:15:04 -0700544 GrBlendCoeff bogusSrcCoeff, bogusDstCoeff;
545 if (NULL == srcCoeff) {
546 srcCoeff = &bogusSrcCoeff;
547 }
548 if (NULL == dstCoeff) {
549 dstCoeff = &bogusDstCoeff;
550 }
551
552 *srcCoeff = this->getSrcBlendCoeff();
553 *dstCoeff = this->getDstBlendCoeff();
554
555 if (this->isColorWriteDisabled()) {
556 *srcCoeff = kZero_GrBlendCoeff;
557 *dstCoeff = kOne_GrBlendCoeff;
558 }
559
560 bool srcAIsOne = this->srcAlphaWillBeOne();
561 bool dstCoeffIsOne = kOne_GrBlendCoeff == *dstCoeff ||
562 (kSA_GrBlendCoeff == *dstCoeff && srcAIsOne);
563 bool dstCoeffIsZero = kZero_GrBlendCoeff == *dstCoeff ||
564 (kISA_GrBlendCoeff == *dstCoeff && srcAIsOne);
565
566 // When coeffs are (0,1) there is no reason to draw at all, unless
567 // stenciling is enabled. Having color writes disabled is effectively
568 // (0,1).
569 if ((kZero_GrBlendCoeff == *srcCoeff && dstCoeffIsOne)) {
570 if (this->getStencil().doesWrite()) {
571 return kEmitCoverage_BlendOptFlag;
572 } else {
573 *dstCoeff = kOne_GrBlendCoeff;
574 return kSkipDraw_BlendOptFlag;
575 }
576 }
577
578 bool hasCoverage = forceCoverage || !this->hasSolidCoverage();
579
580 // if we don't have coverage we can check whether the dst
581 // has to read at all. If not, we'll disable blending.
582 if (!hasCoverage) {
583 if (dstCoeffIsZero) {
584 if (kOne_GrBlendCoeff == *srcCoeff) {
585 // if there is no coverage and coeffs are (1,0) then we
586 // won't need to read the dst at all, it gets replaced by src
587 *dstCoeff = kZero_GrBlendCoeff;
588 return kNone_BlendOpt;
589 } else if (kZero_GrBlendCoeff == *srcCoeff) {
590 // if the op is "clear" then we don't need to emit a color
591 // or blend, just write transparent black into the dst.
592 *srcCoeff = kOne_GrBlendCoeff;
593 *dstCoeff = kZero_GrBlendCoeff;
594 return kEmitTransBlack_BlendOptFlag;
595 }
596 }
597 } else if (this->isCoverageDrawing()) {
598 // we have coverage but we aren't distinguishing it from alpha by request.
599 return kCoverageAsAlpha_BlendOptFlag;
600 } else {
601 // check whether coverage can be safely rolled into alpha
602 // of if we can skip color computation and just emit coverage
603 if (this->canTweakAlphaForCoverage()) {
604 return kCoverageAsAlpha_BlendOptFlag;
605 }
606 if (dstCoeffIsZero) {
607 if (kZero_GrBlendCoeff == *srcCoeff) {
608 // the source color is not included in the blend
609 // the dst coeff is effectively zero so blend works out to:
610 // (c)(0)D + (1-c)D = (1-c)D.
611 *dstCoeff = kISA_GrBlendCoeff;
612 return kEmitCoverage_BlendOptFlag;
613 } else if (srcAIsOne) {
614 // the dst coeff is effectively zero so blend works out to:
615 // cS + (c)(0)D + (1-c)D = cS + (1-c)D.
616 // If Sa is 1 then we can replace Sa with c
617 // and set dst coeff to 1-Sa.
618 *dstCoeff = kISA_GrBlendCoeff;
619 return kCoverageAsAlpha_BlendOptFlag;
620 }
621 } else if (dstCoeffIsOne) {
622 // the dst coeff is effectively one so blend works out to:
623 // cS + (c)(1)D + (1-c)D = cS + D.
624 *dstCoeff = kOne_GrBlendCoeff;
625 return kCoverageAsAlpha_BlendOptFlag;
626 }
627 }
628
629 return kNone_BlendOpt;
630}
631
egdaniel89af44a2014-09-26 06:15:04 -0700632bool GrDrawState::srcAlphaWillBeOne() const {
egdanielb6cbc382014-11-13 11:00:34 -0800633 this->calcColorInvariantOutput();
egdaniel89af44a2014-09-26 06:15:04 -0700634 if (this->isCoverageDrawing()) {
egdanielb6cbc382014-11-13 11:00:34 -0800635 this->calcCoverageInvariantOutput();
636 return (fColorProcInfo.isOpaque() && fCoverageProcInfo.isOpaque());
egdaniel89af44a2014-09-26 06:15:04 -0700637 }
egdanielb6cbc382014-11-13 11:00:34 -0800638 return fColorProcInfo.isOpaque();
egdaniel89af44a2014-09-26 06:15:04 -0700639}
640
egdanielcd8b6302014-11-11 14:46:05 -0800641bool GrDrawState::willBlendWithDst() const {
642 if (!this->hasSolidCoverage()) {
643 return true;
644 }
645
egdanielb1cff032014-11-13 06:19:25 -0800646 if (this->willEffectReadDstColor()) {
647 return true;
egdanielcd8b6302014-11-11 14:46:05 -0800648 }
egdanielb1cff032014-11-13 06:19:25 -0800649
650 if (GrBlendCoeffRefsDst(this->getSrcBlendCoeff())) {
651 return true;
652 }
653
654 GrBlendCoeff dstCoeff = this->getDstBlendCoeff();
655 if (!(kZero_GrBlendCoeff == dstCoeff ||
656 (kISA_GrBlendCoeff == dstCoeff && this->srcAlphaWillBeOne()))) {
egdanielcd8b6302014-11-11 14:46:05 -0800657 return true;
658 }
659
660 return false;
661}
662
egdanielb6cbc382014-11-13 11:00:34 -0800663void GrDrawState::calcColorInvariantOutput() const {
664 if (!fColorProcInfoValid) {
665 GrColor color;
666 GrColorComponentFlags flags;
667 if (this->hasColorVertexAttribute()) {
668 if (fHints & kVertexColorsAreOpaque_Hint) {
669 flags = kA_GrColorComponentFlag;
670 color = 0xFF << GrColor_SHIFT_A;
671 } else {
672 flags = static_cast<GrColorComponentFlags>(0);
673 color = 0;
674 }
675 } else {
676 flags = kRGBA_GrColorComponentFlags;
677 color = this->getColor();
678 }
679 fColorProcInfo.calcWithInitialValues(fColorStages.begin(), this->numColorStages(),
680 color, flags, false);
681 fColorProcInfoValid = true;
682 }
683}
684
685void GrDrawState::calcCoverageInvariantOutput() const {
686 if (!fCoverageProcInfoValid) {
687 GrColor color;
688 GrColorComponentFlags flags;
689 // Check if per-vertex or constant color may have partial alpha
690 if (this->hasCoverageVertexAttribute()) {
691 flags = static_cast<GrColorComponentFlags>(0);
692 color = 0;
693 } else {
694 flags = kRGBA_GrColorComponentFlags;
695 color = this->getCoverageColor();
696 }
697 fCoverageProcInfo.calcWithInitialValues(fCoverageStages.begin(), this->numCoverageStages(),
698 color, flags, true, fGeometryProcessor.get());
699 fCoverageProcInfoValid = true;
700 }
701}
702