blob: 8c74c4a4bd9620edeb2e7080e3a0a0c252d7ecdc [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.com39768252013-02-14 15:25:44 +000060void gen_tex_coord_mask(GrVertexLayout* texCoordMask) {
61 *texCoordMask = 0;
jvanverth@google.comcc782382013-01-28 20:39:48 +000062 for (int s = 0; s < GrDrawState::kNumStages; ++s) {
jvanverth@google.com39768252013-02-14 15:25:44 +000063 *texCoordMask |= GrDrawState::StageTexCoordVertexLayoutBit(s);
jvanverth@google.comcc782382013-01-28 20:39:48 +000064 }
65}
66
jvanverth@google.com39768252013-02-14 15:25:44 +000067const GrVertexLayout kTexCoordMask = (1 << GrDrawState::kNumStages)-1;
jvanverth@google.comcc782382013-01-28 20:39:48 +000068
jvanverth@google.com39768252013-02-14 15:25:44 +000069inline int num_tex_coords(GrVertexLayout layout) {
70 return (kTexCoordMask & layout) ? 1 : 0;
jvanverth@google.comcc782382013-01-28 20:39:48 +000071}
72
73} //unnamed namespace
74
bsalomon@google.com85983282013-02-07 22:00:29 +000075static const size_t kVec2Size = sizeof(GrPoint);
76
jvanverth@google.comcc782382013-01-28 20:39:48 +000077size_t GrDrawState::VertexSize(GrVertexLayout vertexLayout) {
bsalomon@google.com85983282013-02-07 22:00:29 +000078 size_t size = kVec2Size; // position
79 size += num_tex_coords(vertexLayout) * kVec2Size;
jvanverth@google.comcc782382013-01-28 20:39:48 +000080 if (vertexLayout & kColor_VertexLayoutBit) {
81 size += sizeof(GrColor);
82 }
83 if (vertexLayout & kCoverage_VertexLayoutBit) {
84 size += sizeof(GrColor);
85 }
86 if (vertexLayout & kEdge_VertexLayoutBit) {
87 size += 4 * sizeof(SkScalar);
88 }
89 return size;
90}
91
92////////////////////////////////////////////////////////////////////////////////
93
94/**
95 * Functions for computing offsets of various components from the layout
96 * bitfield.
97 *
98 * Order of vertex components:
99 * Position
skia.committer@gmail.com044679e2013-02-15 07:16:57 +0000100 * Tex Coord
jvanverth@google.comcc782382013-01-28 20:39:48 +0000101 * Color
102 * Coverage
103 */
104
105int GrDrawState::VertexStageCoordOffset(int stageIdx, GrVertexLayout vertexLayout) {
jvanverth@google.comcc782382013-01-28 20:39:48 +0000106 if (!StageUsesTexCoords(vertexLayout, stageIdx)) {
107 return 0;
108 }
jvanverth@google.comcc782382013-01-28 20:39:48 +0000109
jvanverth@google.com39768252013-02-14 15:25:44 +0000110 return kVec2Size;
jvanverth@google.comcc782382013-01-28 20:39:48 +0000111}
112
113int GrDrawState::VertexColorOffset(GrVertexLayout vertexLayout) {
jvanverth@google.comcc782382013-01-28 20:39:48 +0000114 if (vertexLayout & kColor_VertexLayoutBit) {
bsalomon@google.com85983282013-02-07 22:00:29 +0000115 return kVec2Size * (num_tex_coords(vertexLayout) + 1); //+1 for pos
jvanverth@google.comcc782382013-01-28 20:39:48 +0000116 }
117 return -1;
118}
119
120int GrDrawState::VertexCoverageOffset(GrVertexLayout vertexLayout) {
jvanverth@google.comcc782382013-01-28 20:39:48 +0000121 if (vertexLayout & kCoverage_VertexLayoutBit) {
bsalomon@google.com85983282013-02-07 22:00:29 +0000122 int offset = kVec2Size * (num_tex_coords(vertexLayout) + 1);
jvanverth@google.comcc782382013-01-28 20:39:48 +0000123 if (vertexLayout & kColor_VertexLayoutBit) {
124 offset += sizeof(GrColor);
125 }
126 return offset;
127 }
128 return -1;
129}
130
131int GrDrawState::VertexEdgeOffset(GrVertexLayout vertexLayout) {
jvanverth@google.comcc782382013-01-28 20:39:48 +0000132 // edge pts are after the pos, tex coords, and color
133 if (vertexLayout & kEdge_VertexLayoutBit) {
bsalomon@google.com85983282013-02-07 22:00:29 +0000134 int offset = kVec2Size * (num_tex_coords(vertexLayout) + 1); //+1 for pos
jvanverth@google.comcc782382013-01-28 20:39:48 +0000135 if (vertexLayout & kColor_VertexLayoutBit) {
136 offset += sizeof(GrColor);
137 }
138 if (vertexLayout & kCoverage_VertexLayoutBit) {
139 offset += sizeof(GrColor);
140 }
141 return offset;
142 }
143 return -1;
144}
145
jvanverth@google.com39768252013-02-14 15:25:44 +0000146int GrDrawState::VertexSizeAndOffsets(
jvanverth@google.comcc782382013-01-28 20:39:48 +0000147 GrVertexLayout vertexLayout,
jvanverth@google.com39768252013-02-14 15:25:44 +0000148 int* texCoordOffset,
jvanverth@google.comcc782382013-01-28 20:39:48 +0000149 int* colorOffset,
150 int* coverageOffset,
151 int* edgeOffset) {
bsalomon@google.com85983282013-02-07 22:00:29 +0000152 int size = kVec2Size; // position
jvanverth@google.comcc782382013-01-28 20:39:48 +0000153
jvanverth@google.com39768252013-02-14 15:25:44 +0000154 if (kTexCoordMask & vertexLayout) {
155 if (NULL != texCoordOffset) {
156 *texCoordOffset = size;
157 }
158 size += kVec2Size;
159 } else {
160 if (NULL != texCoordOffset) {
161 *texCoordOffset = -1;
jvanverth@google.comcc782382013-01-28 20:39:48 +0000162 }
163 }
164 if (kColor_VertexLayoutBit & vertexLayout) {
165 if (NULL != colorOffset) {
166 *colorOffset = size;
167 }
168 size += sizeof(GrColor);
169 } else {
170 if (NULL != colorOffset) {
171 *colorOffset = -1;
172 }
173 }
174 if (kCoverage_VertexLayoutBit & vertexLayout) {
175 if (NULL != coverageOffset) {
176 *coverageOffset = size;
177 }
178 size += sizeof(GrColor);
179 } else {
180 if (NULL != coverageOffset) {
181 *coverageOffset = -1;
182 }
183 }
184 if (kEdge_VertexLayoutBit & vertexLayout) {
185 if (NULL != edgeOffset) {
186 *edgeOffset = size;
187 }
188 size += 4 * sizeof(SkScalar);
189 } else {
190 if (NULL != edgeOffset) {
191 *edgeOffset = -1;
192 }
193 }
194 return size;
195}
196
197int GrDrawState::VertexSizeAndOffsetsByStage(
198 GrVertexLayout vertexLayout,
199 int texCoordOffsetsByStage[GrDrawState::kNumStages],
200 int* colorOffset,
201 int* coverageOffset,
202 int* edgeOffset) {
jvanverth@google.comcc782382013-01-28 20:39:48 +0000203
jvanverth@google.com39768252013-02-14 15:25:44 +0000204 int texCoordOffset;
205 int size = VertexSizeAndOffsets(vertexLayout,
206 &texCoordOffset,
207 colorOffset,
208 coverageOffset,
209 edgeOffset);
jvanverth@google.comcc782382013-01-28 20:39:48 +0000210 if (NULL != texCoordOffsetsByStage) {
211 for (int s = 0; s < GrDrawState::kNumStages; ++s) {
jvanverth@google.com39768252013-02-14 15:25:44 +0000212 texCoordOffsetsByStage[s] = StageUsesTexCoords(vertexLayout, s) ?
213 texCoordOffset : 0;
jvanverth@google.comcc782382013-01-28 20:39:48 +0000214 }
215 }
216 return size;
217}
218
219////////////////////////////////////////////////////////////////////////////////
220
jvanverth@google.com39768252013-02-14 15:25:44 +0000221bool GrDrawState::VertexUsesTexCoords(GrVertexLayout vertexLayout) {
222 return SkToBool(kTexCoordMask & vertexLayout);
jvanverth@google.comcc782382013-01-28 20:39:48 +0000223}
224
225////////////////////////////////////////////////////////////////////////////////
226
227void GrDrawState::VertexLayoutUnitTest() {
jvanverth@google.com39768252013-02-14 15:25:44 +0000228 // Ensure that our tex coord mask is correct
229 GrVertexLayout texCoordMask;
230 gen_tex_coord_mask(&texCoordMask);
231 GrAssert(texCoordMask == kTexCoordMask);
jvanverth@google.comcc782382013-01-28 20:39:48 +0000232
233 // not necessarily exhaustive
234 static bool run;
235 if (!run) {
236 run = true;
jvanverth@google.com39768252013-02-14 15:25:44 +0000237 GrVertexLayout tcMask = 0;
238 GrAssert(!VertexUsesTexCoords(0));
jvanverth@google.comcc782382013-01-28 20:39:48 +0000239 for (int s = 0; s < GrDrawState::kNumStages; ++s) {
jvanverth@google.com39768252013-02-14 15:25:44 +0000240 tcMask |= StageTexCoordVertexLayoutBit(s);
241 GrAssert(sizeof(GrPoint) == VertexStageCoordOffset(s, tcMask));
242 GrAssert(VertexUsesTexCoords(tcMask));
243 GrAssert(2*sizeof(GrPoint) == VertexSize(tcMask));
244 GrAssert(StageUsesTexCoords(tcMask, s));
245 for (int s2 = s + 1; s2 < GrDrawState::kNumStages; ++s2) {
246 GrAssert(!StageUsesTexCoords(tcMask, s2));
jvanverth@google.comcc782382013-01-28 20:39:48 +0000247
jvanverth@google.com39768252013-02-14 15:25:44 +0000248 #if GR_DEBUG
249 GrVertexLayout posAsTex = tcMask;
250 #endif
251 GrAssert(0 == VertexStageCoordOffset(s2, posAsTex));
252 GrAssert(2*sizeof(GrPoint) == VertexSize(posAsTex));
253 GrAssert(!StageUsesTexCoords(posAsTex, s2));
254 GrAssert(-1 == VertexEdgeOffset(posAsTex));
jvanverth@google.comcc782382013-01-28 20:39:48 +0000255 }
jvanverth@google.com39768252013-02-14 15:25:44 +0000256 GrAssert(-1 == VertexEdgeOffset(tcMask));
257 GrAssert(-1 == VertexColorOffset(tcMask));
258 GrAssert(-1 == VertexCoverageOffset(tcMask));
259 #if GR_DEBUG
260 GrVertexLayout withColor = tcMask | kColor_VertexLayoutBit;
261 #endif
262 GrAssert(-1 == VertexCoverageOffset(withColor));
263 GrAssert(2*sizeof(GrPoint) == VertexColorOffset(withColor));
264 GrAssert(2*sizeof(GrPoint) + sizeof(GrColor) == VertexSize(withColor));
265 #if GR_DEBUG
266 GrVertexLayout withEdge = tcMask | kEdge_VertexLayoutBit;
267 #endif
268 GrAssert(-1 == VertexColorOffset(withEdge));
269 GrAssert(2*sizeof(GrPoint) == VertexEdgeOffset(withEdge));
270 GrAssert(4*sizeof(GrPoint) == VertexSize(withEdge));
271 #if GR_DEBUG
272 GrVertexLayout withColorAndEdge = withColor | kEdge_VertexLayoutBit;
273 #endif
274 GrAssert(2*sizeof(GrPoint) == VertexColorOffset(withColorAndEdge));
275 GrAssert(2*sizeof(GrPoint) + sizeof(GrColor) == VertexEdgeOffset(withColorAndEdge));
276 GrAssert(4*sizeof(GrPoint) + sizeof(GrColor) == VertexSize(withColorAndEdge));
277 #if GR_DEBUG
278 GrVertexLayout withCoverage = tcMask | kCoverage_VertexLayoutBit;
279 #endif
280 GrAssert(-1 == VertexColorOffset(withCoverage));
281 GrAssert(2*sizeof(GrPoint) == VertexCoverageOffset(withCoverage));
282 GrAssert(2*sizeof(GrPoint) + sizeof(GrColor) == VertexSize(withCoverage));
283 #if GR_DEBUG
284 GrVertexLayout withCoverageAndColor = tcMask | kCoverage_VertexLayoutBit |
285 kColor_VertexLayoutBit;
286 #endif
287 GrAssert(2*sizeof(GrPoint) == VertexColorOffset(withCoverageAndColor));
288 GrAssert(2*sizeof(GrPoint) + sizeof(GrColor) == VertexCoverageOffset(withCoverageAndColor));
289 GrAssert(2*sizeof(GrPoint) + 2 * sizeof(GrColor) == VertexSize(withCoverageAndColor));
jvanverth@google.comcc782382013-01-28 20:39:48 +0000290 }
jvanverth@google.com39768252013-02-14 15:25:44 +0000291 GrAssert(kTexCoordMask == tcMask);
jvanverth@google.comcc782382013-01-28 20:39:48 +0000292
jvanverth@google.com39768252013-02-14 15:25:44 +0000293 int stageOffsets[GrDrawState::kNumStages];
294 int colorOffset;
295 int edgeOffset;
296 int coverageOffset;
297 int size;
298 size = VertexSizeAndOffsetsByStage(tcMask,
299 stageOffsets, &colorOffset,
300 &coverageOffset, &edgeOffset);
301 GrAssert(2*sizeof(GrPoint) == size);
302 GrAssert(-1 == colorOffset);
303 GrAssert(-1 == coverageOffset);
304 GrAssert(-1 == edgeOffset);
305 for (int s = 0; s < GrDrawState::kNumStages; ++s) {
306 GrAssert(sizeof(GrPoint) == stageOffsets[s]);
307 GrAssert(sizeof(GrPoint) == VertexStageCoordOffset(s, tcMask));
jvanverth@google.comcc782382013-01-28 20:39:48 +0000308 }
309 }
310}
311
312////////////////////////////////////////////////////////////////////////////////
313
314bool GrDrawState::StageUsesTexCoords(GrVertexLayout layout, int stageIdx) {
jvanverth@google.com39768252013-02-14 15:25:44 +0000315 return SkToBool(layout & StageTexCoordVertexLayoutBit(stageIdx));
jvanverth@google.comcc782382013-01-28 20:39:48 +0000316}
317
318bool GrDrawState::srcAlphaWillBeOne(GrVertexLayout layout) const {
319
320 uint32_t validComponentFlags;
321 GrColor color;
322 // Check if per-vertex or constant color may have partial alpha
323 if (layout & kColor_VertexLayoutBit) {
324 validComponentFlags = 0;
325 } else {
326 validComponentFlags = GrEffect::kAll_ValidComponentFlags;
327 color = this->getColor();
328 }
329
330 // Run through the color stages
331 int stageCnt = getFirstCoverageStage();
332 for (int s = 0; s < stageCnt; ++s) {
333 const GrEffectRef* effect = this->getStage(s).getEffect();
334 if (NULL != effect) {
335 (*effect)->getConstantColorComponents(&color, &validComponentFlags);
336 }
337 }
338
339 // Check if the color filter could introduce an alpha.
340 // We could skip the above work when this is true, but it is rare and the right fix is to make
341 // the color filter a GrEffect and implement getConstantColorComponents() for it.
342 if (SkXfermode::kDst_Mode != this->getColorFilterMode()) {
343 validComponentFlags = 0;
344 }
345
346 // Check whether coverage is treated as color. If so we run through the coverage computation.
347 if (this->isCoverageDrawing()) {
348 GrColor coverageColor = this->getCoverage();
349 GrColor oldColor = color;
350 color = 0;
351 for (int c = 0; c < 4; ++c) {
352 if (validComponentFlags & (1 << c)) {
353 U8CPU a = (oldColor >> (c * 8)) & 0xff;
354 U8CPU b = (coverageColor >> (c * 8)) & 0xff;
355 color |= (SkMulDiv255Round(a, b) << (c * 8));
356 }
357 }
358 for (int s = this->getFirstCoverageStage(); s < GrDrawState::kNumStages; ++s) {
359 const GrEffectRef* effect = this->getStage(s).getEffect();
360 if (NULL != effect) {
361 (*effect)->getConstantColorComponents(&color, &validComponentFlags);
362 }
363 }
364 }
365 return (GrEffect::kA_ValidComponentFlag & validComponentFlags) && 0xff == GrColorUnpackA(color);
366}
367
bsalomon@google.comd62e88e2013-02-01 14:19:27 +0000368bool GrDrawState::hasSolidCoverage(GrVertexLayout layout) const {
369 // If we're drawing coverage directly then coverage is effectively treated as color.
370 if (this->isCoverageDrawing()) {
371 return true;
372 }
373
374 GrColor coverage;
375 uint32_t validComponentFlags;
376 // Initialize to an unknown starting coverage if per-vertex coverage is specified.
377 if (layout & kCoverage_VertexLayoutBit) {
378 validComponentFlags = 0;
379 } else {
380 coverage = fCommon.fCoverage;
381 validComponentFlags = GrEffect::kAll_ValidComponentFlags;
382 }
383
384 // Run through the coverage stages and see if the coverage will be all ones at the end.
385 for (int s = this->getFirstCoverageStage(); s < GrDrawState::kNumStages; ++s) {
386 const GrEffectRef* effect = this->getStage(s).getEffect();
387 if (NULL != effect) {
388 (*effect)->getConstantColorComponents(&coverage, &validComponentFlags);
389 }
390 }
391 return (GrEffect::kAll_ValidComponentFlags == validComponentFlags) && (0xffffffff == coverage);
392}
393
jvanverth@google.comcc782382013-01-28 20:39:48 +0000394////////////////////////////////////////////////////////////////////////////////
395
bsalomon@google.com2b446732013-02-12 16:47:41 +0000396// Some blend modes allow folding a fractional coverage value into the color's alpha channel, while
397// others will blend incorrectly.
398bool GrDrawState::canTweakAlphaForCoverage() const {
399 /*
400 The fractional coverage is f.
401 The src and dst coeffs are Cs and Cd.
402 The dst and src colors are S and D.
403 We want the blend to compute: f*Cs*S + (f*Cd + (1-f))D. By tweaking the source color's alpha
404 we're replacing S with S'=fS. It's obvious that that first term will always be ok. The second
405 term can be rearranged as [1-(1-Cd)f]D. By substituting in the various possibilities for Cd we
406 find that only 1, ISA, and ISC produce the correct destination when applied to S' and D.
407 Also, if we're directly rendering coverage (isCoverageDrawing) then coverage is treated as
408 color by definition.
409 */
410 return kOne_GrBlendCoeff == fCommon.fDstBlend ||
411 kISA_GrBlendCoeff == fCommon.fDstBlend ||
412 kISC_GrBlendCoeff == fCommon.fDstBlend ||
413 this->isCoverageDrawing();
414}
415
416GrDrawState::BlendOptFlags GrDrawState::getBlendOpts(bool forceCoverage,
417 GrBlendCoeff* srcCoeff,
418 GrBlendCoeff* dstCoeff) const {
419 GrVertexLayout layout = this->getVertexLayout();
420
421 GrBlendCoeff bogusSrcCoeff, bogusDstCoeff;
422 if (NULL == srcCoeff) {
423 srcCoeff = &bogusSrcCoeff;
424 }
425 *srcCoeff = this->getSrcBlendCoeff();
426
427 if (NULL == dstCoeff) {
428 dstCoeff = &bogusDstCoeff;
429 }
430 *dstCoeff = this->getDstBlendCoeff();
431
432 if (this->isColorWriteDisabled()) {
433 *srcCoeff = kZero_GrBlendCoeff;
434 *dstCoeff = kOne_GrBlendCoeff;
435 }
436
437 bool srcAIsOne = this->srcAlphaWillBeOne(layout);
438 bool dstCoeffIsOne = kOne_GrBlendCoeff == *dstCoeff ||
439 (kSA_GrBlendCoeff == *dstCoeff && srcAIsOne);
440 bool dstCoeffIsZero = kZero_GrBlendCoeff == *dstCoeff ||
441 (kISA_GrBlendCoeff == *dstCoeff && srcAIsOne);
442
443 bool covIsZero = !this->isCoverageDrawing() &&
444 !(layout & GrDrawState::kCoverage_VertexLayoutBit) &&
445 0 == this->getCoverage();
446 // When coeffs are (0,1) there is no reason to draw at all, unless
447 // stenciling is enabled. Having color writes disabled is effectively
448 // (0,1). The same applies when coverage is known to be 0.
449 if ((kZero_GrBlendCoeff == *srcCoeff && dstCoeffIsOne) || covIsZero) {
450 if (this->getStencil().doesWrite()) {
451 return kDisableBlend_BlendOptFlag |
452 kEmitTransBlack_BlendOptFlag;
453 } else {
454 return kSkipDraw_BlendOptFlag;
455 }
456 }
457
458 // check for coverage due to constant coverage, per-vertex coverage,
459 // edge aa or coverage stage
460 bool hasCoverage = forceCoverage ||
461 0xffffffff != this->getCoverage() ||
462 (layout & GrDrawState::kCoverage_VertexLayoutBit) ||
463 (layout & GrDrawState::kEdge_VertexLayoutBit);
464 for (int s = this->getFirstCoverageStage();
465 !hasCoverage && s < GrDrawState::kNumStages;
466 ++s) {
467 if (this->isStageEnabled(s)) {
468 hasCoverage = true;
469 }
470 }
471
472 // if we don't have coverage we can check whether the dst
473 // has to read at all. If not, we'll disable blending.
474 if (!hasCoverage) {
475 if (dstCoeffIsZero) {
476 if (kOne_GrBlendCoeff == *srcCoeff) {
477 // if there is no coverage and coeffs are (1,0) then we
478 // won't need to read the dst at all, it gets replaced by src
479 return kDisableBlend_BlendOptFlag;
480 } else if (kZero_GrBlendCoeff == *srcCoeff) {
481 // if the op is "clear" then we don't need to emit a color
482 // or blend, just write transparent black into the dst.
483 *srcCoeff = kOne_GrBlendCoeff;
484 *dstCoeff = kZero_GrBlendCoeff;
485 return kDisableBlend_BlendOptFlag | kEmitTransBlack_BlendOptFlag;
486 }
487 }
488 } else if (this->isCoverageDrawing()) {
489 // we have coverage but we aren't distinguishing it from alpha by request.
490 return kCoverageAsAlpha_BlendOptFlag;
491 } else {
492 // check whether coverage can be safely rolled into alpha
493 // of if we can skip color computation and just emit coverage
494 if (this->canTweakAlphaForCoverage()) {
495 return kCoverageAsAlpha_BlendOptFlag;
496 }
497 if (dstCoeffIsZero) {
498 if (kZero_GrBlendCoeff == *srcCoeff) {
499 // the source color is not included in the blend
500 // the dst coeff is effectively zero so blend works out to:
501 // (c)(0)D + (1-c)D = (1-c)D.
502 *dstCoeff = kISA_GrBlendCoeff;
503 return kEmitCoverage_BlendOptFlag;
504 } else if (srcAIsOne) {
505 // the dst coeff is effectively zero so blend works out to:
506 // cS + (c)(0)D + (1-c)D = cS + (1-c)D.
507 // If Sa is 1 then we can replace Sa with c
508 // and set dst coeff to 1-Sa.
509 *dstCoeff = kISA_GrBlendCoeff;
510 return kCoverageAsAlpha_BlendOptFlag;
511 }
512 } else if (dstCoeffIsOne) {
513 // the dst coeff is effectively one so blend works out to:
514 // cS + (c)(1)D + (1-c)D = cS + D.
515 *dstCoeff = kOne_GrBlendCoeff;
516 return kCoverageAsAlpha_BlendOptFlag;
517 }
518 }
519 return kNone_BlendOpt;
520}
521
522////////////////////////////////////////////////////////////////////////////////
523
bsalomon@google.com2fdcdeb2012-10-08 17:15:55 +0000524void GrDrawState::AutoViewMatrixRestore::restore() {
525 if (NULL != fDrawState) {
526 fDrawState->setViewMatrix(fViewMatrix);
527 for (int s = 0; s < GrDrawState::kNumStages; ++s) {
528 if (fRestoreMask & (1 << s)) {
bsalomon@google.comadc65362013-01-28 14:26:09 +0000529 fDrawState->fStages[s].restoreCoordChange(fSavedCoordChanges[s]);
bsalomon@google.com2fdcdeb2012-10-08 17:15:55 +0000530 }
531 }
532 }
533 fDrawState = NULL;
534}
535
536void GrDrawState::AutoViewMatrixRestore::set(GrDrawState* drawState,
bsalomon@google.comb9086a02012-11-01 18:02:54 +0000537 const SkMatrix& preconcatMatrix,
bsalomon@google.com2fdcdeb2012-10-08 17:15:55 +0000538 uint32_t explicitCoordStageMask) {
539 this->restore();
bsalomon@google.com5b3e8902012-10-05 20:13:28 +0000540
541 fDrawState = drawState;
bsalomon@google.com2fdcdeb2012-10-08 17:15:55 +0000542 if (NULL == drawState) {
543 return;
544 }
545
546 fRestoreMask = 0;
547 fViewMatrix = drawState->getViewMatrix();
548 drawState->preConcatViewMatrix(preconcatMatrix);
549 for (int s = 0; s < GrDrawState::kNumStages; ++s) {
550 if (!(explicitCoordStageMask & (1 << s)) && drawState->isStageEnabled(s)) {
551 fRestoreMask |= (1 << s);
bsalomon@google.comadc65362013-01-28 14:26:09 +0000552 fDrawState->fStages[s].saveCoordChange(&fSavedCoordChanges[s]);
553 drawState->fStages[s].preConcatCoordChange(preconcatMatrix);
bsalomon@google.com2fdcdeb2012-10-08 17:15:55 +0000554 }
555 }
556}
557
558////////////////////////////////////////////////////////////////////////////////
559
560void GrDrawState::AutoDeviceCoordDraw::restore() {
561 if (NULL != fDrawState) {
562 fDrawState->setViewMatrix(fViewMatrix);
563 for (int s = 0; s < GrDrawState::kNumStages; ++s) {
564 if (fRestoreMask & (1 << s)) {
bsalomon@google.comadc65362013-01-28 14:26:09 +0000565 fDrawState->fStages[s].restoreCoordChange(fSavedCoordChanges[s]);
bsalomon@google.com2fdcdeb2012-10-08 17:15:55 +0000566 }
567 }
568 }
569 fDrawState = NULL;
570}
571
572bool GrDrawState::AutoDeviceCoordDraw::set(GrDrawState* drawState,
573 uint32_t explicitCoordStageMask) {
574 GrAssert(NULL != drawState);
575
576 this->restore();
577
578 fDrawState = drawState;
579 if (NULL == fDrawState) {
580 return false;
skia.committer@gmail.comf467ce72012-10-09 02:01:37 +0000581 }
bsalomon@google.com2fdcdeb2012-10-08 17:15:55 +0000582
bsalomon@google.com5b3e8902012-10-05 20:13:28 +0000583 fViewMatrix = drawState->getViewMatrix();
584 fRestoreMask = 0;
bsalomon@google.comb9086a02012-11-01 18:02:54 +0000585 SkMatrix invVM;
bsalomon@google.com5b3e8902012-10-05 20:13:28 +0000586 bool inverted = false;
587
588 for (int s = 0; s < GrDrawState::kNumStages; ++s) {
589 if (!(explicitCoordStageMask & (1 << s)) && drawState->isStageEnabled(s)) {
590 if (!inverted && !fViewMatrix.invert(&invVM)) {
591 // sad trombone sound
592 fDrawState = NULL;
bsalomon@google.com2fdcdeb2012-10-08 17:15:55 +0000593 return false;
bsalomon@google.com5b3e8902012-10-05 20:13:28 +0000594 } else {
595 inverted = true;
596 }
597 fRestoreMask |= (1 << s);
bsalomon@google.comadc65362013-01-28 14:26:09 +0000598 GrEffectStage* stage = drawState->fStages + s;
bsalomon@google.com08283af2012-10-26 13:01:20 +0000599 stage->saveCoordChange(&fSavedCoordChanges[s]);
600 stage->preConcatCoordChange(invVM);
bsalomon@google.com5b3e8902012-10-05 20:13:28 +0000601 }
602 }
603 drawState->viewMatrix()->reset();
bsalomon@google.com2fdcdeb2012-10-08 17:15:55 +0000604 return true;
bsalomon@google.com5b3e8902012-10-05 20:13:28 +0000605}