blob: 2cc50f7dc463c7a3c5511d3d278433275b414e55 [file] [log] [blame]
bsalomon@google.comaf84e742012-10-05 13:23:24 +00001/*
2 * Copyright 2012 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "GrDrawState.h"
bsalomon@google.comaf84e742012-10-05 13:23:24 +00009#include "GrPaint.h"
10
commit-bot@chromium.orgbb6a3172013-05-28 17:25:49 +000011void GrDrawState::setFromPaint(const GrPaint& paint, const SkMatrix& vm, GrRenderTarget* rt) {
bsalomon@google.com88becf42012-10-05 14:54:42 +000012 for (int i = 0; i < GrPaint::kMaxColorStages; ++i) {
13 int s = i + GrPaint::kFirstColorStage;
14 if (paint.isColorStageEnabled(i)) {
bsalomon@google.comadc65362013-01-28 14:26:09 +000015 fStages[s] = paint.getColorStage(i);
16 } else {
17 fStages[s].setEffect(NULL);
bsalomon@google.comaf84e742012-10-05 13:23:24 +000018 }
19 }
20
bsalomon@google.com88becf42012-10-05 14:54:42 +000021 this->setFirstCoverageStage(GrPaint::kFirstCoverageStage);
bsalomon@google.comaf84e742012-10-05 13:23:24 +000022
bsalomon@google.com88becf42012-10-05 14:54:42 +000023 for (int i = 0; i < GrPaint::kMaxCoverageStages; ++i) {
24 int s = i + GrPaint::kFirstCoverageStage;
25 if (paint.isCoverageStageEnabled(i)) {
bsalomon@google.comadc65362013-01-28 14:26:09 +000026 fStages[s] = paint.getCoverageStage(i);
27 } else {
28 fStages[s].setEffect(NULL);
bsalomon@google.comaf84e742012-10-05 13:23:24 +000029 }
30 }
31
32 // disable all stages not accessible via the paint
33 for (int s = GrPaint::kTotalStages; s < GrDrawState::kNumStages; ++s) {
34 this->disableStage(s);
35 }
36
commit-bot@chromium.orgbb6a3172013-05-28 17:25:49 +000037 this->setRenderTarget(rt);
bsalomon@google.comaf84e742012-10-05 13:23:24 +000038
commit-bot@chromium.orgbb6a3172013-05-28 17:25:49 +000039 fCommon.fViewMatrix = vm;
40
41 // These have no equivalent in GrPaint, set them to defaults
42 fCommon.fBlendConstant = 0x0;
43 fCommon.fCoverage = 0xffffffff;
44 fCommon.fDrawFace = kBoth_DrawFace;
45 fCommon.fStencilSettings.setDisabled();
46 this->resetStateFlags();
47
48 this->setColor(paint.getColor());
bsalomon@google.comc7448ce2012-10-05 19:04:13 +000049 this->setState(GrDrawState::kDither_StateBit, paint.isDither());
50 this->setState(GrDrawState::kHWAntialias_StateBit, paint.isAntiAlias());
bsalomon@google.comaf84e742012-10-05 13:23:24 +000051
bsalomon@google.comc7448ce2012-10-05 19:04:13 +000052 this->setBlendFunc(paint.getSrcBlendCoeff(), paint.getDstBlendCoeff());
53 this->setColorFilter(paint.getColorFilterColor(), paint.getColorFilterMode());
54 this->setCoverage(paint.getCoverage());
bsalomon@google.comaf84e742012-10-05 13:23:24 +000055}
bsalomon@google.com5b3e8902012-10-05 20:13:28 +000056
57////////////////////////////////////////////////////////////////////////////////
58
jvanverth@google.com9b855c72013-03-01 18:21:22 +000059static size_t vertex_size(const GrVertexAttrib* attribs, int count) {
60 // this works as long as we're 4 byte-aligned
61#if GR_DEBUG
62 uint32_t overlapCheck = 0;
63#endif
jvanverth@google.com054ae992013-04-01 20:06:51 +000064 GrAssert(count <= GrDrawState::kMaxVertexAttribCnt);
jvanverth@google.com9b855c72013-03-01 18:21:22 +000065 size_t size = 0;
66 for (int index = 0; index < count; ++index) {
jvanverth@google.com054ae992013-04-01 20:06:51 +000067 size_t attribSize = GrVertexAttribTypeSize(attribs[index].fType);
jvanverth@google.com9b855c72013-03-01 18:21:22 +000068 size += attribSize;
69#if GR_DEBUG
70 size_t dwordCount = attribSize >> 2;
71 uint32_t mask = (1 << dwordCount)-1;
72 size_t offsetShift = attribs[index].fOffset >> 2;
73 GrAssert(!(overlapCheck & (mask << offsetShift)));
74 overlapCheck |= (mask << offsetShift);
75#endif
jvanverth@google.comcc782382013-01-28 20:39:48 +000076 }
77 return size;
78}
79
jvanverth@google.com9b855c72013-03-01 18:21:22 +000080size_t GrDrawState::getVertexSize() const {
robertphillips@google.com42903302013-04-20 12:26:07 +000081 return vertex_size(fCommon.fVAPtr, fCommon.fVACount);
jvanverth@google.com9b855c72013-03-01 18:21:22 +000082}
83
jvanverth@google.comcc782382013-01-28 20:39:48 +000084////////////////////////////////////////////////////////////////////////////////
85
jvanverth@google.com9b855c72013-03-01 18:21:22 +000086void GrDrawState::setVertexAttribs(const GrVertexAttrib* attribs, int count) {
jvanverth@google.com054ae992013-04-01 20:06:51 +000087 GrAssert(count <= kMaxVertexAttribCnt);
robertphillips@google.com42903302013-04-20 12:26:07 +000088
89 fCommon.fVAPtr = attribs;
90 fCommon.fVACount = count;
jvanverth@google.com054ae992013-04-01 20:06:51 +000091
92 // Set all the indices to -1
93 memset(fCommon.fFixedFunctionVertexAttribIndices,
94 0xff,
95 sizeof(fCommon.fFixedFunctionVertexAttribIndices));
96#if GR_DEBUG
97 uint32_t overlapCheck = 0;
98#endif
99 for (int i = 0; i < count; ++i) {
100 if (attribs[i].fBinding < kGrFixedFunctionVertexAttribBindingCnt) {
101 // The fixed function attribs can only be specified once
102 GrAssert(-1 == fCommon.fFixedFunctionVertexAttribIndices[attribs[i].fBinding]);
103 GrAssert(GrFixedFunctionVertexAttribVectorCount(attribs[i].fBinding) ==
104 GrVertexAttribTypeVectorCount(attribs[i].fType));
105 fCommon.fFixedFunctionVertexAttribIndices[attribs[i].fBinding] = i;
106 }
107#if GR_DEBUG
108 size_t dwordCount = GrVertexAttribTypeSize(attribs[i].fType) >> 2;
109 uint32_t mask = (1 << dwordCount)-1;
110 size_t offsetShift = attribs[i].fOffset >> 2;
111 GrAssert(!(overlapCheck & (mask << offsetShift)));
112 overlapCheck |= (mask << offsetShift);
113#endif
jvanverth@google.comcc782382013-01-28 20:39:48 +0000114 }
jvanverth@google.com054ae992013-04-01 20:06:51 +0000115 // Positions must be specified.
116 GrAssert(-1 != fCommon.fFixedFunctionVertexAttribIndices[kPosition_GrVertexAttribBinding]);
jvanverth@google.comcc782382013-01-28 20:39:48 +0000117}
118
119////////////////////////////////////////////////////////////////////////////////
120
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000121void GrDrawState::setDefaultVertexAttribs() {
jvanverth@google.com054ae992013-04-01 20:06:51 +0000122 static const GrVertexAttrib kPositionAttrib =
123 {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding};
robertphillips@google.com42903302013-04-20 12:26:07 +0000124
125 fCommon.fVAPtr = &kPositionAttrib;
126 fCommon.fVACount = 1;
127
jvanverth@google.com054ae992013-04-01 20:06:51 +0000128 // set all the fixed function indices to -1 except position.
129 memset(fCommon.fFixedFunctionVertexAttribIndices,
130 0xff,
131 sizeof(fCommon.fFixedFunctionVertexAttribIndices));
132 fCommon.fFixedFunctionVertexAttribIndices[kPosition_GrVertexAttribBinding] = 0;
jvanverth@google.comcc782382013-01-28 20:39:48 +0000133}
134
135////////////////////////////////////////////////////////////////////////////////
136
commit-bot@chromium.orgff6ea262013-03-12 12:26:08 +0000137bool GrDrawState::validateVertexAttribs() const {
jvanverth@google.com054ae992013-04-01 20:06:51 +0000138 // check consistency of effects and attributes
139 GrSLType slTypes[kMaxVertexAttribCnt];
140 for (int i = 0; i < kMaxVertexAttribCnt; ++i) {
141 slTypes[i] = static_cast<GrSLType>(-1);
commit-bot@chromium.orgff6ea262013-03-12 12:26:08 +0000142 }
jvanverth@google.comc7bf2962013-04-01 19:29:32 +0000143 for (int s = 0; s < kNumStages; ++s) {
jvanverth@google.com054ae992013-04-01 20:06:51 +0000144 if (this->isStageEnabled(s)) {
145 const GrEffectStage& stage = fStages[s];
146 const GrEffectRef* effect = stage.getEffect();
147 // make sure that any attribute indices have the correct binding type, that the attrib
148 // type and effect's shader lang type are compatible, and that attributes shared by
149 // multiple effects use the same shader lang type.
150 const int* attributeIndices = stage.getVertexAttribIndices();
151 int numAttributes = stage.getVertexAttribIndexCount();
152 for (int i = 0; i < numAttributes; ++i) {
153 int attribIndex = attributeIndices[i];
robertphillips@google.com42903302013-04-20 12:26:07 +0000154 if (attribIndex >= fCommon.fVACount ||
155 kEffect_GrVertexAttribBinding != fCommon.fVAPtr[attribIndex].fBinding) {
jvanverth@google.com054ae992013-04-01 20:06:51 +0000156 return false;
157 }
jvanverth@google.comc7bf2962013-04-01 19:29:32 +0000158
jvanverth@google.com054ae992013-04-01 20:06:51 +0000159 GrSLType effectSLType = (*effect)->vertexAttribType(i);
robertphillips@google.com42903302013-04-20 12:26:07 +0000160 GrVertexAttribType attribType = fCommon.fVAPtr[attribIndex].fType;
jvanverth@google.com054ae992013-04-01 20:06:51 +0000161 int slVecCount = GrSLTypeVectorCount(effectSLType);
162 int attribVecCount = GrVertexAttribTypeVectorCount(attribType);
163 if (slVecCount != attribVecCount ||
skia.committer@gmail.com05a2ee02013-04-02 07:01:34 +0000164 (static_cast<GrSLType>(-1) != slTypes[attribIndex] &&
robertphillips@google.com2c5ddb62013-04-01 23:24:15 +0000165 slTypes[attribIndex] != effectSLType)) {
jvanverth@google.com054ae992013-04-01 20:06:51 +0000166 return false;
167 }
168 slTypes[attribIndex] = effectSLType;
jvanverth@google.comc7bf2962013-04-01 19:29:32 +0000169 }
commit-bot@chromium.orgff6ea262013-03-12 12:26:08 +0000170 }
171 }
172
173 return true;
174}
175
bsalomon@google.comd09ab842013-05-15 17:30:26 +0000176bool GrDrawState::willEffectReadDstColor() const {
177 int startStage = this->isColorWriteDisabled() ? this->getFirstCoverageStage() : 0;
178 for (int s = startStage; s < kNumStages; ++s) {
179 if (this->isStageEnabled(s) && (*this->getStage(s).getEffect())->willReadDstColor()) {
180 return true;
181 }
182 }
183 return false;
184}
185
jvanverth@google.comcc782382013-01-28 20:39:48 +0000186////////////////////////////////////////////////////////////////////////////////
187
jvanverth@google.com054ae992013-04-01 20:06:51 +0000188bool GrDrawState::srcAlphaWillBeOne() const {
jvanverth@google.comcc782382013-01-28 20:39:48 +0000189 uint32_t validComponentFlags;
bsalomon@google.com89e6f5b2013-02-27 18:43:47 +0000190 GrColor color;
jvanverth@google.comcc782382013-01-28 20:39:48 +0000191 // Check if per-vertex or constant color may have partial alpha
jvanverth@google.com054ae992013-04-01 20:06:51 +0000192 if (this->hasColorVertexAttribute()) {
jvanverth@google.comcc782382013-01-28 20:39:48 +0000193 validComponentFlags = 0;
bsalomon@google.com89e6f5b2013-02-27 18:43:47 +0000194 color = 0; // not strictly necessary but we get false alarms from tools about uninit.
jvanverth@google.comcc782382013-01-28 20:39:48 +0000195 } else {
bsalomon@google.comb8eb2e82013-03-28 13:46:42 +0000196 validComponentFlags = kRGBA_GrColorComponentFlags;
jvanverth@google.comcc782382013-01-28 20:39:48 +0000197 color = this->getColor();
198 }
199
200 // Run through the color stages
201 int stageCnt = getFirstCoverageStage();
202 for (int s = 0; s < stageCnt; ++s) {
203 const GrEffectRef* effect = this->getStage(s).getEffect();
204 if (NULL != effect) {
205 (*effect)->getConstantColorComponents(&color, &validComponentFlags);
206 }
207 }
208
209 // Check if the color filter could introduce an alpha.
210 // We could skip the above work when this is true, but it is rare and the right fix is to make
211 // the color filter a GrEffect and implement getConstantColorComponents() for it.
212 if (SkXfermode::kDst_Mode != this->getColorFilterMode()) {
213 validComponentFlags = 0;
214 }
215
216 // Check whether coverage is treated as color. If so we run through the coverage computation.
217 if (this->isCoverageDrawing()) {
218 GrColor coverageColor = this->getCoverage();
219 GrColor oldColor = color;
220 color = 0;
221 for (int c = 0; c < 4; ++c) {
222 if (validComponentFlags & (1 << c)) {
223 U8CPU a = (oldColor >> (c * 8)) & 0xff;
224 U8CPU b = (coverageColor >> (c * 8)) & 0xff;
225 color |= (SkMulDiv255Round(a, b) << (c * 8));
226 }
227 }
228 for (int s = this->getFirstCoverageStage(); s < GrDrawState::kNumStages; ++s) {
229 const GrEffectRef* effect = this->getStage(s).getEffect();
230 if (NULL != effect) {
231 (*effect)->getConstantColorComponents(&color, &validComponentFlags);
232 }
233 }
234 }
bsalomon@google.comb8eb2e82013-03-28 13:46:42 +0000235 return (kA_GrColorComponentFlag & validComponentFlags) && 0xff == GrColorUnpackA(color);
jvanverth@google.comcc782382013-01-28 20:39:48 +0000236}
237
jvanverth@google.com054ae992013-04-01 20:06:51 +0000238bool GrDrawState::hasSolidCoverage() const {
bsalomon@google.comd62e88e2013-02-01 14:19:27 +0000239 // If we're drawing coverage directly then coverage is effectively treated as color.
240 if (this->isCoverageDrawing()) {
241 return true;
242 }
243
244 GrColor coverage;
245 uint32_t validComponentFlags;
246 // Initialize to an unknown starting coverage if per-vertex coverage is specified.
jvanverth@google.com054ae992013-04-01 20:06:51 +0000247 if (this->hasCoverageVertexAttribute()) {
bsalomon@google.comd62e88e2013-02-01 14:19:27 +0000248 validComponentFlags = 0;
249 } else {
250 coverage = fCommon.fCoverage;
bsalomon@google.comb8eb2e82013-03-28 13:46:42 +0000251 validComponentFlags = kRGBA_GrColorComponentFlags;
bsalomon@google.comd62e88e2013-02-01 14:19:27 +0000252 }
253
254 // Run through the coverage stages and see if the coverage will be all ones at the end.
255 for (int s = this->getFirstCoverageStage(); s < GrDrawState::kNumStages; ++s) {
256 const GrEffectRef* effect = this->getStage(s).getEffect();
257 if (NULL != effect) {
258 (*effect)->getConstantColorComponents(&coverage, &validComponentFlags);
259 }
260 }
bsalomon@google.comb8eb2e82013-03-28 13:46:42 +0000261 return (kRGBA_GrColorComponentFlags == validComponentFlags) && (0xffffffff == coverage);
bsalomon@google.comd62e88e2013-02-01 14:19:27 +0000262}
263
jvanverth@google.comcc782382013-01-28 20:39:48 +0000264////////////////////////////////////////////////////////////////////////////////
265
bsalomon@google.com2b446732013-02-12 16:47:41 +0000266// Some blend modes allow folding a fractional coverage value into the color's alpha channel, while
267// others will blend incorrectly.
268bool GrDrawState::canTweakAlphaForCoverage() const {
269 /*
270 The fractional coverage is f.
271 The src and dst coeffs are Cs and Cd.
272 The dst and src colors are S and D.
273 We want the blend to compute: f*Cs*S + (f*Cd + (1-f))D. By tweaking the source color's alpha
274 we're replacing S with S'=fS. It's obvious that that first term will always be ok. The second
275 term can be rearranged as [1-(1-Cd)f]D. By substituting in the various possibilities for Cd we
276 find that only 1, ISA, and ISC produce the correct destination when applied to S' and D.
277 Also, if we're directly rendering coverage (isCoverageDrawing) then coverage is treated as
278 color by definition.
279 */
280 return kOne_GrBlendCoeff == fCommon.fDstBlend ||
281 kISA_GrBlendCoeff == fCommon.fDstBlend ||
282 kISC_GrBlendCoeff == fCommon.fDstBlend ||
283 this->isCoverageDrawing();
284}
285
286GrDrawState::BlendOptFlags GrDrawState::getBlendOpts(bool forceCoverage,
287 GrBlendCoeff* srcCoeff,
288 GrBlendCoeff* dstCoeff) const {
bsalomon@google.com2b446732013-02-12 16:47:41 +0000289
290 GrBlendCoeff bogusSrcCoeff, bogusDstCoeff;
291 if (NULL == srcCoeff) {
292 srcCoeff = &bogusSrcCoeff;
293 }
294 *srcCoeff = this->getSrcBlendCoeff();
295
296 if (NULL == dstCoeff) {
297 dstCoeff = &bogusDstCoeff;
298 }
299 *dstCoeff = this->getDstBlendCoeff();
300
301 if (this->isColorWriteDisabled()) {
302 *srcCoeff = kZero_GrBlendCoeff;
303 *dstCoeff = kOne_GrBlendCoeff;
304 }
305
jvanverth@google.com054ae992013-04-01 20:06:51 +0000306 bool srcAIsOne = this->srcAlphaWillBeOne();
bsalomon@google.com2b446732013-02-12 16:47:41 +0000307 bool dstCoeffIsOne = kOne_GrBlendCoeff == *dstCoeff ||
308 (kSA_GrBlendCoeff == *dstCoeff && srcAIsOne);
309 bool dstCoeffIsZero = kZero_GrBlendCoeff == *dstCoeff ||
310 (kISA_GrBlendCoeff == *dstCoeff && srcAIsOne);
311
312 bool covIsZero = !this->isCoverageDrawing() &&
jvanverth@google.com054ae992013-04-01 20:06:51 +0000313 !this->hasCoverageVertexAttribute() &&
bsalomon@google.com2b446732013-02-12 16:47:41 +0000314 0 == this->getCoverage();
315 // When coeffs are (0,1) there is no reason to draw at all, unless
316 // stenciling is enabled. Having color writes disabled is effectively
317 // (0,1). The same applies when coverage is known to be 0.
318 if ((kZero_GrBlendCoeff == *srcCoeff && dstCoeffIsOne) || covIsZero) {
319 if (this->getStencil().doesWrite()) {
320 return kDisableBlend_BlendOptFlag |
321 kEmitTransBlack_BlendOptFlag;
322 } else {
323 return kSkipDraw_BlendOptFlag;
324 }
325 }
326
bsalomon@google.com4647f902013-03-26 14:45:27 +0000327 // check for coverage due to constant coverage, per-vertex coverage, or coverage stage
bsalomon@google.com2b446732013-02-12 16:47:41 +0000328 bool hasCoverage = forceCoverage ||
329 0xffffffff != this->getCoverage() ||
jvanverth@google.com054ae992013-04-01 20:06:51 +0000330 this->hasCoverageVertexAttribute();
331 for (int s = this->getFirstCoverageStage(); !hasCoverage && s < GrDrawState::kNumStages; ++s) {
bsalomon@google.com2b446732013-02-12 16:47:41 +0000332 if (this->isStageEnabled(s)) {
333 hasCoverage = true;
334 }
335 }
336
337 // if we don't have coverage we can check whether the dst
338 // has to read at all. If not, we'll disable blending.
339 if (!hasCoverage) {
340 if (dstCoeffIsZero) {
341 if (kOne_GrBlendCoeff == *srcCoeff) {
342 // if there is no coverage and coeffs are (1,0) then we
343 // won't need to read the dst at all, it gets replaced by src
344 return kDisableBlend_BlendOptFlag;
345 } else if (kZero_GrBlendCoeff == *srcCoeff) {
346 // if the op is "clear" then we don't need to emit a color
347 // or blend, just write transparent black into the dst.
348 *srcCoeff = kOne_GrBlendCoeff;
349 *dstCoeff = kZero_GrBlendCoeff;
350 return kDisableBlend_BlendOptFlag | kEmitTransBlack_BlendOptFlag;
351 }
352 }
353 } else if (this->isCoverageDrawing()) {
354 // we have coverage but we aren't distinguishing it from alpha by request.
355 return kCoverageAsAlpha_BlendOptFlag;
356 } else {
357 // check whether coverage can be safely rolled into alpha
358 // of if we can skip color computation and just emit coverage
359 if (this->canTweakAlphaForCoverage()) {
360 return kCoverageAsAlpha_BlendOptFlag;
361 }
362 if (dstCoeffIsZero) {
363 if (kZero_GrBlendCoeff == *srcCoeff) {
364 // the source color is not included in the blend
365 // the dst coeff is effectively zero so blend works out to:
366 // (c)(0)D + (1-c)D = (1-c)D.
367 *dstCoeff = kISA_GrBlendCoeff;
368 return kEmitCoverage_BlendOptFlag;
369 } else if (srcAIsOne) {
370 // the dst coeff is effectively zero so blend works out to:
371 // cS + (c)(0)D + (1-c)D = cS + (1-c)D.
372 // If Sa is 1 then we can replace Sa with c
373 // and set dst coeff to 1-Sa.
374 *dstCoeff = kISA_GrBlendCoeff;
375 return kCoverageAsAlpha_BlendOptFlag;
376 }
377 } else if (dstCoeffIsOne) {
378 // the dst coeff is effectively one so blend works out to:
379 // cS + (c)(1)D + (1-c)D = cS + D.
380 *dstCoeff = kOne_GrBlendCoeff;
381 return kCoverageAsAlpha_BlendOptFlag;
382 }
383 }
bsalomon@google.com0c89db22013-05-15 17:53:04 +0000384 if (kOne_GrBlendCoeff == *srcCoeff &&
385 kZero_GrBlendCoeff == *dstCoeff &&
386 this->willEffectReadDstColor()) {
387 // In this case the shader will fully resolve the color, coverage, and dst and we don't
388 // need blending.
389 return kDisableBlend_BlendOptFlag;
390 }
bsalomon@google.com2b446732013-02-12 16:47:41 +0000391 return kNone_BlendOpt;
392}
393
394////////////////////////////////////////////////////////////////////////////////
395
bsalomon@google.com2fdcdeb2012-10-08 17:15:55 +0000396void GrDrawState::AutoViewMatrixRestore::restore() {
397 if (NULL != fDrawState) {
398 fDrawState->setViewMatrix(fViewMatrix);
399 for (int s = 0; s < GrDrawState::kNumStages; ++s) {
400 if (fRestoreMask & (1 << s)) {
bsalomon@google.comadc65362013-01-28 14:26:09 +0000401 fDrawState->fStages[s].restoreCoordChange(fSavedCoordChanges[s]);
bsalomon@google.com2fdcdeb2012-10-08 17:15:55 +0000402 }
403 }
404 }
405 fDrawState = NULL;
406}
407
408void GrDrawState::AutoViewMatrixRestore::set(GrDrawState* drawState,
bsalomon@google.comc7818882013-03-20 19:19:53 +0000409 const SkMatrix& preconcatMatrix) {
bsalomon@google.com2fdcdeb2012-10-08 17:15:55 +0000410 this->restore();
bsalomon@google.com5b3e8902012-10-05 20:13:28 +0000411
412 fDrawState = drawState;
bsalomon@google.com2fdcdeb2012-10-08 17:15:55 +0000413 if (NULL == drawState) {
414 return;
415 }
416
417 fRestoreMask = 0;
418 fViewMatrix = drawState->getViewMatrix();
419 drawState->preConcatViewMatrix(preconcatMatrix);
420 for (int s = 0; s < GrDrawState::kNumStages; ++s) {
bsalomon@google.comc7818882013-03-20 19:19:53 +0000421 if (drawState->isStageEnabled(s)) {
bsalomon@google.com2fdcdeb2012-10-08 17:15:55 +0000422 fRestoreMask |= (1 << s);
bsalomon@google.comadc65362013-01-28 14:26:09 +0000423 fDrawState->fStages[s].saveCoordChange(&fSavedCoordChanges[s]);
bsalomon@google.comc7818882013-03-20 19:19:53 +0000424 drawState->fStages[s].localCoordChange(preconcatMatrix);
bsalomon@google.com2fdcdeb2012-10-08 17:15:55 +0000425 }
426 }
427}
428
429////////////////////////////////////////////////////////////////////////////////
430
431void GrDrawState::AutoDeviceCoordDraw::restore() {
432 if (NULL != fDrawState) {
433 fDrawState->setViewMatrix(fViewMatrix);
434 for (int s = 0; s < GrDrawState::kNumStages; ++s) {
435 if (fRestoreMask & (1 << s)) {
bsalomon@google.comadc65362013-01-28 14:26:09 +0000436 fDrawState->fStages[s].restoreCoordChange(fSavedCoordChanges[s]);
bsalomon@google.com2fdcdeb2012-10-08 17:15:55 +0000437 }
438 }
439 }
440 fDrawState = NULL;
441}
442
bsalomon@google.comc7818882013-03-20 19:19:53 +0000443bool GrDrawState::AutoDeviceCoordDraw::set(GrDrawState* drawState) {
bsalomon@google.com2fdcdeb2012-10-08 17:15:55 +0000444 GrAssert(NULL != drawState);
445
446 this->restore();
447
448 fDrawState = drawState;
449 if (NULL == fDrawState) {
450 return false;
skia.committer@gmail.comf467ce72012-10-09 02:01:37 +0000451 }
bsalomon@google.com2fdcdeb2012-10-08 17:15:55 +0000452
bsalomon@google.com5b3e8902012-10-05 20:13:28 +0000453 fViewMatrix = drawState->getViewMatrix();
454 fRestoreMask = 0;
bsalomon@google.comb9086a02012-11-01 18:02:54 +0000455 SkMatrix invVM;
bsalomon@google.com5b3e8902012-10-05 20:13:28 +0000456 bool inverted = false;
457
458 for (int s = 0; s < GrDrawState::kNumStages; ++s) {
bsalomon@google.comc7818882013-03-20 19:19:53 +0000459 if (drawState->isStageEnabled(s)) {
bsalomon@google.com5b3e8902012-10-05 20:13:28 +0000460 if (!inverted && !fViewMatrix.invert(&invVM)) {
461 // sad trombone sound
462 fDrawState = NULL;
bsalomon@google.com2fdcdeb2012-10-08 17:15:55 +0000463 return false;
bsalomon@google.com5b3e8902012-10-05 20:13:28 +0000464 } else {
465 inverted = true;
466 }
467 fRestoreMask |= (1 << s);
bsalomon@google.comadc65362013-01-28 14:26:09 +0000468 GrEffectStage* stage = drawState->fStages + s;
bsalomon@google.com08283af2012-10-26 13:01:20 +0000469 stage->saveCoordChange(&fSavedCoordChanges[s]);
bsalomon@google.comc7818882013-03-20 19:19:53 +0000470 stage->localCoordChange(invVM);
bsalomon@google.com5b3e8902012-10-05 20:13:28 +0000471 }
472 }
473 drawState->viewMatrix()->reset();
bsalomon@google.com2fdcdeb2012-10-08 17:15:55 +0000474 return true;
bsalomon@google.com5b3e8902012-10-05 20:13:28 +0000475}