|  | 
 | /* | 
 |  * Copyright 2011 Google Inc. | 
 |  * | 
 |  * Use of this source code is governed by a BSD-style license that can be | 
 |  * found in the LICENSE file. | 
 |  */ | 
 |  | 
 |  | 
 | #include "GrStencil.h" | 
 |  | 
 | //////////////////////////////////////////////////////////////////////////////// | 
 | // Stencil Rules for Merging user stencil space into clip | 
 |  | 
 | // We can't include the clip bit in the ref or mask values because the division | 
 | // between user and clip bits in the stencil depends on the number of stencil | 
 | // bits in the runtime. Comments below indicate what the code should do to | 
 | // incorporate the clip bit into these settings. | 
 |  | 
 | /////// | 
 | // Replace | 
 |  | 
 | // set the ref to be the clip bit, but mask it out for the test | 
 | GR_STATIC_CONST_SAME_STENCIL(gUserToClipReplace, | 
 |     kReplace_StencilOp, | 
 |     kZero_StencilOp, | 
 |     kLess_StencilFunc, | 
 |     0xffff,           // unset clip bit | 
 |     0x0000,           // set clip bit | 
 |     0xffff); | 
 |  | 
 | GR_STATIC_CONST_SAME_STENCIL(gInvUserToClipReplace, | 
 |     kReplace_StencilOp, | 
 |     kZero_StencilOp, | 
 |     kEqual_StencilFunc, | 
 |     0xffff,           // unset clip bit | 
 |     0x0000,           // set clip bit | 
 |     0xffff); | 
 |  | 
 | /////// | 
 | // Intersect | 
 | GR_STATIC_CONST_SAME_STENCIL(gUserToClipIsect, | 
 |     kReplace_StencilOp, | 
 |     kZero_StencilOp, | 
 |     kLess_StencilFunc, | 
 |     0xffff, | 
 |     0x0000,           // set clip bit | 
 |     0xffff); | 
 |  | 
 | GR_STATIC_CONST_SAME_STENCIL(gInvUserToClipIsect, | 
 |     kReplace_StencilOp, | 
 |     kZero_StencilOp, | 
 |     kEqual_StencilFunc, | 
 |     0xffff, | 
 |     0x0000,           // set clip bit | 
 |     0xffff); | 
 |  | 
 | /////// | 
 | // Difference | 
 | GR_STATIC_CONST_SAME_STENCIL(gUserToClipDiff, | 
 |     kReplace_StencilOp, | 
 |     kZero_StencilOp, | 
 |     kEqual_StencilFunc, | 
 |     0xffff, | 
 |     0x0000,           // set clip bit | 
 |     0xffff); | 
 |  | 
 | GR_STATIC_CONST_SAME_STENCIL(gInvUserToClipDiff, | 
 |     kReplace_StencilOp, | 
 |     kZero_StencilOp, | 
 |     kLess_StencilFunc, | 
 |     0xffff, | 
 |     0x0000,           // set clip bit | 
 |     0xffff); | 
 |  | 
 | /////// | 
 | // Union | 
 |  | 
 | // first pass makes all the passing cases >= just clip bit set. | 
 | GR_STATIC_CONST_SAME_STENCIL(gUserToClipUnionPass0, | 
 |     kReplace_StencilOp, | 
 |     kKeep_StencilOp, | 
 |     kLEqual_StencilFunc, | 
 |     0xffff, | 
 |     0x0001,           // set clip bit | 
 |     0xffff); | 
 |  | 
 | // second pass allows anything greater than just clip bit set to pass | 
 | GR_STATIC_CONST_SAME_STENCIL(gUserToClipUnionPass1, | 
 |     kReplace_StencilOp, | 
 |     kZero_StencilOp, | 
 |     kLEqual_StencilFunc, | 
 |     0xffff, | 
 |     0x0000,           // set clip bit | 
 |     0xffff); | 
 |  | 
 | // first pass finds zeros in the user bits and if found sets | 
 | // the clip bit to 1 | 
 | GR_STATIC_CONST_SAME_STENCIL(gInvUserToClipUnionPass0, | 
 |     kReplace_StencilOp, | 
 |     kKeep_StencilOp, | 
 |     kEqual_StencilFunc, | 
 |     0xffff, | 
 |     0x0000,           // set clip bit | 
 |     0x0000            // set clip bit | 
 | ); | 
 |  | 
 | // second pass zeros the user bits | 
 | GR_STATIC_CONST_SAME_STENCIL(gInvUserToClipUnionPass1, | 
 |     kZero_StencilOp, | 
 |     kZero_StencilOp, | 
 |     kLess_StencilFunc, | 
 |     0xffff, | 
 |     0x0000, | 
 |     0xffff            // unset clip bit | 
 | ); | 
 |  | 
 | /////// | 
 | // Xor | 
 | GR_STATIC_CONST_SAME_STENCIL(gUserToClipXorPass0, | 
 |     kInvert_StencilOp, | 
 |     kKeep_StencilOp, | 
 |     kEqual_StencilFunc, | 
 |     0xffff,           // unset clip bit | 
 |     0x0000, | 
 |     0xffff); | 
 |  | 
 | GR_STATIC_CONST_SAME_STENCIL(gUserToClipXorPass1, | 
 |     kReplace_StencilOp, | 
 |     kZero_StencilOp, | 
 |     kGreater_StencilFunc, | 
 |     0xffff, | 
 |     0x0000,          // set clip bit | 
 |     0xffff); | 
 |  | 
 | GR_STATIC_CONST_SAME_STENCIL(gInvUserToClipXorPass0, | 
 |     kInvert_StencilOp, | 
 |     kKeep_StencilOp, | 
 |     kEqual_StencilFunc, | 
 |     0xffff,           // unset clip bit | 
 |     0x0000, | 
 |     0xffff); | 
 |  | 
 | GR_STATIC_CONST_SAME_STENCIL(gInvUserToClipXorPass1, | 
 |     kReplace_StencilOp, | 
 |     kZero_StencilOp, | 
 |     kLess_StencilFunc, | 
 |     0xffff, | 
 |     0x0000,          // set clip bit | 
 |     0xffff); | 
 |  | 
 | /////// | 
 | // Reverse Diff | 
 | GR_STATIC_CONST_SAME_STENCIL(gUserToClipRDiffPass0, | 
 |     kInvert_StencilOp, | 
 |     kZero_StencilOp, | 
 |     kLess_StencilFunc, | 
 |     0xffff,         // unset clip bit | 
 |     0x0000,         // set clip bit | 
 |     0xffff); | 
 |  | 
 | GR_STATIC_CONST_SAME_STENCIL(gUserToClipRDiffPass1, | 
 |     kReplace_StencilOp, | 
 |     kZero_StencilOp, | 
 |     kEqual_StencilFunc, | 
 |     0x0000,          // set clip bit | 
 |     0x0000,          // set clip bit | 
 |     0xffff); | 
 |  | 
 | // We are looking for stencil values that are all zero. The first pass sets the | 
 | // clip bit if the stencil is all zeros. The second pass clears the user bits. | 
 | GR_STATIC_CONST_SAME_STENCIL(gInvUserToClipRDiffPass0, | 
 |     kInvert_StencilOp, | 
 |     kZero_StencilOp, | 
 |     kEqual_StencilFunc, | 
 |     0xffff, | 
 |     0x0000, | 
 |     0x0000           // set clip bit | 
 | ); | 
 |  | 
 | GR_STATIC_CONST_SAME_STENCIL(gInvUserToClipRDiffPass1, | 
 |     kZero_StencilOp, | 
 |     kZero_StencilOp, | 
 |     kAlways_StencilFunc, | 
 |     0xffff, | 
 |     0x0000, | 
 |     0xffff           // unset clip bit | 
 | ); | 
 |  | 
 | /////// | 
 | // Direct to Stencil | 
 |  | 
 | // We can render a clip element directly without first writing to the client | 
 | // portion of the clip when the fill is not inverse and the set operation will | 
 | // only modify the in/out status of samples covered by the clip element. | 
 |  | 
 | // this one only works if used right after stencil clip was cleared. | 
 | // Our clip mask creation code doesn't allow midstream replace ops. | 
 | GR_STATIC_CONST_SAME_STENCIL(gReplaceClip, | 
 |     kReplace_StencilOp, | 
 |     kReplace_StencilOp, | 
 |     kAlways_StencilFunc, | 
 |     0xffff, | 
 |     0x0000,           // set clip bit | 
 |     0x0000            // set clipBit | 
 | ); | 
 |  | 
 | GR_STATIC_CONST_SAME_STENCIL(gUnionClip, | 
 |     kReplace_StencilOp, | 
 |     kReplace_StencilOp, | 
 |     kAlways_StencilFunc, | 
 |     0xffff, | 
 |     0x0000,           // set clip bit | 
 |     0x0000            // set clip bit | 
 | ); | 
 |  | 
 | GR_STATIC_CONST_SAME_STENCIL(gXorClip, | 
 |     kInvert_StencilOp, | 
 |     kInvert_StencilOp, | 
 |     kAlways_StencilFunc, | 
 |     0xffff, | 
 |     0x0000, | 
 |     0x0000            // set clip bit | 
 | ); | 
 |  | 
 | GR_STATIC_CONST_SAME_STENCIL(gDiffClip, | 
 |     kZero_StencilOp, | 
 |     kZero_StencilOp, | 
 |     kAlways_StencilFunc, | 
 |     0xffff, | 
 |     0x0000, | 
 |     0x0000            // set clip bit | 
 | ); | 
 |  | 
 | bool GrStencilSettings::GetClipPasses( | 
 |                             SkRegion::Op op, | 
 |                             bool canBeDirect, | 
 |                             unsigned int stencilClipMask, | 
 |                             bool invertedFill, | 
 |                             int* numPasses, | 
 |                             GrStencilSettings settings[kMaxStencilClipPasses]) { | 
 |     if (canBeDirect && !invertedFill) { | 
 |         *numPasses = 0; | 
 |         switch (op) { | 
 |             case SkRegion::kReplace_Op: | 
 |                 *numPasses = 1; | 
 |                 settings[0] = gReplaceClip; | 
 |                 break; | 
 |             case SkRegion::kUnion_Op: | 
 |                 *numPasses = 1; | 
 |                 settings[0] = gUnionClip; | 
 |                 break; | 
 |             case SkRegion::kXOR_Op: | 
 |                 *numPasses = 1; | 
 |                 settings[0] = gXorClip; | 
 |                 break; | 
 |             case SkRegion::kDifference_Op: | 
 |                 *numPasses = 1; | 
 |                 settings[0] = gDiffClip; | 
 |                 break; | 
 |             default: // suppress warning | 
 |                 break; | 
 |         } | 
 |         if (1 == *numPasses) { | 
 |             settings[0].fFuncRefs[kFront_Face]   |= stencilClipMask; | 
 |             settings[0].fWriteMasks[kFront_Face] |= stencilClipMask; | 
 |             settings[0].fFuncRefs[kBack_Face] = | 
 |                 settings[0].fFuncRefs[kFront_Face]; | 
 |             settings[0].fWriteMasks[kBack_Face] = | 
 |                 settings[0].fWriteMasks[kFront_Face]; | 
 |             return true; | 
 |         } | 
 |     } | 
 |     switch (op) { | 
 |         // if we make the path renderer go to stencil we always give it a | 
 |         // non-inverted fill and we use the stencil rules on the client->clipbit | 
 |         // pass to select either the zeros or nonzeros. | 
 |         case SkRegion::kReplace_Op: | 
 |             *numPasses= 1; | 
 |             settings[0] = invertedFill ? gInvUserToClipReplace : | 
 |                                          gUserToClipReplace; | 
 |             settings[0].fFuncMasks[kFront_Face] &= ~stencilClipMask; | 
 |             settings[0].fFuncRefs[kFront_Face] |= stencilClipMask; | 
 |             settings[0].fFuncMasks[kBack_Face] = | 
 |                 settings[0].fFuncMasks[kFront_Face]; | 
 |             settings[0].fFuncRefs[kBack_Face] = | 
 |                 settings[0].fFuncRefs[kFront_Face]; | 
 |             break; | 
 |         case SkRegion::kIntersect_Op: | 
 |             *numPasses = 1; | 
 |             settings[0] = invertedFill ? gInvUserToClipIsect : gUserToClipIsect; | 
 |             settings[0].fFuncRefs[kFront_Face] = stencilClipMask; | 
 |             settings[0].fFuncRefs[kBack_Face] = | 
 |                 settings[0].fFuncRefs[kFront_Face]; | 
 |             break; | 
 |         case SkRegion::kUnion_Op: | 
 |             *numPasses = 2; | 
 |             if (invertedFill) { | 
 |                 settings[0] = gInvUserToClipUnionPass0; | 
 |                 settings[0].fFuncMasks[kFront_Face] &= ~stencilClipMask; | 
 |                 settings[0].fFuncMasks[kBack_Face] = | 
 |                     settings[0].fFuncMasks[kFront_Face]; | 
 |                 settings[0].fFuncRefs[kFront_Face] |= stencilClipMask; | 
 |                 settings[0].fFuncRefs[kBack_Face] = | 
 |                     settings[0].fFuncRefs[kFront_Face]; | 
 |                 settings[0].fWriteMasks[kFront_Face] |= stencilClipMask; | 
 |                 settings[0].fWriteMasks[kBack_Face] = | 
 |                     settings[0].fWriteMasks[kFront_Face]; | 
 |  | 
 |                 settings[1] = gInvUserToClipUnionPass1; | 
 |                 settings[1].fWriteMasks[kFront_Face] &= ~stencilClipMask; | 
 |                 settings[1].fWriteMasks[kBack_Face] &= | 
 |                     settings[1].fWriteMasks[kFront_Face]; | 
 |  | 
 |             } else { | 
 |                 settings[0] = gUserToClipUnionPass0; | 
 |                 settings[0].fFuncMasks[kFront_Face] &= ~stencilClipMask; | 
 |                 settings[0].fFuncRefs[kFront_Face] |= stencilClipMask; | 
 |                 settings[0].fFuncMasks[kBack_Face] = | 
 |                     settings[0].fFuncMasks[kFront_Face]; | 
 |                 settings[0].fFuncRefs[kBack_Face] = | 
 |                     settings[0].fFuncRefs[kFront_Face]; | 
 |  | 
 |                 settings[1] = gUserToClipUnionPass1; | 
 |                 settings[1].fFuncRefs[kFront_Face] |= stencilClipMask; | 
 |                 settings[1].fFuncRefs[kBack_Face] = | 
 |                     settings[1].fFuncRefs[kFront_Face]; | 
 |             } | 
 |             break; | 
 |         case SkRegion::kXOR_Op: | 
 |             *numPasses = 2; | 
 |             if (invertedFill) { | 
 |                 settings[0] = gInvUserToClipXorPass0; | 
 |                 settings[0].fFuncMasks[kFront_Face] &= ~stencilClipMask; | 
 |                 settings[0].fFuncMasks[kBack_Face] = | 
 |                     settings[0].fFuncMasks[kFront_Face]; | 
 |  | 
 |                 settings[1] = gInvUserToClipXorPass1; | 
 |                 settings[1].fFuncRefs[kFront_Face] |= stencilClipMask; | 
 |                 settings[1].fFuncRefs[kBack_Face] = | 
 |                     settings[1].fFuncRefs[kFront_Face]; | 
 |             } else { | 
 |                 settings[0] = gUserToClipXorPass0; | 
 |                 settings[0].fFuncMasks[kFront_Face] &= ~stencilClipMask; | 
 |                 settings[0].fFuncMasks[kBack_Face] = | 
 |                     settings[0].fFuncMasks[kFront_Face]; | 
 |  | 
 |                 settings[1] = gUserToClipXorPass1; | 
 |                 settings[1].fFuncRefs[kFront_Face] |= stencilClipMask; | 
 |                 settings[1].fFuncRefs[kBack_Face] = | 
 |                     settings[1].fFuncRefs[kFront_Face]; | 
 |             } | 
 |             break; | 
 |         case SkRegion::kDifference_Op: | 
 |             *numPasses = 1; | 
 |             settings[0] = invertedFill ? gInvUserToClipDiff : gUserToClipDiff; | 
 |             settings[0].fFuncRefs[kFront_Face] |= stencilClipMask; | 
 |             settings[0].fFuncRefs[kBack_Face] = | 
 |                 settings[0].fFuncRefs[kFront_Face]; | 
 |             break; | 
 |         case SkRegion::kReverseDifference_Op: | 
 |             if (invertedFill) { | 
 |                 *numPasses = 2; | 
 |                 settings[0] = gInvUserToClipRDiffPass0; | 
 |                 settings[0].fWriteMasks[kFront_Face] |= stencilClipMask; | 
 |                 settings[0].fWriteMasks[kBack_Face] = | 
 |                     settings[0].fWriteMasks[kFront_Face]; | 
 |                 settings[1] = gInvUserToClipRDiffPass1; | 
 |                 settings[1].fWriteMasks[kFront_Face] &= ~stencilClipMask; | 
 |                 settings[1].fWriteMasks[kBack_Face] = | 
 |                     settings[1].fWriteMasks[kFront_Face]; | 
 |             } else { | 
 |                 *numPasses = 2; | 
 |                 settings[0] = gUserToClipRDiffPass0; | 
 |                 settings[0].fFuncMasks[kFront_Face] &= ~stencilClipMask; | 
 |                 settings[0].fFuncMasks[kBack_Face] = | 
 |                     settings[0].fFuncMasks[kFront_Face]; | 
 |                 settings[0].fFuncRefs[kFront_Face] |= stencilClipMask; | 
 |                 settings[0].fFuncRefs[kBack_Face] = | 
 |                     settings[0].fFuncRefs[kFront_Face]; | 
 |  | 
 |                 settings[1] = gUserToClipRDiffPass1; | 
 |                 settings[1].fFuncMasks[kFront_Face] |= stencilClipMask; | 
 |                 settings[1].fFuncRefs[kFront_Face] |= stencilClipMask; | 
 |                 settings[1].fFuncMasks[kBack_Face] = | 
 |                     settings[1].fFuncMasks[kFront_Face]; | 
 |                 settings[1].fFuncRefs[kBack_Face] = | 
 |                     settings[1].fFuncRefs[kFront_Face]; | 
 |             } | 
 |             break; | 
 |         default: | 
 |             SkFAIL("Unknown set op"); | 
 |     } | 
 |     return false; | 
 | } |