/* * 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); GR_STATIC_CONST_SAME_STENCIL(gInvUserToClipRDiff, kInvert_StencilOp, kZero_StencilOp, kEqual_StencilFunc, 0xffff, 0x0000, 0x0000 // set 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 GrClip 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(GrSetOp op, bool canBeDirect, unsigned int stencilClipMask, bool invertedFill, int* numPasses, GrStencilSettings settings[kMaxStencilClipPasses]) { if (canBeDirect && !invertedFill) { *numPasses = 0; switch (op) { case kReplace_SetOp: *numPasses = 1; settings[0] = gReplaceClip; break; case kUnion_SetOp: *numPasses = 1; settings[0] = gUnionClip; break; case kXor_SetOp: *numPasses = 1; settings[0] = gXorClip; break; case kDifference_SetOp: *numPasses = 1; settings[0] = gDiffClip; break; default: // suppress warning break; } if (1 == *numPasses) { settings[0].fFrontFuncRef |= stencilClipMask; settings[0].fFrontWriteMask |= stencilClipMask; settings[0].fBackFuncRef = settings[0].fFrontFuncRef; settings[0].fBackWriteMask = settings[0].fFrontWriteMask; 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 kReplace_SetOp: *numPasses= 1; settings[0] = invertedFill ? gInvUserToClipReplace : gUserToClipReplace; settings[0].fFrontFuncMask &= ~stencilClipMask; settings[0].fFrontFuncRef |= stencilClipMask; settings[0].fBackFuncMask = settings[0].fFrontFuncMask; settings[0].fBackFuncRef = settings[0].fFrontFuncRef; break; case kIntersect_SetOp: *numPasses = 1; settings[0] = invertedFill ? gInvUserToClipIsect : gUserToClipIsect; settings[0].fFrontFuncRef = stencilClipMask; settings[0].fBackFuncRef = settings[0].fFrontFuncRef; break; case kUnion_SetOp: *numPasses = 2; if (invertedFill) { settings[0] = gInvUserToClipUnionPass0; settings[0].fFrontFuncMask &= ~stencilClipMask; settings[0].fBackFuncMask = settings[0].fFrontFuncMask; settings[0].fFrontFuncRef |= stencilClipMask; settings[0].fBackFuncRef = settings[0].fFrontFuncRef; settings[0].fFrontWriteMask |= stencilClipMask; settings[0].fBackWriteMask = settings[0].fFrontWriteMask; settings[1] = gInvUserToClipUnionPass1; settings[1].fFrontWriteMask &= ~stencilClipMask; settings[1].fBackWriteMask &= settings[1].fFrontWriteMask; } else { settings[0] = gUserToClipUnionPass0; settings[0].fFrontFuncMask &= ~stencilClipMask; settings[0].fFrontFuncRef |= stencilClipMask; settings[0].fBackFuncMask = settings[0].fFrontFuncMask; settings[0].fBackFuncRef = settings[0].fFrontFuncRef; settings[1] = gUserToClipUnionPass1; settings[1].fFrontFuncRef |= stencilClipMask; settings[1].fBackFuncRef = settings[1].fFrontFuncRef; } break; case kXor_SetOp: *numPasses = 2; if (invertedFill) { settings[0] = gInvUserToClipXorPass0; settings[0].fFrontFuncMask &= ~stencilClipMask; settings[0].fBackFuncMask = settings[0].fFrontFuncMask; settings[1] = gInvUserToClipXorPass1; settings[1].fFrontFuncRef |= stencilClipMask; settings[1].fBackFuncRef = settings[1].fFrontFuncRef; } else { settings[0] = gUserToClipXorPass0; settings[0].fFrontFuncMask &= ~stencilClipMask; settings[0].fBackFuncMask = settings[0].fFrontFuncMask; settings[1] = gUserToClipXorPass1; settings[1].fFrontFuncRef |= stencilClipMask; settings[1].fBackFuncRef = settings[1].fFrontFuncRef; } break; case kDifference_SetOp: *numPasses = 1; settings[0] = invertedFill ? gInvUserToClipDiff : gUserToClipDiff; settings[0].fFrontFuncRef |= stencilClipMask; settings[0].fBackFuncRef = settings[0].fFrontFuncRef; break; case kReverseDifference_SetOp: if (invertedFill) { *numPasses = 1; settings[0] = gInvUserToClipRDiff; settings[0].fFrontWriteMask |= stencilClipMask; settings[0].fBackWriteMask = settings[0].fFrontWriteMask; } else { *numPasses = 2; settings[0] = gUserToClipRDiffPass0; settings[0].fFrontFuncMask &= ~stencilClipMask; settings[0].fBackFuncMask = settings[0].fFrontFuncMask; settings[0].fFrontFuncRef |= stencilClipMask; settings[0].fBackFuncRef = settings[0].fFrontFuncRef; settings[1] = gUserToClipRDiffPass1; settings[1].fFrontFuncMask |= stencilClipMask; settings[1].fFrontFuncRef |= stencilClipMask; settings[1].fBackFuncMask = settings[1].fFrontFuncMask; settings[1].fBackFuncRef = settings[1].fFrontFuncRef; } break; default: GrCrash("Unknown set op"); } return false; }