epoger@google.com | ec3ed6a | 2011-07-28 14:26:00 +0000 | [diff] [blame] | 1 | |
bsalomon@google.com | d302f14 | 2011-03-03 13:54:13 +0000 | [diff] [blame] | 2 | /* |
epoger@google.com | ec3ed6a | 2011-07-28 14:26:00 +0000 | [diff] [blame] | 3 | * Copyright 2011 Google Inc. |
| 4 | * |
| 5 | * Use of this source code is governed by a BSD-style license that can be |
| 6 | * found in the LICENSE file. |
bsalomon@google.com | d302f14 | 2011-03-03 13:54:13 +0000 | [diff] [blame] | 7 | */ |
| 8 | |
epoger@google.com | ec3ed6a | 2011-07-28 14:26:00 +0000 | [diff] [blame] | 9 | |
bsalomon@google.com | d302f14 | 2011-03-03 13:54:13 +0000 | [diff] [blame] | 10 | #ifndef GrStencil_DEFINED |
| 11 | #define GrStencil_DEFINED |
| 12 | |
| 13 | #include "GrTypes.h" |
| 14 | /** |
| 15 | * Gr uses the stencil buffer to implement complex clipping inside the |
| 16 | * GrDrawTarget class. The GrDrawTarget makes a subset of the stencil buffer |
| 17 | * bits available for other uses by external code (clients). Client code can |
| 18 | * modify these bits. GrDrawTarget will ignore ref, mask, and writemask bits |
bsalomon@google.com | dea2f8d | 2011-08-01 15:51:05 +0000 | [diff] [blame] | 19 | * provided by clients that overlap the bits used to implement clipping. |
bsalomon@google.com | d302f14 | 2011-03-03 13:54:13 +0000 | [diff] [blame] | 20 | * |
| 21 | * When code outside the GrDrawTarget class uses the stencil buffer the contract |
| 22 | * is as follows: |
| 23 | * |
bsalomon@google.com | dea2f8d | 2011-08-01 15:51:05 +0000 | [diff] [blame] | 24 | * > Normal stencil funcs allow the client to pass / fail regardless of the |
| 25 | * reserved clip bits. |
| 26 | * > Additional functions allow a test against the clip along with a limited |
| 27 | * set of tests against the client bits. |
bsalomon@google.com | d302f14 | 2011-03-03 13:54:13 +0000 | [diff] [blame] | 28 | * > Client can assume all client bits are zero initially. |
| 29 | * > Client must ensure that after all its passes are finished it has only |
| 30 | * written to the color buffer in the region inside the clip. Furthermore, it |
| 31 | * must zero all client bits that were modifed (both inside and outside the |
| 32 | * clip). |
| 33 | */ |
| 34 | |
| 35 | /** |
| 36 | * Determines which pixels pass / fail the stencil test. |
| 37 | * Stencil test passes if (ref & mask) FUNC (stencil & mask) is true |
| 38 | */ |
| 39 | enum GrStencilFunc { |
| 40 | kAlways_StencilFunc = 0, |
| 41 | kNever_StencilFunc, |
| 42 | kGreater_StencilFunc, |
| 43 | kGEqual_StencilFunc, |
| 44 | kLess_StencilFunc, |
| 45 | kLEqual_StencilFunc, |
| 46 | kEqual_StencilFunc, |
| 47 | kNotEqual_StencilFunc, |
| 48 | |
| 49 | // Gr stores the current clip in the |
| 50 | // stencil buffer in the high bits that |
| 51 | // are not directly accessible modifiable |
| 52 | // via the GrDrawTarget interface. The below |
| 53 | // stencil funcs test against the current |
| 54 | // clip in addition to the GrDrawTarget |
| 55 | // client's stencil bits. |
| 56 | |
| 57 | // pass if inside the clip |
| 58 | kAlwaysIfInClip_StencilFunc, |
| 59 | kEqualIfInClip_StencilFunc, |
| 60 | kLessIfInClip_StencilFunc, |
| 61 | kLEqualIfInClip_StencilFunc, |
| 62 | kNonZeroIfInClip_StencilFunc, // this one forces the ref to be 0 |
| 63 | |
| 64 | // counts |
| 65 | kStencilFuncCount, |
| 66 | kClipStencilFuncCount = kNonZeroIfInClip_StencilFunc - |
| 67 | kAlwaysIfInClip_StencilFunc + 1, |
| 68 | kBasicStencilFuncCount = kStencilFuncCount - kClipStencilFuncCount |
| 69 | }; |
| 70 | |
| 71 | /** |
| 72 | * Operations to perform based on whether stencil test passed failed. |
| 73 | */ |
| 74 | enum GrStencilOp { |
| 75 | kKeep_StencilOp = 0, // preserve existing stencil value |
| 76 | kReplace_StencilOp, // replace with reference value from stencl test |
| 77 | kIncWrap_StencilOp, // increment and wrap at max |
| 78 | kIncClamp_StencilOp, // increment and clamp at max |
| 79 | kDecWrap_StencilOp, // decrement and wrap at 0 |
| 80 | kDecClamp_StencilOp, // decrement and clamp at 0 |
| 81 | kZero_StencilOp, // zero stencil bits |
| 82 | kInvert_StencilOp, // invert stencil bits |
| 83 | |
| 84 | kStencilOpCount |
| 85 | }; |
| 86 | |
| 87 | /** |
bsalomon@google.com | 6b2445e | 2011-12-15 19:47:46 +0000 | [diff] [blame] | 88 | * GrStencilState needs to be a class with accessors and setters so that it |
| 89 | * can maintain flags related to its current state. However, we also want to |
| 90 | * be able to declare pre-made stencil settings at compile time (without |
| 91 | * inserting static initializer code). So all the data members are in this |
| 92 | * struct. A macro defined after the class can be used to jam an instance of |
| 93 | * this struct that is created from an initializer list into a |
| 94 | * GrStencilSettings. (We hang our heads in shame.) |
bsalomon@google.com | d302f14 | 2011-03-03 13:54:13 +0000 | [diff] [blame] | 95 | */ |
bsalomon@google.com | 6b2445e | 2011-12-15 19:47:46 +0000 | [diff] [blame] | 96 | struct GrStencilSettingsStruct { |
tomhudson@google.com | 62b0968 | 2011-11-09 16:39:17 +0000 | [diff] [blame] | 97 | GrStencilOp fFrontPassOp : 8; // op to perform when front faces pass |
| 98 | GrStencilOp fBackPassOp : 8; // op to perform when back faces pass |
| 99 | GrStencilOp fFrontFailOp : 8; // op to perform when front faces fail |
| 100 | GrStencilOp fBackFailOp : 8; // op to perform when back faces fail |
| 101 | GrStencilFunc fFrontFunc : 8; // test function for front faces |
| 102 | GrStencilFunc fBackFunc : 8; // test function for back faces |
bsalomon@google.com | 39dab77 | 2012-01-03 19:39:31 +0000 | [diff] [blame^] | 103 | int fPad0 : 8; |
| 104 | int fPad1 : 8; |
tomhudson@google.com | 62b0968 | 2011-11-09 16:39:17 +0000 | [diff] [blame] | 105 | unsigned short fFrontFuncMask; // mask for front face test |
| 106 | unsigned short fBackFuncMask; // mask for back face test |
| 107 | unsigned short fFrontFuncRef; // reference value for front face test |
| 108 | unsigned short fBackFuncRef; // reference value for back face test |
| 109 | unsigned short fFrontWriteMask; // stencil write mask for front faces |
| 110 | unsigned short fBackWriteMask; // stencil write mask for back faces |
bsalomon@google.com | 39dab77 | 2012-01-03 19:39:31 +0000 | [diff] [blame^] | 111 | mutable uint32_t fFlags; |
bsalomon@google.com | 6b2445e | 2011-12-15 19:47:46 +0000 | [diff] [blame] | 112 | }; |
bsalomon@google.com | 39dab77 | 2012-01-03 19:39:31 +0000 | [diff] [blame^] | 113 | // We rely on this being packed and aligned (memcmp'ed and memcpy'ed) |
| 114 | GR_STATIC_ASSERT(sizeof(GrStencilSettingsStruct) % 4 == 0); |
| 115 | GR_STATIC_ASSERT(sizeof(GrStencilSettingsStruct) == |
| 116 | 4*sizeof(uint8_t) + // ops |
| 117 | 2*sizeof(uint8_t) + // funcs |
| 118 | 2*sizeof(uint8_t) + // pads |
| 119 | 2*sizeof(unsigned short) + // func masks |
| 120 | 2*sizeof(unsigned short) + // ref values |
| 121 | 2*sizeof(unsigned short) + // write masks |
| 122 | sizeof(uint32_t)); // flags |
bsalomon@google.com | d302f14 | 2011-03-03 13:54:13 +0000 | [diff] [blame] | 123 | |
bsalomon@google.com | 6b2445e | 2011-12-15 19:47:46 +0000 | [diff] [blame] | 124 | /** |
| 125 | * Class representing stencil state. |
| 126 | */ |
| 127 | class GrStencilSettings : private GrStencilSettingsStruct { |
| 128 | |
| 129 | public: |
bsalomon@google.com | 39dab77 | 2012-01-03 19:39:31 +0000 | [diff] [blame^] | 130 | GrStencilSettings() { |
| 131 | fPad0 = fPad1 = 0; |
| 132 | this->setDisabled(); |
bsalomon@google.com | d302f14 | 2011-03-03 13:54:13 +0000 | [diff] [blame] | 133 | } |
bsalomon@google.com | 39dab77 | 2012-01-03 19:39:31 +0000 | [diff] [blame^] | 134 | |
bsalomon@google.com | 6b2445e | 2011-12-15 19:47:46 +0000 | [diff] [blame] | 135 | GrStencilOp frontPassOp() const { return fFrontPassOp; } |
| 136 | GrStencilOp backPassOp() const { return fBackPassOp; } |
| 137 | GrStencilOp frontFailOp() const { return fFrontFailOp; } |
| 138 | GrStencilOp backFailOp() const { return fBackFailOp; } |
| 139 | GrStencilFunc frontFunc() const { return fFrontFunc; } |
| 140 | GrStencilFunc backFunc() const { return fBackFunc; } |
| 141 | unsigned short frontFuncMask() const { return fFrontFuncMask; } |
| 142 | unsigned short backFuncMask() const { return fBackFuncMask; } |
| 143 | unsigned short frontFuncRef() const { return fFrontFuncRef; } |
| 144 | unsigned short backFuncRef() const { return fBackFuncRef; } |
| 145 | unsigned short frontWriteMask() const {return fFrontWriteMask; } |
| 146 | unsigned short backWriteMask() const { return fBackWriteMask; } |
| 147 | |
bsalomon@google.com | 39dab77 | 2012-01-03 19:39:31 +0000 | [diff] [blame^] | 148 | void setFrontPassOp(GrStencilOp op) { fFrontPassOp = op; fFlags = 0;} |
| 149 | void setBackPassOp(GrStencilOp op) { fBackPassOp = op; fFlags = 0;} |
| 150 | void setFrontFailOp(GrStencilOp op) {fFrontFailOp = op; fFlags = 0;} |
| 151 | void setBackFailOp(GrStencilOp op) { fBackFailOp = op; fFlags = 0;} |
| 152 | void setFrontFunc(GrStencilFunc func) { fFrontFunc = func; fFlags = 0;} |
| 153 | void setBackFunc(GrStencilFunc func) { fBackFunc = func; fFlags = 0;} |
bsalomon@google.com | 6b2445e | 2011-12-15 19:47:46 +0000 | [diff] [blame] | 154 | void setFrontFuncMask(unsigned short mask) { fFrontFuncMask = mask; } |
| 155 | void setBackFuncMask(unsigned short mask) { fBackFuncMask = mask; } |
| 156 | void setFrontFuncRef(unsigned short ref) { fFrontFuncRef = ref; } |
| 157 | void setBackFuncRef(unsigned short ref) { fBackFuncRef = ref; } |
| 158 | void setFrontWriteMask(unsigned short writeMask) { fFrontWriteMask = writeMask; } |
| 159 | void setBackWriteMask(unsigned short writeMask) { fBackWriteMask = writeMask; } |
| 160 | |
bsalomon@google.com | d302f14 | 2011-03-03 13:54:13 +0000 | [diff] [blame] | 161 | void setSame(GrStencilOp passOp, |
| 162 | GrStencilOp failOp, |
| 163 | GrStencilFunc func, |
tomhudson@google.com | 62b0968 | 2011-11-09 16:39:17 +0000 | [diff] [blame] | 164 | unsigned short funcMask, |
| 165 | unsigned short funcRef, |
| 166 | unsigned short writeMask) { |
bsalomon@google.com | d302f14 | 2011-03-03 13:54:13 +0000 | [diff] [blame] | 167 | fFrontPassOp = passOp; |
| 168 | fBackPassOp = passOp; |
| 169 | fFrontFailOp = failOp; |
| 170 | fBackFailOp = failOp; |
| 171 | fFrontFunc = func; |
| 172 | fBackFunc = func; |
| 173 | fFrontFuncMask = funcMask; |
| 174 | fBackFuncMask = funcMask; |
| 175 | fFrontFuncRef = funcRef; |
| 176 | fBackFuncRef = funcRef; |
| 177 | fFrontWriteMask = writeMask; |
| 178 | fBackWriteMask = writeMask; |
bsalomon@google.com | 39dab77 | 2012-01-03 19:39:31 +0000 | [diff] [blame^] | 179 | fFlags = 0; |
bsalomon@google.com | d302f14 | 2011-03-03 13:54:13 +0000 | [diff] [blame] | 180 | } |
| 181 | |
bsalomon@google.com | d302f14 | 2011-03-03 13:54:13 +0000 | [diff] [blame] | 182 | void setDisabled() { |
bsalomon@google.com | 6b2445e | 2011-12-15 19:47:46 +0000 | [diff] [blame] | 183 | memset(this, 0, sizeof(*this)); |
| 184 | GR_STATIC_ASSERT(0 == kKeep_StencilOp); |
| 185 | GR_STATIC_ASSERT(0 == kAlways_StencilFunc); |
bsalomon@google.com | 39dab77 | 2012-01-03 19:39:31 +0000 | [diff] [blame^] | 186 | fFlags = kIsDisabled_Flag | kDoesNotWrite_Flag; |
bsalomon@google.com | d302f14 | 2011-03-03 13:54:13 +0000 | [diff] [blame] | 187 | } |
bsalomon@google.com | 39dab77 | 2012-01-03 19:39:31 +0000 | [diff] [blame^] | 188 | |
bsalomon@google.com | d302f14 | 2011-03-03 13:54:13 +0000 | [diff] [blame] | 189 | bool isDisabled() const { |
bsalomon@google.com | 39dab77 | 2012-01-03 19:39:31 +0000 | [diff] [blame^] | 190 | if (fFlags & kIsDisabled_Flag) { |
| 191 | return true; |
| 192 | } |
| 193 | if (fFlags & kNotDisabled_Flag) { |
| 194 | return false; |
| 195 | } |
| 196 | bool disabled = kKeep_StencilOp == fFrontPassOp && |
| 197 | kKeep_StencilOp == fBackPassOp && |
| 198 | kKeep_StencilOp == fFrontFailOp && |
| 199 | kKeep_StencilOp == fBackFailOp && |
| 200 | kAlways_StencilFunc == fFrontFunc && |
| 201 | kAlways_StencilFunc == fBackFunc; |
| 202 | fFlags |= disabled ? kIsDisabled_Flag : kNotDisabled_Flag; |
| 203 | return disabled; |
bsalomon@google.com | d302f14 | 2011-03-03 13:54:13 +0000 | [diff] [blame] | 204 | } |
bsalomon@google.com | 39dab77 | 2012-01-03 19:39:31 +0000 | [diff] [blame^] | 205 | |
bsalomon@google.com | 86c1f71 | 2011-10-12 14:54:26 +0000 | [diff] [blame] | 206 | bool doesWrite() const { |
bsalomon@google.com | 39dab77 | 2012-01-03 19:39:31 +0000 | [diff] [blame^] | 207 | if (fFlags & kDoesWrite_Flag) { |
| 208 | return true; |
| 209 | } |
| 210 | if (fFlags & kDoesNotWrite_Flag) { |
| 211 | return false; |
| 212 | } |
| 213 | bool writes = !((kNever_StencilFunc == fFrontFunc || |
| 214 | kKeep_StencilOp == fFrontPassOp) && |
| 215 | (kNever_StencilFunc == fBackFunc || |
| 216 | kKeep_StencilOp == fBackPassOp) && |
| 217 | (kAlways_StencilFunc == fFrontFunc || |
| 218 | kKeep_StencilOp == fFrontFailOp) && |
| 219 | (kAlways_StencilFunc == fBackFunc || |
| 220 | kKeep_StencilOp == fBackFailOp)); |
| 221 | fFlags |= writes ? kDoesWrite_Flag : kDoesNotWrite_Flag; |
| 222 | return writes; |
bsalomon@google.com | 86c1f71 | 2011-10-12 14:54:26 +0000 | [diff] [blame] | 223 | } |
bsalomon@google.com | 39dab77 | 2012-01-03 19:39:31 +0000 | [diff] [blame^] | 224 | |
bsalomon@google.com | d302f14 | 2011-03-03 13:54:13 +0000 | [diff] [blame] | 225 | void invalidate() { |
bsalomon@google.com | 39dab77 | 2012-01-03 19:39:31 +0000 | [diff] [blame^] | 226 | // write an illegal value to the first member |
tomhudson@google.com | 62b0968 | 2011-11-09 16:39:17 +0000 | [diff] [blame] | 227 | fFrontPassOp = (GrStencilOp)(uint8_t)-1; |
bsalomon@google.com | 39dab77 | 2012-01-03 19:39:31 +0000 | [diff] [blame^] | 228 | fFlags = 0; |
| 229 | } |
| 230 | |
| 231 | bool operator == (const GrStencilSettings& s) const { |
| 232 | static const size_t gCompareSize = sizeof(GrStencilSettings) - |
| 233 | sizeof(fFlags); |
| 234 | GrAssert((const char*)&fFlags + sizeof(fFlags) == |
| 235 | (const char*)this + sizeof(GrStencilSettings)); |
| 236 | if (this->isDisabled() & s.isDisabled()) { // using & not && |
| 237 | return true; |
| 238 | } |
| 239 | return 0 == memcmp(this, &s, gCompareSize); |
| 240 | } |
| 241 | |
| 242 | bool operator != (const GrStencilSettings& s) const { |
| 243 | return !(*this == s); |
| 244 | } |
| 245 | |
| 246 | GrStencilSettings& operator =(const GrStencilSettings& s) { |
| 247 | memcpy(this, &s, sizeof(GrStencilSettings)); |
| 248 | return *this; |
bsalomon@google.com | d302f14 | 2011-03-03 13:54:13 +0000 | [diff] [blame] | 249 | } |
| 250 | |
| 251 | private: |
| 252 | friend class GrGpu; |
bsalomon@google.com | 39dab77 | 2012-01-03 19:39:31 +0000 | [diff] [blame^] | 253 | enum { |
| 254 | kIsDisabled_Flag = 0x1, |
| 255 | kNotDisabled_Flag = 0x2, |
| 256 | kDoesWrite_Flag = 0x4, |
| 257 | kDoesNotWrite_Flag = 0x8, |
| 258 | }; |
bsalomon@google.com | d302f14 | 2011-03-03 13:54:13 +0000 | [diff] [blame] | 259 | |
| 260 | enum { |
| 261 | kMaxStencilClipPasses = 2 // maximum number of passes to add a clip |
| 262 | // element to the stencil buffer. |
| 263 | }; |
| 264 | |
| 265 | /** |
| 266 | * Given a thing to draw into the stencil clip, a fill type, and a set op |
| 267 | * this function determines: |
| 268 | * 1. Whether the thing can be draw directly to the stencil clip or |
| 269 | * needs to be drawn to the client portion of the stencil first. |
| 270 | * 2. How many passes are needed. |
| 271 | * 3. What those passes are. |
| 272 | * 4. The fill rule that should actually be used to render (will |
| 273 | * always be non-inverted). |
| 274 | * |
| 275 | * @param op the set op to combine this element with the |
| 276 | * existing clip |
| 277 | * @param stencilClipMask mask with just the stencil bit used for clipping |
| 278 | * enabled. |
bsalomon@google.com | 5aaa69e | 2011-03-04 20:29:08 +0000 | [diff] [blame] | 279 | * @param invertedFill is this path inverted |
bsalomon@google.com | d302f14 | 2011-03-03 13:54:13 +0000 | [diff] [blame] | 280 | * @param numPasses out: the number of passes needed to add the |
| 281 | * element to the clip. |
| 282 | * @param settings out: the stencil settings to use for each pass |
| 283 | * |
| 284 | * @return true if the clip element's geometry can be drawn directly to the |
| 285 | * stencil clip bit. Will only be true if canBeDirect is true. |
| 286 | * numPasses will be 1 if return value is true. |
| 287 | */ |
| 288 | static bool GetClipPasses(GrSetOp op, |
| 289 | bool canBeDirect, |
| 290 | unsigned int stencilClipMask, |
bsalomon@google.com | 5aaa69e | 2011-03-04 20:29:08 +0000 | [diff] [blame] | 291 | bool invertedFill, |
bsalomon@google.com | d302f14 | 2011-03-03 13:54:13 +0000 | [diff] [blame] | 292 | int* numPasses, |
| 293 | GrStencilSettings settings[kMaxStencilClipPasses]); |
| 294 | }; |
| 295 | |
bsalomon@google.com | 6b2445e | 2011-12-15 19:47:46 +0000 | [diff] [blame] | 296 | GR_STATIC_ASSERT(sizeof(GrStencilSettingsStruct) == sizeof(GrStencilSettings)); |
| 297 | |
| 298 | #define GR_STATIC_CONST_STENCIL(NAME, \ |
| 299 | FRONT_PASS_OP, BACK_PASS_OP, \ |
| 300 | FRONT_FAIL_OP, BACK_FAIL_OP, \ |
| 301 | FRONT_FUNC, BACK_FUNC, \ |
| 302 | FRONT_MASK, BACK_MASK, \ |
| 303 | FRONT_REF, BACK_REF, \ |
| 304 | FRONT_WRITE_MASK, BACK_WRITE_MASK) \ |
| 305 | static const GrStencilSettingsStruct NAME ## _STRUCT = { \ |
| 306 | (FRONT_PASS_OP), (BACK_PASS_OP), \ |
| 307 | (FRONT_FAIL_OP), (BACK_FAIL_OP), \ |
| 308 | (FRONT_FUNC), (BACK_FUNC), \ |
bsalomon@google.com | 39dab77 | 2012-01-03 19:39:31 +0000 | [diff] [blame^] | 309 | (0), (0), \ |
bsalomon@google.com | 6b2445e | 2011-12-15 19:47:46 +0000 | [diff] [blame] | 310 | (FRONT_MASK), (BACK_MASK), \ |
| 311 | (FRONT_REF), (BACK_REF), \ |
bsalomon@google.com | 39dab77 | 2012-01-03 19:39:31 +0000 | [diff] [blame^] | 312 | (FRONT_WRITE_MASK), (BACK_WRITE_MASK), \ |
| 313 | 0 \ |
bsalomon@google.com | 6b2445e | 2011-12-15 19:47:46 +0000 | [diff] [blame] | 314 | }; \ |
| 315 | static const GrStencilSettings& NAME = \ |
bsalomon@google.com | c315aeb | 2011-12-15 19:51:05 +0000 | [diff] [blame] | 316 | *reinterpret_cast<const GrStencilSettings*>(&(NAME ## _STRUCT)) |
bsalomon@google.com | d302f14 | 2011-03-03 13:54:13 +0000 | [diff] [blame] | 317 | #endif |
bsalomon@google.com | 6b2445e | 2011-12-15 19:47:46 +0000 | [diff] [blame] | 318 | |
| 319 | #define GR_STATIC_CONST_SAME_STENCIL(NAME, \ |
| 320 | PASS_OP, FAIL_OP, FUNC, MASK, REF, WRITE_MASK) \ |
| 321 | GR_STATIC_CONST_STENCIL(NAME, (PASS_OP), (PASS_OP), (FAIL_OP), \ |
| 322 | (FAIL_OP), (FUNC), (FUNC), (MASK), (MASK), (REF), (REF), (WRITE_MASK), \ |
| 323 | (WRITE_MASK)) |