| |
| /* |
| * Copyright 2011 Google Inc. |
| * |
| * Use of this source code is governed by a BSD-style license that can be |
| * found in the LICENSE file. |
| */ |
| |
| |
| #ifndef GrStencil_DEFINED |
| #define GrStencil_DEFINED |
| |
| #include "GrTypes.h" |
| /** |
| * Gr uses the stencil buffer to implement complex clipping inside the |
| * GrDrawTarget class. The GrDrawTarget makes a subset of the stencil buffer |
| * bits available for other uses by external code (clients). Client code can |
| * modify these bits. GrDrawTarget will ignore ref, mask, and writemask bits |
| * provided by clients that overlap the bits used to implement clipping. |
| * |
| * When code outside the GrDrawTarget class uses the stencil buffer the contract |
| * is as follows: |
| * |
| * > Normal stencil funcs allow the client to pass / fail regardless of the |
| * reserved clip bits. |
| * > Additional functions allow a test against the clip along with a limited |
| * set of tests against the client bits. |
| * > Client can assume all client bits are zero initially. |
| * > Client must ensure that after all its passes are finished it has only |
| * written to the color buffer in the region inside the clip. Furthermore, it |
| * must zero all client bits that were modifed (both inside and outside the |
| * clip). |
| */ |
| |
| /** |
| * Determines which pixels pass / fail the stencil test. |
| * Stencil test passes if (ref & mask) FUNC (stencil & mask) is true |
| */ |
| enum GrStencilFunc { |
| kAlways_StencilFunc = 0, |
| kNever_StencilFunc, |
| kGreater_StencilFunc, |
| kGEqual_StencilFunc, |
| kLess_StencilFunc, |
| kLEqual_StencilFunc, |
| kEqual_StencilFunc, |
| kNotEqual_StencilFunc, |
| |
| // Gr stores the current clip in the |
| // stencil buffer in the high bits that |
| // are not directly accessible modifiable |
| // via the GrDrawTarget interface. The below |
| // stencil funcs test against the current |
| // clip in addition to the GrDrawTarget |
| // client's stencil bits. |
| |
| // pass if inside the clip |
| kAlwaysIfInClip_StencilFunc, |
| kEqualIfInClip_StencilFunc, |
| kLessIfInClip_StencilFunc, |
| kLEqualIfInClip_StencilFunc, |
| kNonZeroIfInClip_StencilFunc, // this one forces the ref to be 0 |
| |
| // counts |
| kStencilFuncCount, |
| kClipStencilFuncCount = kNonZeroIfInClip_StencilFunc - |
| kAlwaysIfInClip_StencilFunc + 1, |
| kBasicStencilFuncCount = kStencilFuncCount - kClipStencilFuncCount |
| }; |
| |
| /** |
| * Operations to perform based on whether stencil test passed failed. |
| */ |
| enum GrStencilOp { |
| kKeep_StencilOp = 0, // preserve existing stencil value |
| kReplace_StencilOp, // replace with reference value from stencl test |
| kIncWrap_StencilOp, // increment and wrap at max |
| kIncClamp_StencilOp, // increment and clamp at max |
| kDecWrap_StencilOp, // decrement and wrap at 0 |
| kDecClamp_StencilOp, // decrement and clamp at 0 |
| kZero_StencilOp, // zero stencil bits |
| kInvert_StencilOp, // invert stencil bits |
| |
| kStencilOpCount |
| }; |
| |
| /** |
| * Struct representing stencil state. |
| */ |
| struct GrStencilSettings { |
| GrStencilOp fFrontPassOp; // op to perform when front faces pass |
| GrStencilOp fBackPassOp; // op to perform when back faces pass |
| GrStencilOp fFrontFailOp; // op to perform when front faces fail |
| GrStencilOp fBackFailOp; // op to perform when back faces fail |
| GrStencilFunc fFrontFunc; // test function for front faces |
| GrStencilFunc fBackFunc; // test function for back faces |
| unsigned int fFrontFuncMask; // mask for front face test |
| unsigned int fBackFuncMask; // mask for back face test |
| unsigned int fFrontFuncRef; // reference value for front face test |
| unsigned int fBackFuncRef; // reference value for back face test |
| unsigned int fFrontWriteMask; // stencil write mask for front faces |
| unsigned int fBackWriteMask; // stencil write mask for back faces |
| |
| bool operator == (const GrStencilSettings& s) const { |
| // make sure this is tightly packed. |
| GR_STATIC_ASSERT(0 == sizeof(GrStencilOp)%4); |
| GR_STATIC_ASSERT(0 == sizeof(GrStencilFunc)%4); |
| GR_STATIC_ASSERT(sizeof(GrStencilSettings) == |
| 4*sizeof(GrStencilOp) + |
| 2*sizeof(GrStencilFunc) + |
| 6*sizeof(unsigned int)); |
| return 0 == memcmp(this, &s, sizeof(GrStencilSettings)); |
| } |
| |
| bool operator != (const GrStencilSettings& s) const { |
| return !(*this == s); |
| } |
| |
| GrStencilSettings& operator =(const GrStencilSettings& s) { |
| memcpy(this, &s, sizeof(GrStencilSettings)); |
| return *this; |
| } |
| |
| void setSame(GrStencilOp passOp, |
| GrStencilOp failOp, |
| GrStencilFunc func, |
| unsigned int funcMask, |
| unsigned int funcRef, |
| unsigned int writeMask) { |
| fFrontPassOp = passOp; |
| fBackPassOp = passOp; |
| fFrontFailOp = failOp; |
| fBackFailOp = failOp; |
| fFrontFunc = func; |
| fBackFunc = func; |
| fFrontFuncMask = funcMask; |
| fBackFuncMask = funcMask; |
| fFrontFuncRef = funcRef; |
| fBackFuncRef = funcRef; |
| fFrontWriteMask = writeMask; |
| fBackWriteMask = writeMask; |
| } |
| |
| // canonical value for disabled stenciling |
| static const GrStencilSettings gDisabled; |
| void setDisabled() { |
| *this = gDisabled; |
| } |
| bool isDisabled() const { |
| return kKeep_StencilOp == fFrontPassOp && |
| kKeep_StencilOp == fBackPassOp && |
| kKeep_StencilOp == fFrontFailOp && |
| kKeep_StencilOp == fBackFailOp && |
| kAlways_StencilFunc == fFrontFunc && |
| kAlways_StencilFunc == fBackFunc; |
| } |
| bool doesWrite() const { |
| return !((kNever_StencilFunc == fFrontFunc || |
| kKeep_StencilOp == fFrontPassOp) && |
| (kNever_StencilFunc == fBackFunc || |
| kKeep_StencilOp == fBackPassOp) && |
| (kAlways_StencilFunc == fFrontFunc || |
| kKeep_StencilOp == fFrontFailOp) && |
| (kAlways_StencilFunc == fBackFunc || |
| kKeep_StencilOp == fBackFailOp)); |
| } |
| void invalidate() { |
| // just write an illegal value to the first member |
| fFrontPassOp = (GrStencilOp)-1; |
| } |
| |
| private: |
| friend class GrGpu; |
| |
| enum { |
| kMaxStencilClipPasses = 2 // maximum number of passes to add a clip |
| // element to the stencil buffer. |
| }; |
| |
| /** |
| * Given a thing to draw into the stencil clip, a fill type, and a set op |
| * this function determines: |
| * 1. Whether the thing can be draw directly to the stencil clip or |
| * needs to be drawn to the client portion of the stencil first. |
| * 2. How many passes are needed. |
| * 3. What those passes are. |
| * 4. The fill rule that should actually be used to render (will |
| * always be non-inverted). |
| * |
| * @param op the set op to combine this element with the |
| * existing clip |
| * @param stencilClipMask mask with just the stencil bit used for clipping |
| * enabled. |
| * @param invertedFill is this path inverted |
| * @param numPasses out: the number of passes needed to add the |
| * element to the clip. |
| * @param settings out: the stencil settings to use for each pass |
| * |
| * @return true if the clip element's geometry can be drawn directly to the |
| * stencil clip bit. Will only be true if canBeDirect is true. |
| * numPasses will be 1 if return value is true. |
| */ |
| static bool GetClipPasses(GrSetOp op, |
| bool canBeDirect, |
| unsigned int stencilClipMask, |
| bool invertedFill, |
| int* numPasses, |
| GrStencilSettings settings[kMaxStencilClipPasses]); |
| }; |
| |
| #endif |