| bsalomon@google.com | d302f14 | 2011-03-03 13:54:13 +0000 | [diff] [blame] | 1 | /* |
| 2 | Copyright 2011 Google Inc. |
| 3 | |
| 4 | Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | you may not use this file except in compliance with the License. |
| 6 | You may obtain a copy of the License at |
| 7 | |
| 8 | http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | |
| 10 | Unless required by applicable law or agreed to in writing, software |
| 11 | distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | See the License for the specific language governing permissions and |
| 14 | limitations under the License. |
| 15 | */ |
| 16 | |
| 17 | #ifndef GrStencil_DEFINED |
| 18 | #define GrStencil_DEFINED |
| 19 | |
| 20 | #include "GrTypes.h" |
| 21 | /** |
| 22 | * Gr uses the stencil buffer to implement complex clipping inside the |
| 23 | * GrDrawTarget class. The GrDrawTarget makes a subset of the stencil buffer |
| 24 | * bits available for other uses by external code (clients). Client code can |
| 25 | * modify these bits. GrDrawTarget will ignore ref, mask, and writemask bits |
| 26 | * provided by clients that overlap the bits used to implement clipping. The |
| 27 | * client can use the getUsableStencilBits() function to find out how many |
| 28 | * client accessible stencil bits are available. |
| 29 | * |
| 30 | * When code outside the GrDrawTarget class uses the stencil buffer the contract |
| 31 | * is as follows: |
| 32 | * |
| 33 | * > Normal stencil funcs allow the GrGpu client to modify the client bits of |
| 34 | * the stencil buffer outside of the clip. |
| 35 | * > Special functions allow a test against the clip. These are more limited |
| 36 | * than the general stencil functions. |
| 37 | * > Client can assume all client bits are zero initially. |
| 38 | * > Client must ensure that after all its passes are finished it has only |
| 39 | * written to the color buffer in the region inside the clip. Furthermore, it |
| 40 | * must zero all client bits that were modifed (both inside and outside the |
| 41 | * clip). |
| 42 | */ |
| 43 | |
| 44 | /** |
| 45 | * Determines which pixels pass / fail the stencil test. |
| 46 | * Stencil test passes if (ref & mask) FUNC (stencil & mask) is true |
| 47 | */ |
| 48 | enum GrStencilFunc { |
| 49 | kAlways_StencilFunc = 0, |
| 50 | kNever_StencilFunc, |
| 51 | kGreater_StencilFunc, |
| 52 | kGEqual_StencilFunc, |
| 53 | kLess_StencilFunc, |
| 54 | kLEqual_StencilFunc, |
| 55 | kEqual_StencilFunc, |
| 56 | kNotEqual_StencilFunc, |
| 57 | |
| 58 | // Gr stores the current clip in the |
| 59 | // stencil buffer in the high bits that |
| 60 | // are not directly accessible modifiable |
| 61 | // via the GrDrawTarget interface. The below |
| 62 | // stencil funcs test against the current |
| 63 | // clip in addition to the GrDrawTarget |
| 64 | // client's stencil bits. |
| 65 | |
| 66 | // pass if inside the clip |
| 67 | kAlwaysIfInClip_StencilFunc, |
| 68 | kEqualIfInClip_StencilFunc, |
| 69 | kLessIfInClip_StencilFunc, |
| 70 | kLEqualIfInClip_StencilFunc, |
| 71 | kNonZeroIfInClip_StencilFunc, // this one forces the ref to be 0 |
| 72 | |
| 73 | // counts |
| 74 | kStencilFuncCount, |
| 75 | kClipStencilFuncCount = kNonZeroIfInClip_StencilFunc - |
| 76 | kAlwaysIfInClip_StencilFunc + 1, |
| 77 | kBasicStencilFuncCount = kStencilFuncCount - kClipStencilFuncCount |
| 78 | }; |
| 79 | |
| 80 | /** |
| 81 | * Operations to perform based on whether stencil test passed failed. |
| 82 | */ |
| 83 | enum GrStencilOp { |
| 84 | kKeep_StencilOp = 0, // preserve existing stencil value |
| 85 | kReplace_StencilOp, // replace with reference value from stencl test |
| 86 | kIncWrap_StencilOp, // increment and wrap at max |
| 87 | kIncClamp_StencilOp, // increment and clamp at max |
| 88 | kDecWrap_StencilOp, // decrement and wrap at 0 |
| 89 | kDecClamp_StencilOp, // decrement and clamp at 0 |
| 90 | kZero_StencilOp, // zero stencil bits |
| 91 | kInvert_StencilOp, // invert stencil bits |
| 92 | |
| 93 | kStencilOpCount |
| 94 | }; |
| 95 | |
| 96 | /** |
| 97 | * Struct representing stencil state. |
| 98 | */ |
| 99 | struct GrStencilSettings { |
| 100 | GrStencilOp fFrontPassOp; // op to perform when front faces pass |
| 101 | GrStencilOp fBackPassOp; // op to perform when back faces pass |
| 102 | GrStencilOp fFrontFailOp; // op to perform when front faces fail |
| 103 | GrStencilOp fBackFailOp; // op to perform when back faces fail |
| 104 | GrStencilFunc fFrontFunc; // test function for front faces |
| 105 | GrStencilFunc fBackFunc; // test function for back faces |
| 106 | unsigned int fFrontFuncMask; // mask for front face test |
| 107 | unsigned int fBackFuncMask; // mask for back face test |
| 108 | unsigned int fFrontFuncRef; // reference value for front face test |
| 109 | unsigned int fBackFuncRef; // reference value for back face test |
| 110 | unsigned int fFrontWriteMask; // stencil write mask for front faces |
| 111 | unsigned int fBackWriteMask; // stencil write mask for back faces |
| 112 | |
| 113 | bool operator == (const GrStencilSettings& s) const { |
| 114 | // make sure this is tightly packed. |
| 115 | GR_STATIC_ASSERT(0 == sizeof(GrStencilOp)%4); |
| 116 | GR_STATIC_ASSERT(0 == sizeof(GrStencilFunc)%4); |
| 117 | GR_STATIC_ASSERT(sizeof(GrStencilSettings) == |
| 118 | 4*sizeof(GrStencilOp) + |
| 119 | 2*sizeof(GrStencilFunc) + |
| 120 | 6*sizeof(unsigned int)); |
| 121 | return 0 == memcmp(this, &s, sizeof(GrStencilSettings)); |
| 122 | } |
| 123 | |
| 124 | bool operator != (const GrStencilSettings& s) const { |
| 125 | return !(*this == s); |
| 126 | } |
| 127 | |
| 128 | GrStencilSettings& operator =(const GrStencilSettings& s) { |
| 129 | memcpy(this, &s, sizeof(GrStencilSettings)); |
| 130 | return *this; |
| 131 | } |
| 132 | |
| 133 | void setSame(GrStencilOp passOp, |
| 134 | GrStencilOp failOp, |
| 135 | GrStencilFunc func, |
| 136 | unsigned int funcMask, |
| 137 | unsigned int funcRef, |
| 138 | unsigned int writeMask) { |
| 139 | fFrontPassOp = passOp; |
| 140 | fBackPassOp = passOp; |
| 141 | fFrontFailOp = failOp; |
| 142 | fBackFailOp = failOp; |
| 143 | fFrontFunc = func; |
| 144 | fBackFunc = func; |
| 145 | fFrontFuncMask = funcMask; |
| 146 | fBackFuncMask = funcMask; |
| 147 | fFrontFuncRef = funcRef; |
| 148 | fBackFuncRef = funcRef; |
| 149 | fFrontWriteMask = writeMask; |
| 150 | fBackWriteMask = writeMask; |
| 151 | } |
| 152 | |
| 153 | // canonical value for disabled stenciling |
| 154 | static const GrStencilSettings gDisabled; |
| 155 | void setDisabled() { |
| 156 | *this = gDisabled; |
| 157 | } |
| 158 | bool isDisabled() const { |
| 159 | return kKeep_StencilOp == fFrontPassOp && |
| 160 | kKeep_StencilOp == fBackPassOp && |
| 161 | kKeep_StencilOp == fFrontFailOp && |
| bsalomon@google.com | d7beab4 | 2011-05-27 16:42:30 +0000 | [diff] [blame^] | 162 | kKeep_StencilOp == fBackFailOp && |
| bsalomon@google.com | d302f14 | 2011-03-03 13:54:13 +0000 | [diff] [blame] | 163 | kAlways_StencilFunc == fFrontFunc && |
| 164 | kAlways_StencilFunc == fBackFunc; |
| 165 | } |
| 166 | void invalidate() { |
| 167 | // just write an illegal value to the first member |
| 168 | fFrontPassOp = (GrStencilOp)-1; |
| 169 | } |
| 170 | |
| 171 | private: |
| 172 | friend class GrGpu; |
| 173 | |
| 174 | enum { |
| 175 | kMaxStencilClipPasses = 2 // maximum number of passes to add a clip |
| 176 | // element to the stencil buffer. |
| 177 | }; |
| 178 | |
| 179 | /** |
| 180 | * Given a thing to draw into the stencil clip, a fill type, and a set op |
| 181 | * this function determines: |
| 182 | * 1. Whether the thing can be draw directly to the stencil clip or |
| 183 | * needs to be drawn to the client portion of the stencil first. |
| 184 | * 2. How many passes are needed. |
| 185 | * 3. What those passes are. |
| 186 | * 4. The fill rule that should actually be used to render (will |
| 187 | * always be non-inverted). |
| 188 | * |
| 189 | * @param op the set op to combine this element with the |
| 190 | * existing clip |
| 191 | * @param stencilClipMask mask with just the stencil bit used for clipping |
| 192 | * enabled. |
| bsalomon@google.com | 5aaa69e | 2011-03-04 20:29:08 +0000 | [diff] [blame] | 193 | * @param invertedFill is this path inverted |
| bsalomon@google.com | d302f14 | 2011-03-03 13:54:13 +0000 | [diff] [blame] | 194 | * @param numPasses out: the number of passes needed to add the |
| 195 | * element to the clip. |
| 196 | * @param settings out: the stencil settings to use for each pass |
| 197 | * |
| 198 | * @return true if the clip element's geometry can be drawn directly to the |
| 199 | * stencil clip bit. Will only be true if canBeDirect is true. |
| 200 | * numPasses will be 1 if return value is true. |
| 201 | */ |
| 202 | static bool GetClipPasses(GrSetOp op, |
| 203 | bool canBeDirect, |
| 204 | unsigned int stencilClipMask, |
| bsalomon@google.com | 5aaa69e | 2011-03-04 20:29:08 +0000 | [diff] [blame] | 205 | bool invertedFill, |
| bsalomon@google.com | d302f14 | 2011-03-03 13:54:13 +0000 | [diff] [blame] | 206 | int* numPasses, |
| 207 | GrStencilSettings settings[kMaxStencilClipPasses]); |
| 208 | }; |
| 209 | |
| 210 | #endif |