1 /*
2 * Copyright 2011 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
9 #include "src/gpu/GrStencilSettings.h"
10
11 #include "src/gpu/GrProcessor.h"
12
13 constexpr const GrUserStencilSettings gUnused(
14 GrUserStencilSettings::StaticInit<
15 0x0000,
16 GrUserStencilTest::kAlwaysIfInClip,
17 0xffff,
18 GrUserStencilOp::kKeep,
19 GrUserStencilOp::kKeep,
20 0x0000>()
21 );
22
23 GR_STATIC_ASSERT(kAll_StencilFlags == (gUnused.fFrontFlags[0] & gUnused.fBackFlags[0]));
24
25 const GrUserStencilSettings& GrUserStencilSettings::kUnused = gUnused;
26
reset(const GrUserStencilSettings & user,bool hasStencilClip,int numStencilBits)27 void GrStencilSettings::reset(const GrUserStencilSettings& user, bool hasStencilClip,
28 int numStencilBits) {
29 uint16_t frontFlags = user.fFrontFlags[hasStencilClip];
30 if (frontFlags & kSingleSided_StencilFlag) {
31 SkASSERT(frontFlags == user.fBackFlags[hasStencilClip]);
32 fFlags = frontFlags;
33 if (!this->isDisabled()) {
34 fFront.reset(user.fFront, hasStencilClip, numStencilBits);
35 }
36 return;
37 }
38
39 uint16_t backFlags = user.fBackFlags[hasStencilClip];
40 fFlags = frontFlags & backFlags;
41 if (this->isDisabled()) {
42 return;
43 }
44 if (!(frontFlags & kDisabled_StencilFlag)) {
45 fFront.reset(user.fFront, hasStencilClip, numStencilBits);
46 } else {
47 fFront.setDisabled();
48 }
49 if (!(backFlags & kDisabled_StencilFlag)) {
50 fBack.reset(user.fBack, hasStencilClip, numStencilBits);
51 } else {
52 fBack.setDisabled();
53 }
54 }
55
reset(const GrStencilSettings & that)56 void GrStencilSettings::reset(const GrStencilSettings& that) {
57 fFlags = that.fFlags;
58 if ((kInvalid_PrivateFlag | kDisabled_StencilFlag) & fFlags) {
59 return;
60 }
61 if (!this->isTwoSided()) {
62 memcpy(&fFront, &that.fFront, sizeof(Face));
63 } else {
64 memcpy(&fFront, &that.fFront, 2 * sizeof(Face));
65 GR_STATIC_ASSERT(sizeof(Face) ==
66 offsetof(GrStencilSettings, fBack) - offsetof(GrStencilSettings, fFront));
67 }
68 }
69
operator ==(const GrStencilSettings & that) const70 bool GrStencilSettings::operator==(const GrStencilSettings& that) const {
71 if ((kInvalid_PrivateFlag | kDisabled_StencilFlag) & (fFlags | that.fFlags)) {
72 // At least one is invalid and/or disabled.
73 if (kInvalid_PrivateFlag & (fFlags | that.fFlags)) {
74 return false; // We never allow invalid stencils to be equal.
75 }
76 // They're only equal if both are disabled.
77 return kDisabled_StencilFlag & (fFlags & that.fFlags);
78 }
79 if (kSingleSided_StencilFlag & (fFlags & that.fFlags)) {
80 return 0 == memcmp(&fFront, &that.fFront, sizeof(Face)); // Both are single sided.
81 } else if (kSingleSided_StencilFlag & (fFlags | that.fFlags)) {
82 return false;
83 } else {
84 return 0 == memcmp(&fFront, &that.fFront, 2 * sizeof(Face));
85 GR_STATIC_ASSERT(sizeof(Face) ==
86 offsetof(GrStencilSettings, fBack) - offsetof(GrStencilSettings, fFront));
87 }
88 // memcmp relies on GrStencilSettings::Face being tightly packed.
89 GR_STATIC_ASSERT(0 == offsetof(Face, fRef));
90 GR_STATIC_ASSERT(2 == sizeof(Face::fRef));
91 GR_STATIC_ASSERT(2 == offsetof(Face, fTest));
92 GR_STATIC_ASSERT(2 == sizeof(Face::fTest));
93 GR_STATIC_ASSERT(4 == offsetof(Face, fTestMask));
94 GR_STATIC_ASSERT(2 == sizeof(Face::fTestMask));
95 GR_STATIC_ASSERT(6 == offsetof(Face, fPassOp));
96 GR_STATIC_ASSERT(1 == sizeof(Face::fPassOp));
97 GR_STATIC_ASSERT(7 == offsetof(Face, fFailOp));
98 GR_STATIC_ASSERT(1 == sizeof(Face::fFailOp));
99 GR_STATIC_ASSERT(8 == offsetof(Face, fWriteMask));
100 GR_STATIC_ASSERT(2 == sizeof(Face::fWriteMask));
101 GR_STATIC_ASSERT(10 == sizeof(Face));
102 }
103
104 static constexpr GrStencilTest gUserStencilTestToRaw[kGrUserStencilTestCount] = {
105 // Tests that respect the clip.
106 GrStencilTest::kAlways, // kAlwaysIfInClip (This is only for when there is not a stencil clip).
107 GrStencilTest::kEqual, // kEqualIfInClip.
108 GrStencilTest::kLess, // kLessIfInClip.
109 GrStencilTest::kLEqual, // kLEqualIfInClip.
110
111 // Tests that ignore the clip.
112 GrStencilTest::kAlways,
113 GrStencilTest::kNever,
114 GrStencilTest::kGreater,
115 GrStencilTest::kGEqual,
116 GrStencilTest::kLess,
117 GrStencilTest::kLEqual,
118 GrStencilTest::kEqual,
119 GrStencilTest::kNotEqual
120 };
121
122 GR_STATIC_ASSERT(0 == (int)GrUserStencilTest::kAlwaysIfInClip);
123 GR_STATIC_ASSERT(1 == (int)GrUserStencilTest::kEqualIfInClip);
124 GR_STATIC_ASSERT(2 == (int)GrUserStencilTest::kLessIfInClip);
125 GR_STATIC_ASSERT(3 == (int)GrUserStencilTest::kLEqualIfInClip);
126 GR_STATIC_ASSERT(4 == (int)GrUserStencilTest::kAlways);
127 GR_STATIC_ASSERT(5 == (int)GrUserStencilTest::kNever);
128 GR_STATIC_ASSERT(6 == (int)GrUserStencilTest::kGreater);
129 GR_STATIC_ASSERT(7 == (int)GrUserStencilTest::kGEqual);
130 GR_STATIC_ASSERT(8 == (int)GrUserStencilTest::kLess);
131 GR_STATIC_ASSERT(9 == (int)GrUserStencilTest::kLEqual);
132 GR_STATIC_ASSERT(10 == (int)GrUserStencilTest::kEqual);
133 GR_STATIC_ASSERT(11 == (int)GrUserStencilTest::kNotEqual);
134
135 static constexpr GrStencilOp gUserStencilOpToRaw[kGrUserStencilOpCount] = {
136 GrStencilOp::kKeep,
137
138 // Ops that only modify user bits.
139 GrStencilOp::kZero,
140 GrStencilOp::kReplace,
141 GrStencilOp::kInvert,
142 GrStencilOp::kIncWrap,
143 GrStencilOp::kDecWrap,
144 GrStencilOp::kIncClamp, // kIncMaybeClamp.
145 GrStencilOp::kDecClamp, // kDecMaybeClamp.
146
147 // Ops that only modify the clip bit.
148 GrStencilOp::kZero, // kZeroClipBit.
149 GrStencilOp::kReplace, // kSetClipBit.
150 GrStencilOp::kInvert, // kInvertClipBit.
151
152 // Ops that modify clip and user bits.
153 GrStencilOp::kReplace, // kSetClipAndReplaceUserBits.
154 GrStencilOp::kZero // kZeroClipAndUserBits.
155 };
156
157 GR_STATIC_ASSERT(0 == (int)GrUserStencilOp::kKeep);
158 GR_STATIC_ASSERT(1 == (int)GrUserStencilOp::kZero);
159 GR_STATIC_ASSERT(2 == (int)GrUserStencilOp::kReplace);
160 GR_STATIC_ASSERT(3 == (int)GrUserStencilOp::kInvert);
161 GR_STATIC_ASSERT(4 == (int)GrUserStencilOp::kIncWrap);
162 GR_STATIC_ASSERT(5 == (int)GrUserStencilOp::kDecWrap);
163 GR_STATIC_ASSERT(6 == (int)GrUserStencilOp::kIncMaybeClamp);
164 GR_STATIC_ASSERT(7 == (int)GrUserStencilOp::kDecMaybeClamp);
165 GR_STATIC_ASSERT(8 == (int)GrUserStencilOp::kZeroClipBit);
166 GR_STATIC_ASSERT(9 == (int)GrUserStencilOp::kSetClipBit);
167 GR_STATIC_ASSERT(10 == (int)GrUserStencilOp::kInvertClipBit);
168 GR_STATIC_ASSERT(11 == (int)GrUserStencilOp::kSetClipAndReplaceUserBits);
169 GR_STATIC_ASSERT(12 == (int)GrUserStencilOp::kZeroClipAndUserBits);
170
reset(const GrUserStencilSettings::Face & user,bool hasStencilClip,int numStencilBits)171 void GrStencilSettings::Face::reset(const GrUserStencilSettings::Face& user, bool hasStencilClip,
172 int numStencilBits) {
173 SkASSERT(user.fTest < (GrUserStencilTest)kGrUserStencilTestCount);
174 SkASSERT(user.fPassOp < (GrUserStencilOp)kGrUserStencilOpCount);
175 SkASSERT(user.fFailOp < (GrUserStencilOp)kGrUserStencilOpCount);
176 SkASSERT(numStencilBits > 0 && numStencilBits <= 16);
177 int clipBit = 1 << (numStencilBits - 1);
178 int userMask = clipBit - 1;
179
180 GrUserStencilOp maxOp = SkTMax(user.fPassOp, user.fFailOp);
181 SkDEBUGCODE(GrUserStencilOp otherOp = SkTMin(user.fPassOp, user.fFailOp);)
182 if (maxOp <= kLastUserOnlyStencilOp) {
183 // Ops that only modify user bits.
184 fWriteMask = user.fWriteMask & userMask;
185 SkASSERT(otherOp <= kLastUserOnlyStencilOp);
186 } else if (maxOp <= kLastClipOnlyStencilOp) {
187 // Ops that only modify the clip bit.
188 fWriteMask = clipBit;
189 SkASSERT(GrUserStencilOp::kKeep == otherOp ||
190 (otherOp > kLastUserOnlyStencilOp && otherOp <= kLastClipOnlyStencilOp));
191 } else {
192 // Ops that modify both clip and user bits.
193 fWriteMask = clipBit | (user.fWriteMask & userMask);
194 SkASSERT(GrUserStencilOp::kKeep == otherOp || otherOp > kLastClipOnlyStencilOp);
195 }
196
197 fFailOp = gUserStencilOpToRaw[(int)user.fFailOp];
198 fPassOp = gUserStencilOpToRaw[(int)user.fPassOp];
199
200 if (!hasStencilClip || user.fTest > kLastClippedStencilTest) {
201 // Ignore the clip.
202 fTestMask = user.fTestMask & userMask;
203 fTest = gUserStencilTestToRaw[(int)user.fTest];
204 } else if (GrUserStencilTest::kAlwaysIfInClip != user.fTest) {
205 // Respect the clip.
206 fTestMask = clipBit | (user.fTestMask & userMask);
207 fTest = gUserStencilTestToRaw[(int)user.fTest];
208 } else {
209 // Test only for clip.
210 fTestMask = clipBit;
211 fTest = GrStencilTest::kEqual;
212 }
213
214 fRef = (clipBit | user.fRef) & (fTestMask | fWriteMask);
215 }
216
setDisabled()217 void GrStencilSettings::Face::setDisabled() {
218 memset(this, 0, sizeof(*this));
219 GR_STATIC_ASSERT(0 == (int)GrStencilTest::kAlways);
220 GR_STATIC_ASSERT(0 == (int)GrStencilOp::kKeep);
221 }
222
223 ////////////////////////////////////////////////////////////////////////////////
224 // Stencil Rules for Merging user stencil space into clip
225 //
226
227 ///////
228 // Replace
229 static constexpr GrUserStencilSettings gUserToClipReplace(
230 GrUserStencilSettings::StaticInit<
231 0x0000,
232 GrUserStencilTest::kNotEqual,
233 0xffff,
234 GrUserStencilOp::kSetClipAndReplaceUserBits,
235 GrUserStencilOp::kZeroClipAndUserBits,
236 0xffff>()
237 );
238
239 static constexpr GrUserStencilSettings gInvUserToClipReplace(
240 GrUserStencilSettings::StaticInit<
241 0x0000,
242 GrUserStencilTest::kEqual,
243 0xffff,
244 GrUserStencilOp::kSetClipAndReplaceUserBits,
245 GrUserStencilOp::kZeroClipAndUserBits,
246 0xffff>()
247 );
248
249 ///////
250 // Intersect
251 static constexpr GrUserStencilSettings gUserToClipIsect(
252 GrUserStencilSettings::StaticInit<
253 0x0000,
254 GrUserStencilTest::kLessIfInClip, // "0 < userBits" is equivalent to "0 != userBits".
255 0xffff,
256 GrUserStencilOp::kSetClipAndReplaceUserBits,
257 GrUserStencilOp::kZeroClipAndUserBits,
258 0xffff>()
259 );
260
261 ///////
262 // Difference
263 static constexpr GrUserStencilSettings gUserToClipDiff(
264 GrUserStencilSettings::StaticInit<
265 0x0000,
266 GrUserStencilTest::kEqualIfInClip,
267 0xffff,
268 GrUserStencilOp::kSetClipAndReplaceUserBits,
269 GrUserStencilOp::kZeroClipAndUserBits,
270 0xffff>()
271 );
272
273 ///////
274 // Union
275 static constexpr GrUserStencilSettings gUserToClipUnion(
276 GrUserStencilSettings::StaticInit<
277 0x0000,
278 GrUserStencilTest::kNotEqual,
279 0xffff,
280 GrUserStencilOp::kSetClipAndReplaceUserBits,
281 GrUserStencilOp::kKeep,
282 0xffff>()
283 );
284
285 static constexpr GrUserStencilSettings gInvUserToClipUnionPass0( // Does not zero user bits.
286 GrUserStencilSettings::StaticInit<
287 0x0000,
288 GrUserStencilTest::kEqual,
289 0xffff,
290 GrUserStencilOp::kSetClipBit,
291 GrUserStencilOp::kKeep,
292 0x0000>()
293 );
294
295 ///////
296 // Xor
297 static constexpr GrUserStencilSettings gUserToClipXorPass0( // Does not zero user bits.
298 GrUserStencilSettings::StaticInit<
299 0x0000,
300 GrUserStencilTest::kNotEqual,
301 0xffff,
302 GrUserStencilOp::kInvertClipBit,
303 GrUserStencilOp::kKeep,
304 0x0000>()
305 );
306
307 static constexpr GrUserStencilSettings gInvUserToClipXorPass0( // Does not zero user bits.
308 GrUserStencilSettings::StaticInit<
309 0x0000,
310 GrUserStencilTest::kEqual,
311 0xffff,
312 GrUserStencilOp::kInvertClipBit,
313 GrUserStencilOp::kKeep,
314 0x0000>()
315 );
316
317 ///////
318 // Reverse Diff
319 static constexpr GrUserStencilSettings gUserToClipRDiffPass0( // Does not zero user bits.
320 GrUserStencilSettings::StaticInit<
321 0x0000,
322 GrUserStencilTest::kNotEqual,
323 0xffff,
324 GrUserStencilOp::kInvertClipBit,
325 GrUserStencilOp::kZeroClipBit,
326 0x0000>()
327 );
328
329 static constexpr GrUserStencilSettings gInvUserToClipRDiffPass0( // Does not zero user bits.
330 GrUserStencilSettings::StaticInit<
331 0x0000,
332 GrUserStencilTest::kEqual,
333 0xffff,
334 GrUserStencilOp::kInvertClipBit,
335 GrUserStencilOp::kZeroClipBit,
336 0x0000>()
337 );
338
339 ///////
340 // Second pass to clear user bits (only needed sometimes)
341 static constexpr GrUserStencilSettings gZeroUserBits(
342 GrUserStencilSettings::StaticInit<
343 0x0000,
344 GrUserStencilTest::kNotEqual,
345 0xffff,
346 GrUserStencilOp::kZero,
347 GrUserStencilOp::kKeep,
348 0xffff>()
349 );
350
351 static constexpr const GrUserStencilSettings* gUserToClipTable[2][1 + SkRegion::kLastOp][3] = {
352 { /* Normal fill. */
353 {&gUserToClipDiff, nullptr, nullptr}, // kDifference_Op.
354 {&gUserToClipIsect, nullptr, nullptr}, // kIntersect_Op.
355 {&gUserToClipUnion, nullptr, nullptr}, // kUnion_Op.
356 {&gUserToClipXorPass0, &gZeroUserBits, nullptr}, // kXOR_Op.
357 {&gUserToClipRDiffPass0, &gZeroUserBits, nullptr}, // kReverseDifference_Op.
358 {&gUserToClipReplace, nullptr, nullptr} // kReplace_Op.
359
360 }, /* Inverse fill. */ {
361 {&gUserToClipIsect, nullptr, nullptr}, // ~diff (aka isect).
362 {&gUserToClipDiff, nullptr, nullptr}, // ~isect (aka diff).
363 {&gInvUserToClipUnionPass0, &gZeroUserBits, nullptr}, // ~union.
364 {&gInvUserToClipXorPass0, &gZeroUserBits, nullptr}, // ~xor.
365 {&gInvUserToClipRDiffPass0, &gZeroUserBits, nullptr}, // ~reverse diff.
366 {&gInvUserToClipReplace, nullptr, nullptr} // ~replace.
367 }
368 };
369
370 GR_STATIC_ASSERT(0 == SkRegion::kDifference_Op);
371 GR_STATIC_ASSERT(1 == SkRegion::kIntersect_Op);
372 GR_STATIC_ASSERT(2 == SkRegion::kUnion_Op);
373 GR_STATIC_ASSERT(3 == SkRegion::kXOR_Op);
374 GR_STATIC_ASSERT(4 == SkRegion::kReverseDifference_Op);
375 GR_STATIC_ASSERT(5 == SkRegion::kReplace_Op);
376
377 ///////
378 // Direct to Stencil
379
380 // We can render a clip element directly without first writing to the client
381 // portion of the clip when the fill is not inverse and the set operation will
382 // only modify the in/out status of samples covered by the clip element.
383
384 // this one only works if used right after stencil clip was cleared.
385 // Our clip mask creation code doesn't allow midstream replace ops.
386 static constexpr GrUserStencilSettings gReplaceClip(
387 GrUserStencilSettings::StaticInit<
388 0x0000,
389 GrUserStencilTest::kAlways,
390 0xffff,
391 GrUserStencilOp::kSetClipBit,
392 GrUserStencilOp::kSetClipBit,
393 0x0000>()
394 );
395
396 static constexpr GrUserStencilSettings gUnionClip(
397 GrUserStencilSettings::StaticInit<
398 0x0000,
399 GrUserStencilTest::kAlwaysIfInClip,
400 0xffff,
401 GrUserStencilOp::kKeep,
402 GrUserStencilOp::kSetClipBit,
403 0x0000>()
404 );
405
406 static constexpr GrUserStencilSettings gXorClip(
407 GrUserStencilSettings::StaticInit<
408 0x0000,
409 GrUserStencilTest::kAlways,
410 0xffff,
411 GrUserStencilOp::kInvertClipBit,
412 GrUserStencilOp::kInvertClipBit,
413 0x0000>()
414 );
415
416 static constexpr GrUserStencilSettings gDiffClip(
417 GrUserStencilSettings::StaticInit<
418 0x0000,
419 GrUserStencilTest::kAlwaysIfInClip,
420 0xffff,
421 GrUserStencilOp::kZeroClipBit,
422 GrUserStencilOp::kKeep,
423 0x0000>()
424 );
425
426 static constexpr const GrUserStencilSettings* gDirectDrawTable[1 + SkRegion::kLastOp][2] = {
427 {&gDiffClip, nullptr}, // kDifference_Op.
428 {nullptr, nullptr}, // kIntersect_Op.
429 {&gUnionClip, nullptr}, // kUnion_Op.
430 {&gXorClip, nullptr}, // kXOR_Op.
431 {nullptr, nullptr}, // kReverseDifference_Op.
432 {&gReplaceClip, nullptr} // kReplace_Op.
433 };
434
435 GR_STATIC_ASSERT(0 == SkRegion::kDifference_Op);
436 GR_STATIC_ASSERT(1 == SkRegion::kIntersect_Op);
437 GR_STATIC_ASSERT(2 == SkRegion::kUnion_Op);
438 GR_STATIC_ASSERT(3 == SkRegion::kXOR_Op);
439 GR_STATIC_ASSERT(4 == SkRegion::kReverseDifference_Op);
440 GR_STATIC_ASSERT(5 == SkRegion::kReplace_Op);
441
GetClipPasses(SkRegion::Op op,bool canBeDirect,bool invertedFill,bool * drawDirectToClip)442 GrUserStencilSettings const* const* GrStencilSettings::GetClipPasses(SkRegion::Op op,
443 bool canBeDirect,
444 bool invertedFill,
445 bool* drawDirectToClip) {
446 SkASSERT((unsigned)op <= SkRegion::kLastOp);
447 if (canBeDirect && !invertedFill) { // TODO: inverse fill + intersect op can be direct.
448 GrUserStencilSettings const* const* directPass = gDirectDrawTable[op];
449 if (directPass[0]) {
450 *drawDirectToClip = true;
451 return directPass;
452 }
453 }
454 *drawDirectToClip = false;
455 return gUserToClipTable[invertedFill][op];
456 }
457
458 static constexpr GrUserStencilSettings gZeroStencilClipBit(
459 GrUserStencilSettings::StaticInit<
460 0x0000,
461 GrUserStencilTest::kAlways,
462 0xffff,
463 GrUserStencilOp::kZeroClipBit,
464 GrUserStencilOp::kZeroClipBit,
465 0x0000>()
466 );
467
SetClipBitSettings(bool setToInside)468 const GrUserStencilSettings* GrStencilSettings::SetClipBitSettings(bool setToInside) {
469 return setToInside ? &gReplaceClip : &gZeroStencilClipBit;
470 }
471
genKey(GrProcessorKeyBuilder * b) const472 void GrStencilSettings::genKey(GrProcessorKeyBuilder* b) const {
473 b->add32(fFlags);
474 if (this->isDisabled()) {
475 return;
476 }
477 if (!this->isTwoSided()) {
478 constexpr int kCount16 = sizeof(Face) / sizeof(uint16_t);
479 GR_STATIC_ASSERT(0 == sizeof(Face) % sizeof(uint16_t));
480 uint16_t* key = reinterpret_cast<uint16_t*>(b->add32n((kCount16 + 1) / 2));
481 memcpy(key, &fFront, sizeof(Face));
482 key[kCount16] = 0;
483 GR_STATIC_ASSERT(1 == kCount16 % 2);
484 } else {
485 constexpr int kCount32 = (2 * sizeof(Face)) / sizeof(uint32_t);
486 GR_STATIC_ASSERT(0 == (2 * sizeof(Face)) % sizeof(uint32_t));
487 uint32_t* key = b->add32n(kCount32);
488 memcpy(key, &fFront, 2 * sizeof(Face));
489 GR_STATIC_ASSERT(sizeof(Face) ==
490 offsetof(GrStencilSettings, fBack) - offsetof(GrStencilSettings, fFront));
491 }
492 // We rely on GrStencilSettings::Face being tightly packed for the key to be reliable.
493 GR_STATIC_ASSERT(0 == offsetof(Face, fRef));
494 GR_STATIC_ASSERT(2 == sizeof(Face::fRef));
495 GR_STATIC_ASSERT(2 == offsetof(Face, fTest));
496 GR_STATIC_ASSERT(2 == sizeof(Face::fTest));
497 GR_STATIC_ASSERT(4 == offsetof(Face, fTestMask));
498 GR_STATIC_ASSERT(2 == sizeof(Face::fTestMask));
499 GR_STATIC_ASSERT(6 == offsetof(Face, fPassOp));
500 GR_STATIC_ASSERT(1 == sizeof(Face::fPassOp));
501 GR_STATIC_ASSERT(7 == offsetof(Face, fFailOp));
502 GR_STATIC_ASSERT(1 == sizeof(Face::fFailOp));
503 GR_STATIC_ASSERT(8 == offsetof(Face, fWriteMask));
504 GR_STATIC_ASSERT(2 == sizeof(Face::fWriteMask));
505 GR_STATIC_ASSERT(10 == sizeof(Face));
506 }
507