Line data Source code
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 "GrStencilSettings.h"
10 :
11 : #include "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 :
27 0 : void GrStencilSettings::reset(const GrUserStencilSettings& user, bool hasStencilClip,
28 : int numStencilBits) {
29 0 : uint16_t frontFlags = user.fFrontFlags[hasStencilClip];
30 0 : if (frontFlags & kSingleSided_StencilFlag) {
31 0 : SkASSERT(frontFlags == user.fBackFlags[hasStencilClip]);
32 0 : fFlags = frontFlags;
33 0 : if (!this->isDisabled()) {
34 0 : fFront.reset(user.fFront, hasStencilClip, numStencilBits);
35 : }
36 0 : return;
37 : }
38 :
39 0 : uint16_t backFlags = user.fBackFlags[hasStencilClip];
40 0 : fFlags = frontFlags & backFlags;
41 0 : if (this->isDisabled()) {
42 0 : return;
43 : }
44 0 : if (!(frontFlags & kDisabled_StencilFlag)) {
45 0 : fFront.reset(user.fFront, hasStencilClip, numStencilBits);
46 : } else {
47 0 : fFront.setDisabled();
48 : }
49 0 : if (!(backFlags & kDisabled_StencilFlag)) {
50 0 : fBack.reset(user.fBack, hasStencilClip, numStencilBits);
51 : } else {
52 0 : fBack.setDisabled();
53 : }
54 : }
55 :
56 0 : void GrStencilSettings::reset(const GrStencilSettings& that) {
57 0 : fFlags = that.fFlags;
58 0 : if ((kInvalid_PrivateFlag | kDisabled_StencilFlag) & fFlags) {
59 0 : return;
60 : }
61 0 : if (!this->isTwoSided()) {
62 0 : memcpy(&fFront, &that.fFront, sizeof(Face));
63 : } else {
64 0 : memcpy(&fFront, &that.fFront, 2 * sizeof(Face));
65 : GR_STATIC_ASSERT(sizeof(Face) ==
66 : offsetof(GrStencilSettings, fBack) - offsetof(GrStencilSettings, fFront));
67 : }
68 : }
69 :
70 0 : bool GrStencilSettings::operator==(const GrStencilSettings& that) const {
71 0 : if ((kInvalid_PrivateFlag | kDisabled_StencilFlag) & (fFlags | that.fFlags)) {
72 : // At least one is invalid and/or disabled.
73 0 : if (kInvalid_PrivateFlag & (fFlags | that.fFlags)) {
74 0 : return false; // We never allow invalid stencils to be equal.
75 : }
76 : // They're only equal if both are disabled.
77 0 : return kDisabled_StencilFlag & (fFlags & that.fFlags);
78 : }
79 0 : if (kSingleSided_StencilFlag & (fFlags & that.fFlags)) {
80 0 : return 0 == memcmp(&fFront, &that.fFront, sizeof(Face)); // Both are single sided.
81 0 : } else if (kSingleSided_StencilFlag & (fFlags | that.fFlags)) {
82 0 : return false;
83 : } else {
84 0 : 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 :
171 0 : void GrStencilSettings::Face::reset(const GrUserStencilSettings::Face& user, bool hasStencilClip,
172 : int numStencilBits) {
173 0 : SkASSERT(user.fTest < (GrUserStencilTest)kGrUserStencilTestCount);
174 0 : SkASSERT(user.fPassOp < (GrUserStencilOp)kGrUserStencilOpCount);
175 0 : SkASSERT(user.fFailOp < (GrUserStencilOp)kGrUserStencilOpCount);
176 0 : SkASSERT(numStencilBits > 0 && numStencilBits <= 16);
177 0 : int clipBit = 1 << (numStencilBits - 1);
178 0 : int userMask = clipBit - 1;
179 :
180 0 : GrUserStencilOp maxOp = SkTMax(user.fPassOp, user.fFailOp);
181 0 : SkDEBUGCODE(GrUserStencilOp otherOp = SkTMin(user.fPassOp, user.fFailOp);)
182 0 : if (maxOp <= kLastUserOnlyStencilOp) {
183 : // Ops that only modify user bits.
184 0 : fWriteMask = user.fWriteMask & userMask;
185 0 : SkASSERT(otherOp <= kLastUserOnlyStencilOp);
186 0 : } else if (maxOp <= kLastClipOnlyStencilOp) {
187 : // Ops that only modify the clip bit.
188 0 : fWriteMask = clipBit;
189 0 : SkASSERT(GrUserStencilOp::kKeep == otherOp ||
190 : (otherOp > kLastUserOnlyStencilOp && otherOp <= kLastClipOnlyStencilOp));
191 : } else {
192 : // Ops that modify both clip and user bits.
193 0 : fWriteMask = clipBit | (user.fWriteMask & userMask);
194 0 : SkASSERT(GrUserStencilOp::kKeep == otherOp || otherOp > kLastClipOnlyStencilOp);
195 : }
196 :
197 0 : fFailOp = gUserStencilOpToRaw[(int)user.fFailOp];
198 0 : fPassOp = gUserStencilOpToRaw[(int)user.fPassOp];
199 :
200 0 : if (!hasStencilClip || user.fTest > kLastClippedStencilTest) {
201 : // Ignore the clip.
202 0 : fTestMask = user.fTestMask & userMask;
203 0 : fTest = gUserStencilTestToRaw[(int)user.fTest];
204 0 : } else if (GrUserStencilTest::kAlwaysIfInClip != user.fTest) {
205 : // Respect the clip.
206 0 : fTestMask = clipBit | (user.fTestMask & userMask);
207 0 : fTest = gUserStencilTestToRaw[(int)user.fTest];
208 : } else {
209 : // Test only for clip.
210 0 : fTestMask = clipBit;
211 0 : fTest = GrStencilTest::kEqual;
212 : }
213 :
214 0 : fRef = (clipBit | user.fRef) & (fTestMask | fWriteMask);
215 0 : }
216 :
217 0 : void GrStencilSettings::Face::setDisabled() {
218 0 : memset(this, 0, sizeof(*this));
219 : GR_STATIC_ASSERT(0 == (int)GrStencilTest::kAlways);
220 : GR_STATIC_ASSERT(0 == (int)GrStencilOp::kKeep);
221 0 : }
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 :
442 0 : GrUserStencilSettings const* const* GrStencilSettings::GetClipPasses(SkRegion::Op op,
443 : bool canBeDirect,
444 : bool invertedFill,
445 : bool* drawDirectToClip) {
446 0 : SkASSERT((unsigned)op <= SkRegion::kLastOp);
447 0 : if (canBeDirect && !invertedFill) { // TODO: inverse fill + intersect op can be direct.
448 0 : GrUserStencilSettings const* const* directPass = gDirectDrawTable[op];
449 0 : if (directPass[0]) {
450 0 : *drawDirectToClip = true;
451 0 : return directPass;
452 : }
453 : }
454 0 : *drawDirectToClip = false;
455 0 : return gUserToClipTable[invertedFill][op];
456 : }
457 :
458 0 : void GrStencilSettings::genKey(GrProcessorKeyBuilder* b) const {
459 0 : b->add32(fFlags);
460 0 : if (this->isDisabled()) {
461 0 : return;
462 : }
463 0 : if (!this->isTwoSided()) {
464 0 : constexpr int kCount16 = sizeof(Face) / sizeof(uint16_t);
465 : GR_STATIC_ASSERT(0 == sizeof(Face) % sizeof(uint16_t));
466 0 : uint16_t* key = reinterpret_cast<uint16_t*>(b->add32n((kCount16 + 1) / 2));
467 0 : memcpy(key, &fFront, sizeof(Face));
468 0 : key[kCount16] = 0;
469 : GR_STATIC_ASSERT(1 == kCount16 % 2);
470 : } else {
471 0 : constexpr int kCount32 = (2 * sizeof(Face)) / sizeof(uint32_t);
472 : GR_STATIC_ASSERT(0 == (2 * sizeof(Face)) % sizeof(uint32_t));
473 0 : uint32_t* key = b->add32n(kCount32);
474 0 : memcpy(key, &fFront, 2 * sizeof(Face));
475 : GR_STATIC_ASSERT(sizeof(Face) ==
476 : offsetof(GrStencilSettings, fBack) - offsetof(GrStencilSettings, fFront));
477 : }
478 : // We rely on GrStencilSettings::Face being tightly packed for the key to be reliable.
479 : GR_STATIC_ASSERT(0 == offsetof(Face, fRef));
480 : GR_STATIC_ASSERT(2 == sizeof(Face::fRef));
481 : GR_STATIC_ASSERT(2 == offsetof(Face, fTest));
482 : GR_STATIC_ASSERT(2 == sizeof(Face::fTest));
483 : GR_STATIC_ASSERT(4 == offsetof(Face, fTestMask));
484 : GR_STATIC_ASSERT(2 == sizeof(Face::fTestMask));
485 : GR_STATIC_ASSERT(6 == offsetof(Face, fPassOp));
486 : GR_STATIC_ASSERT(1 == sizeof(Face::fPassOp));
487 : GR_STATIC_ASSERT(7 == offsetof(Face, fFailOp));
488 : GR_STATIC_ASSERT(1 == sizeof(Face::fFailOp));
489 : GR_STATIC_ASSERT(8 == offsetof(Face, fWriteMask));
490 : GR_STATIC_ASSERT(2 == sizeof(Face::fWriteMask));
491 : GR_STATIC_ASSERT(10 == sizeof(Face));
492 : }
|