blob: 6b00913036cc97232c8ea45b0475b97677e6276a [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
11void GrDrawState::setFromPaint(const GrPaint& paint) {
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
bsalomon@google.comc7448ce2012-10-05 19:04:13 +000037 this->setColor(paint.getColor());
bsalomon@google.comaf84e742012-10-05 13:23:24 +000038
bsalomon@google.comc7448ce2012-10-05 19:04:13 +000039 this->setState(GrDrawState::kDither_StateBit, paint.isDither());
40 this->setState(GrDrawState::kHWAntialias_StateBit, paint.isAntiAlias());
bsalomon@google.comaf84e742012-10-05 13:23:24 +000041
bsalomon@google.comc7448ce2012-10-05 19:04:13 +000042 this->setBlendFunc(paint.getSrcBlendCoeff(), paint.getDstBlendCoeff());
43 this->setColorFilter(paint.getColorFilterColor(), paint.getColorFilterMode());
44 this->setCoverage(paint.getCoverage());
bsalomon@google.comaf84e742012-10-05 13:23:24 +000045}
bsalomon@google.com5b3e8902012-10-05 20:13:28 +000046
47////////////////////////////////////////////////////////////////////////////////
48
jvanverth@google.comcc782382013-01-28 20:39:48 +000049namespace {
50
51/**
jvanverth@google.com39768252013-02-14 15:25:44 +000052 * This function generates a mask that we like to have known at compile
skia.committer@gmail.com044679e2013-02-15 07:16:57 +000053 * time. When the number of stages is bumped or the way bits are defined in
54 * GrDrawState.h changes this function should be rerun to generate the new mask.
55 * (We attempted to force the compiler to generate the mask using recursive
56 * templates but always wound up with static initializers under gcc, even if
jvanverth@google.com39768252013-02-14 15:25:44 +000057 * they were just a series of immediate->memory moves.)
jvanverth@google.comcc782382013-01-28 20:39:48 +000058 *
59 */
jvanverth@google.com9b855c72013-03-01 18:21:22 +000060void gen_tex_coord_mask(GrAttribBindings* texCoordMask) {
jvanverth@google.com39768252013-02-14 15:25:44 +000061 *texCoordMask = 0;
jvanverth@google.comcc782382013-01-28 20:39:48 +000062 for (int s = 0; s < GrDrawState::kNumStages; ++s) {
jvanverth@google.com9b855c72013-03-01 18:21:22 +000063 *texCoordMask |= GrDrawState::ExplicitTexCoordAttribBindingsBit(s);
jvanverth@google.comcc782382013-01-28 20:39:48 +000064 }
65}
66
jvanverth@google.com9b855c72013-03-01 18:21:22 +000067const GrAttribBindings kTexCoord_AttribBindingsMask = (1 << GrDrawState::kNumStages)-1;
jvanverth@google.comcc782382013-01-28 20:39:48 +000068
69} //unnamed namespace
70
jvanverth@google.com9b855c72013-03-01 18:21:22 +000071const size_t GrDrawState::kVertexAttribSizes[kGrVertexAttribTypeCount] = {
72 sizeof(float), // kFloat_GrVertexAttribType
73 2*sizeof(float), // kVec2_GrVertexAttribType
74 3*sizeof(float), // kVec3_GrVertexAttribType
75 4*sizeof(float), // kVec4_GrVertexAttribType
76 4*sizeof(char) // kCVec4_GrVertexAttribType
77};
bsalomon@google.com85983282013-02-07 22:00:29 +000078
jvanverth@google.com9b855c72013-03-01 18:21:22 +000079static size_t vertex_size(const GrVertexAttrib* attribs, int count) {
80 // this works as long as we're 4 byte-aligned
81#if GR_DEBUG
82 uint32_t overlapCheck = 0;
83#endif
84 GrAssert(count <= GrDrawState::kAttribIndexCount);
85 size_t size = 0;
86 for (int index = 0; index < count; ++index) {
87 size_t attribSize = GrDrawState::kVertexAttribSizes[attribs[index].fType];
88 size += attribSize;
89#if GR_DEBUG
90 size_t dwordCount = attribSize >> 2;
91 uint32_t mask = (1 << dwordCount)-1;
92 size_t offsetShift = attribs[index].fOffset >> 2;
93 GrAssert(!(overlapCheck & (mask << offsetShift)));
94 overlapCheck |= (mask << offsetShift);
95#endif
jvanverth@google.comcc782382013-01-28 20:39:48 +000096 }
97 return size;
98}
99
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000100size_t GrDrawState::getVertexSize() const {
101 return vertex_size(fVertexAttribs.begin(), fVertexAttribs.count());
102}
103
104const GrAttribBindings GrDrawState::kAttribIndexMasks[kAttribIndexCount] = {
105 0, // position is not reflected in the bindings
106 kColor_AttribBindingsBit,
107 kCoverage_AttribBindingsBit,
108 kEdge_AttribBindingsBit,
109 kTexCoord_AttribBindingsMask
110};
111
jvanverth@google.comcc782382013-01-28 20:39:48 +0000112////////////////////////////////////////////////////////////////////////////////
113
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000114void GrDrawState::setVertexAttribs(const GrVertexAttrib* attribs, int count) {
115 GrAssert(count <= GrDrawState::kAttribIndexCount);
116 fVertexAttribs.reset();
117 for (int index = 0; index < count; ++index) {
118 fVertexAttribs.push_back(attribs[index]);
jvanverth@google.comcc782382013-01-28 20:39:48 +0000119 }
jvanverth@google.comcc782382013-01-28 20:39:48 +0000120}
121
122////////////////////////////////////////////////////////////////////////////////
123
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000124void GrDrawState::setDefaultVertexAttribs() {
125 fVertexAttribs.reset();
126 fVertexAttribs.push_back(GrVertexAttrib(kVec2f_GrVertexAttribType, 0));
127
128 fCommon.fAttribBindings = kDefault_AttribBindings;
129
130 fAttribIndices[kPosition_AttribIndex] = 0;
jvanverth@google.comcc782382013-01-28 20:39:48 +0000131}
132
133////////////////////////////////////////////////////////////////////////////////
134
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000135bool GrDrawState::AttributesBindExplicitTexCoords(GrAttribBindings attribBindings) {
136 return SkToBool(kTexCoord_AttribBindingsMask & attribBindings);
137}
138
139////////////////////////////////////////////////////////////////////////////////
140
141void GrDrawState::VertexAttributesUnitTest() {
jvanverth@google.com39768252013-02-14 15:25:44 +0000142 // Ensure that our tex coord mask is correct
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000143 GrAttribBindings texCoordMask;
jvanverth@google.com39768252013-02-14 15:25:44 +0000144 gen_tex_coord_mask(&texCoordMask);
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000145 GrAssert(texCoordMask == kTexCoord_AttribBindingsMask);
jvanverth@google.comcc782382013-01-28 20:39:48 +0000146
147 // not necessarily exhaustive
148 static bool run;
149 if (!run) {
150 run = true;
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000151
152 GrVertexAttribArray<6> attribs;
153 GrAssert(0 == vertex_size(attribs.begin(), attribs.count()));
154
155 attribs.push_back(GrVertexAttrib(kFloat_GrVertexAttribType, 0));
156 GrAssert(sizeof(float) == vertex_size(attribs.begin(), attribs.count()));
157 attribs[0].fType = kVec2f_GrVertexAttribType;
158 GrAssert(2*sizeof(float) == vertex_size(attribs.begin(), attribs.count()));
159 attribs[0].fType = kVec3f_GrVertexAttribType;
160 GrAssert(3*sizeof(float) == vertex_size(attribs.begin(), attribs.count()));
161 attribs[0].fType = kVec4f_GrVertexAttribType;
162 GrAssert(4*sizeof(float) == vertex_size(attribs.begin(), attribs.count()));
163 attribs[0].fType = kVec4ub_GrVertexAttribType;
164 GrAssert(4*sizeof(char) == vertex_size(attribs.begin(), attribs.count()));
165
166 attribs.push_back(GrVertexAttrib(kVec2f_GrVertexAttribType, attribs[0].fOffset + 4*sizeof(char)));
167 GrAssert(4*sizeof(char) + 2*sizeof(float) == vertex_size(attribs.begin(), attribs.count()));
168 attribs.push_back(GrVertexAttrib(kVec3f_GrVertexAttribType, attribs[1].fOffset + 2*sizeof(float)));
169 GrAssert(4*sizeof(char) + 2*sizeof(float) + 3*sizeof(float) ==
170 vertex_size(attribs.begin(), attribs.count()));
171 attribs.push_back(GrVertexAttrib(kFloat_GrVertexAttribType, attribs[2].fOffset + 3*sizeof(float)));
172 GrAssert(4*sizeof(char) + 2*sizeof(float) + 3*sizeof(float) + sizeof(float) ==
173 vertex_size(attribs.begin(), attribs.count()));
174 attribs.push_back(GrVertexAttrib(kVec4f_GrVertexAttribType, attribs[3].fOffset + sizeof(float)));
175 GrAssert(4*sizeof(char) + 2*sizeof(float) + 3*sizeof(float) + sizeof(float) + 4*sizeof(float) ==
176 vertex_size(attribs.begin(), attribs.count()));
177
178 GrAttribBindings tcMask = 0;
179 GrAssert(!AttributesBindExplicitTexCoords(0));
jvanverth@google.comcc782382013-01-28 20:39:48 +0000180 for (int s = 0; s < GrDrawState::kNumStages; ++s) {
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000181 tcMask |= ExplicitTexCoordAttribBindingsBit(s);
182 GrAssert(AttributesBindExplicitTexCoords(tcMask));
183 GrAssert(StageBindsExplicitTexCoords(tcMask, s));
jvanverth@google.com39768252013-02-14 15:25:44 +0000184 for (int s2 = s + 1; s2 < GrDrawState::kNumStages; ++s2) {
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000185 GrAssert(!StageBindsExplicitTexCoords(tcMask, s2));
jvanverth@google.comcc782382013-01-28 20:39:48 +0000186 }
jvanverth@google.comcc782382013-01-28 20:39:48 +0000187 }
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000188 GrAssert(kTexCoord_AttribBindingsMask == tcMask);
jvanverth@google.comcc782382013-01-28 20:39:48 +0000189 }
190}
191
192////////////////////////////////////////////////////////////////////////////////
193
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000194bool GrDrawState::StageBindsExplicitTexCoords(GrAttribBindings bindings, int stageIdx) {
195 return SkToBool(bindings & ExplicitTexCoordAttribBindingsBit(stageIdx));
jvanverth@google.comcc782382013-01-28 20:39:48 +0000196}
197
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000198bool GrDrawState::srcAlphaWillBeOne(GrAttribBindings bindings) const {
jvanverth@google.comcc782382013-01-28 20:39:48 +0000199
200 uint32_t validComponentFlags;
bsalomon@google.com89e6f5b2013-02-27 18:43:47 +0000201 GrColor color;
jvanverth@google.comcc782382013-01-28 20:39:48 +0000202 // Check if per-vertex or constant color may have partial alpha
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000203 if (bindings & kColor_AttribBindingsBit) {
jvanverth@google.comcc782382013-01-28 20:39:48 +0000204 validComponentFlags = 0;
bsalomon@google.com89e6f5b2013-02-27 18:43:47 +0000205 color = 0; // not strictly necessary but we get false alarms from tools about uninit.
jvanverth@google.comcc782382013-01-28 20:39:48 +0000206 } else {
207 validComponentFlags = GrEffect::kAll_ValidComponentFlags;
208 color = this->getColor();
209 }
210
211 // Run through the color stages
212 int stageCnt = getFirstCoverageStage();
213 for (int s = 0; s < stageCnt; ++s) {
214 const GrEffectRef* effect = this->getStage(s).getEffect();
215 if (NULL != effect) {
216 (*effect)->getConstantColorComponents(&color, &validComponentFlags);
217 }
218 }
219
220 // Check if the color filter could introduce an alpha.
221 // We could skip the above work when this is true, but it is rare and the right fix is to make
222 // the color filter a GrEffect and implement getConstantColorComponents() for it.
223 if (SkXfermode::kDst_Mode != this->getColorFilterMode()) {
224 validComponentFlags = 0;
225 }
226
227 // Check whether coverage is treated as color. If so we run through the coverage computation.
228 if (this->isCoverageDrawing()) {
229 GrColor coverageColor = this->getCoverage();
230 GrColor oldColor = color;
231 color = 0;
232 for (int c = 0; c < 4; ++c) {
233 if (validComponentFlags & (1 << c)) {
234 U8CPU a = (oldColor >> (c * 8)) & 0xff;
235 U8CPU b = (coverageColor >> (c * 8)) & 0xff;
236 color |= (SkMulDiv255Round(a, b) << (c * 8));
237 }
238 }
239 for (int s = this->getFirstCoverageStage(); s < GrDrawState::kNumStages; ++s) {
240 const GrEffectRef* effect = this->getStage(s).getEffect();
241 if (NULL != effect) {
242 (*effect)->getConstantColorComponents(&color, &validComponentFlags);
243 }
244 }
245 }
246 return (GrEffect::kA_ValidComponentFlag & validComponentFlags) && 0xff == GrColorUnpackA(color);
247}
248
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000249bool GrDrawState::hasSolidCoverage(GrAttribBindings bindings) const {
bsalomon@google.comd62e88e2013-02-01 14:19:27 +0000250 // If we're drawing coverage directly then coverage is effectively treated as color.
251 if (this->isCoverageDrawing()) {
252 return true;
253 }
254
255 GrColor coverage;
256 uint32_t validComponentFlags;
257 // Initialize to an unknown starting coverage if per-vertex coverage is specified.
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000258 if (bindings & kCoverage_AttribBindingsBit) {
bsalomon@google.comd62e88e2013-02-01 14:19:27 +0000259 validComponentFlags = 0;
260 } else {
261 coverage = fCommon.fCoverage;
262 validComponentFlags = GrEffect::kAll_ValidComponentFlags;
263 }
264
265 // Run through the coverage stages and see if the coverage will be all ones at the end.
266 for (int s = this->getFirstCoverageStage(); s < GrDrawState::kNumStages; ++s) {
267 const GrEffectRef* effect = this->getStage(s).getEffect();
268 if (NULL != effect) {
269 (*effect)->getConstantColorComponents(&coverage, &validComponentFlags);
270 }
271 }
272 return (GrEffect::kAll_ValidComponentFlags == validComponentFlags) && (0xffffffff == coverage);
273}
274
jvanverth@google.comcc782382013-01-28 20:39:48 +0000275////////////////////////////////////////////////////////////////////////////////
276
bsalomon@google.com2b446732013-02-12 16:47:41 +0000277// Some blend modes allow folding a fractional coverage value into the color's alpha channel, while
278// others will blend incorrectly.
279bool GrDrawState::canTweakAlphaForCoverage() const {
280 /*
281 The fractional coverage is f.
282 The src and dst coeffs are Cs and Cd.
283 The dst and src colors are S and D.
284 We want the blend to compute: f*Cs*S + (f*Cd + (1-f))D. By tweaking the source color's alpha
285 we're replacing S with S'=fS. It's obvious that that first term will always be ok. The second
286 term can be rearranged as [1-(1-Cd)f]D. By substituting in the various possibilities for Cd we
287 find that only 1, ISA, and ISC produce the correct destination when applied to S' and D.
288 Also, if we're directly rendering coverage (isCoverageDrawing) then coverage is treated as
289 color by definition.
290 */
291 return kOne_GrBlendCoeff == fCommon.fDstBlend ||
292 kISA_GrBlendCoeff == fCommon.fDstBlend ||
293 kISC_GrBlendCoeff == fCommon.fDstBlend ||
294 this->isCoverageDrawing();
295}
296
297GrDrawState::BlendOptFlags GrDrawState::getBlendOpts(bool forceCoverage,
298 GrBlendCoeff* srcCoeff,
299 GrBlendCoeff* dstCoeff) const {
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000300 GrAttribBindings bindings = this->getAttribBindings();
bsalomon@google.com2b446732013-02-12 16:47:41 +0000301
302 GrBlendCoeff bogusSrcCoeff, bogusDstCoeff;
303 if (NULL == srcCoeff) {
304 srcCoeff = &bogusSrcCoeff;
305 }
306 *srcCoeff = this->getSrcBlendCoeff();
307
308 if (NULL == dstCoeff) {
309 dstCoeff = &bogusDstCoeff;
310 }
311 *dstCoeff = this->getDstBlendCoeff();
312
313 if (this->isColorWriteDisabled()) {
314 *srcCoeff = kZero_GrBlendCoeff;
315 *dstCoeff = kOne_GrBlendCoeff;
316 }
317
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000318 bool srcAIsOne = this->srcAlphaWillBeOne(bindings);
bsalomon@google.com2b446732013-02-12 16:47:41 +0000319 bool dstCoeffIsOne = kOne_GrBlendCoeff == *dstCoeff ||
320 (kSA_GrBlendCoeff == *dstCoeff && srcAIsOne);
321 bool dstCoeffIsZero = kZero_GrBlendCoeff == *dstCoeff ||
322 (kISA_GrBlendCoeff == *dstCoeff && srcAIsOne);
323
324 bool covIsZero = !this->isCoverageDrawing() &&
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000325 !(bindings & GrDrawState::kCoverage_AttribBindingsBit) &&
bsalomon@google.com2b446732013-02-12 16:47:41 +0000326 0 == this->getCoverage();
327 // When coeffs are (0,1) there is no reason to draw at all, unless
328 // stenciling is enabled. Having color writes disabled is effectively
329 // (0,1). The same applies when coverage is known to be 0.
330 if ((kZero_GrBlendCoeff == *srcCoeff && dstCoeffIsOne) || covIsZero) {
331 if (this->getStencil().doesWrite()) {
332 return kDisableBlend_BlendOptFlag |
333 kEmitTransBlack_BlendOptFlag;
334 } else {
335 return kSkipDraw_BlendOptFlag;
336 }
337 }
338
339 // check for coverage due to constant coverage, per-vertex coverage,
340 // edge aa or coverage stage
341 bool hasCoverage = forceCoverage ||
342 0xffffffff != this->getCoverage() ||
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000343 (bindings & GrDrawState::kCoverage_AttribBindingsBit) ||
344 (bindings & GrDrawState::kEdge_AttribBindingsBit);
bsalomon@google.com2b446732013-02-12 16:47:41 +0000345 for (int s = this->getFirstCoverageStage();
346 !hasCoverage && s < GrDrawState::kNumStages;
347 ++s) {
348 if (this->isStageEnabled(s)) {
349 hasCoverage = true;
350 }
351 }
352
353 // if we don't have coverage we can check whether the dst
354 // has to read at all. If not, we'll disable blending.
355 if (!hasCoverage) {
356 if (dstCoeffIsZero) {
357 if (kOne_GrBlendCoeff == *srcCoeff) {
358 // if there is no coverage and coeffs are (1,0) then we
359 // won't need to read the dst at all, it gets replaced by src
360 return kDisableBlend_BlendOptFlag;
361 } else if (kZero_GrBlendCoeff == *srcCoeff) {
362 // if the op is "clear" then we don't need to emit a color
363 // or blend, just write transparent black into the dst.
364 *srcCoeff = kOne_GrBlendCoeff;
365 *dstCoeff = kZero_GrBlendCoeff;
366 return kDisableBlend_BlendOptFlag | kEmitTransBlack_BlendOptFlag;
367 }
368 }
369 } else if (this->isCoverageDrawing()) {
370 // we have coverage but we aren't distinguishing it from alpha by request.
371 return kCoverageAsAlpha_BlendOptFlag;
372 } else {
373 // check whether coverage can be safely rolled into alpha
374 // of if we can skip color computation and just emit coverage
375 if (this->canTweakAlphaForCoverage()) {
376 return kCoverageAsAlpha_BlendOptFlag;
377 }
378 if (dstCoeffIsZero) {
379 if (kZero_GrBlendCoeff == *srcCoeff) {
380 // the source color is not included in the blend
381 // the dst coeff is effectively zero so blend works out to:
382 // (c)(0)D + (1-c)D = (1-c)D.
383 *dstCoeff = kISA_GrBlendCoeff;
384 return kEmitCoverage_BlendOptFlag;
385 } else if (srcAIsOne) {
386 // the dst coeff is effectively zero so blend works out to:
387 // cS + (c)(0)D + (1-c)D = cS + (1-c)D.
388 // If Sa is 1 then we can replace Sa with c
389 // and set dst coeff to 1-Sa.
390 *dstCoeff = kISA_GrBlendCoeff;
391 return kCoverageAsAlpha_BlendOptFlag;
392 }
393 } else if (dstCoeffIsOne) {
394 // the dst coeff is effectively one so blend works out to:
395 // cS + (c)(1)D + (1-c)D = cS + D.
396 *dstCoeff = kOne_GrBlendCoeff;
397 return kCoverageAsAlpha_BlendOptFlag;
398 }
399 }
400 return kNone_BlendOpt;
401}
402
403////////////////////////////////////////////////////////////////////////////////
404
bsalomon@google.com2fdcdeb2012-10-08 17:15:55 +0000405void GrDrawState::AutoViewMatrixRestore::restore() {
406 if (NULL != fDrawState) {
407 fDrawState->setViewMatrix(fViewMatrix);
408 for (int s = 0; s < GrDrawState::kNumStages; ++s) {
409 if (fRestoreMask & (1 << s)) {
bsalomon@google.comadc65362013-01-28 14:26:09 +0000410 fDrawState->fStages[s].restoreCoordChange(fSavedCoordChanges[s]);
bsalomon@google.com2fdcdeb2012-10-08 17:15:55 +0000411 }
412 }
413 }
414 fDrawState = NULL;
415}
416
417void GrDrawState::AutoViewMatrixRestore::set(GrDrawState* drawState,
bsalomon@google.comb9086a02012-11-01 18:02:54 +0000418 const SkMatrix& preconcatMatrix,
bsalomon@google.com2fdcdeb2012-10-08 17:15:55 +0000419 uint32_t explicitCoordStageMask) {
420 this->restore();
bsalomon@google.com5b3e8902012-10-05 20:13:28 +0000421
422 fDrawState = drawState;
bsalomon@google.com2fdcdeb2012-10-08 17:15:55 +0000423 if (NULL == drawState) {
424 return;
425 }
426
427 fRestoreMask = 0;
428 fViewMatrix = drawState->getViewMatrix();
429 drawState->preConcatViewMatrix(preconcatMatrix);
430 for (int s = 0; s < GrDrawState::kNumStages; ++s) {
431 if (!(explicitCoordStageMask & (1 << s)) && drawState->isStageEnabled(s)) {
432 fRestoreMask |= (1 << s);
bsalomon@google.comadc65362013-01-28 14:26:09 +0000433 fDrawState->fStages[s].saveCoordChange(&fSavedCoordChanges[s]);
434 drawState->fStages[s].preConcatCoordChange(preconcatMatrix);
bsalomon@google.com2fdcdeb2012-10-08 17:15:55 +0000435 }
436 }
437}
438
439////////////////////////////////////////////////////////////////////////////////
440
441void GrDrawState::AutoDeviceCoordDraw::restore() {
442 if (NULL != fDrawState) {
443 fDrawState->setViewMatrix(fViewMatrix);
444 for (int s = 0; s < GrDrawState::kNumStages; ++s) {
445 if (fRestoreMask & (1 << s)) {
bsalomon@google.comadc65362013-01-28 14:26:09 +0000446 fDrawState->fStages[s].restoreCoordChange(fSavedCoordChanges[s]);
bsalomon@google.com2fdcdeb2012-10-08 17:15:55 +0000447 }
448 }
449 }
450 fDrawState = NULL;
451}
452
453bool GrDrawState::AutoDeviceCoordDraw::set(GrDrawState* drawState,
454 uint32_t explicitCoordStageMask) {
455 GrAssert(NULL != drawState);
456
457 this->restore();
458
459 fDrawState = drawState;
460 if (NULL == fDrawState) {
461 return false;
skia.committer@gmail.comf467ce72012-10-09 02:01:37 +0000462 }
bsalomon@google.com2fdcdeb2012-10-08 17:15:55 +0000463
bsalomon@google.com5b3e8902012-10-05 20:13:28 +0000464 fViewMatrix = drawState->getViewMatrix();
465 fRestoreMask = 0;
bsalomon@google.comb9086a02012-11-01 18:02:54 +0000466 SkMatrix invVM;
bsalomon@google.com5b3e8902012-10-05 20:13:28 +0000467 bool inverted = false;
468
469 for (int s = 0; s < GrDrawState::kNumStages; ++s) {
470 if (!(explicitCoordStageMask & (1 << s)) && drawState->isStageEnabled(s)) {
471 if (!inverted && !fViewMatrix.invert(&invVM)) {
472 // sad trombone sound
473 fDrawState = NULL;
bsalomon@google.com2fdcdeb2012-10-08 17:15:55 +0000474 return false;
bsalomon@google.com5b3e8902012-10-05 20:13:28 +0000475 } else {
476 inverted = true;
477 }
478 fRestoreMask |= (1 << s);
bsalomon@google.comadc65362013-01-28 14:26:09 +0000479 GrEffectStage* stage = drawState->fStages + s;
bsalomon@google.com08283af2012-10-26 13:01:20 +0000480 stage->saveCoordChange(&fSavedCoordChanges[s]);
481 stage->preConcatCoordChange(invVM);
bsalomon@google.com5b3e8902012-10-05 20:13:28 +0000482 }
483 }
484 drawState->viewMatrix()->reset();
bsalomon@google.com2fdcdeb2012-10-08 17:15:55 +0000485 return true;
bsalomon@google.com5b3e8902012-10-05 20:13:28 +0000486}