Home | History | Annotate | Download | only in gpu
      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 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 
     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 
     70 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 
    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 
    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 
    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 
    468 const GrUserStencilSettings* GrStencilSettings::SetClipBitSettings(bool setToInside) {
    469     return setToInside ? &gReplaceClip : &gZeroStencilClipBit;
    470 }
    471 
    472 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