OLD | NEW |
(Empty) | |
| 1 /* |
| 2 * Copyright 2011 Google Inc. |
| 3 * |
| 4 * Use of this source code is governed by a BSD-style license that can be |
| 5 * found in the LICENSE file. |
| 6 */ |
| 7 |
| 8 |
| 9 #ifndef GrStencil_DEFINED |
| 10 #define GrStencil_DEFINED |
| 11 |
| 12 #include "GrTypes.h" |
| 13 #include "SkRegion.h" |
| 14 |
| 15 class GrProcessorKeyBuilder; |
| 16 |
| 17 /** |
| 18 * Gr uses the stencil buffer to implement complex clipping inside the |
| 19 * GrDrawTarget class. The GrDrawTarget makes a subset of the stencil buffer |
| 20 * bits available for other uses by external code (clients). Client code can |
| 21 * modify these bits. GrDrawTarget will ignore ref, mask, and writemask bits |
| 22 * provided by clients that overlap the bits used to implement clipping. |
| 23 * |
| 24 * When code outside the GrDrawTarget class uses the stencil buffer the contract |
| 25 * is as follows: |
| 26 * |
| 27 * > Normal stencil funcs allow the client to pass / fail regardless of the |
| 28 * reserved clip bits. |
| 29 * > Additional functions allow a test against the clip along with a limited |
| 30 * set of tests against the client bits. |
| 31 * > Client can assume all client bits are zero initially. |
| 32 * > Client must ensure that after all its passes are finished it has only |
| 33 * written to the color buffer in the region inside the clip. Furthermore, it |
| 34 * must zero all client bits that were modifed (both inside and outside the |
| 35 * clip). |
| 36 */ |
| 37 |
| 38 /** |
| 39 * Determines which pixels pass / fail the stencil test. |
| 40 * Stencil test passes if (ref & mask) FUNC (stencil & mask) is true |
| 41 */ |
| 42 enum GrStencilFunc { |
| 43 kAlways_StencilFunc = 0, |
| 44 kNever_StencilFunc, |
| 45 kGreater_StencilFunc, |
| 46 kGEqual_StencilFunc, |
| 47 kLess_StencilFunc, |
| 48 kLEqual_StencilFunc, |
| 49 kEqual_StencilFunc, |
| 50 kNotEqual_StencilFunc, |
| 51 |
| 52 // Gr stores the current clip in the |
| 53 // stencil buffer in the high bits that |
| 54 // are not directly accessible modifiable |
| 55 // via the GrDrawTarget interface. The below |
| 56 // stencil funcs test against the current |
| 57 // clip in addition to the GrDrawTarget |
| 58 // client's stencil bits. |
| 59 |
| 60 // pass if inside the clip |
| 61 kAlwaysIfInClip_StencilFunc, |
| 62 kEqualIfInClip_StencilFunc, |
| 63 kLessIfInClip_StencilFunc, |
| 64 kLEqualIfInClip_StencilFunc, |
| 65 kNonZeroIfInClip_StencilFunc, // this one forces the ref to be 0 |
| 66 |
| 67 kLast_StencilFunc = kNonZeroIfInClip_StencilFunc |
| 68 }; |
| 69 |
| 70 static const int kStencilFuncCnt = kLast_StencilFunc + 1; |
| 71 static const int kClipStencilFuncCnt = |
| 72 kNonZeroIfInClip_StencilFunc - kAlwaysIfInClip_StencilFunc + 1; |
| 73 static const int kBasicStencilFuncCnt = kStencilFuncCnt - kClipStencilFuncCnt; |
| 74 |
| 75 /** |
| 76 * Operations to perform based on whether stencil test passed failed. |
| 77 */ |
| 78 enum GrStencilOp { |
| 79 kKeep_StencilOp = 0, // preserve existing stencil value |
| 80 kReplace_StencilOp, // replace with reference value from stencl test |
| 81 kIncWrap_StencilOp, // increment and wrap at max |
| 82 kIncClamp_StencilOp, // increment and clamp at max |
| 83 kDecWrap_StencilOp, // decrement and wrap at 0 |
| 84 kDecClamp_StencilOp, // decrement and clamp at 0 |
| 85 kZero_StencilOp, // zero stencil bits |
| 86 kInvert_StencilOp, // invert stencil bits |
| 87 kLast_StencilOp = kInvert_StencilOp |
| 88 }; |
| 89 static const int kStencilOpCnt = kLast_StencilOp + 1; |
| 90 |
| 91 /** |
| 92 * Class representing stencil state. |
| 93 */ |
| 94 class GrStencilSettings { |
| 95 public: |
| 96 enum Face { |
| 97 kFront_Face = 0, |
| 98 kBack_Face = 1, |
| 99 }; |
| 100 |
| 101 constexpr GrStencilSettings(GrStencilOp passOp, |
| 102 GrStencilOp failOp, |
| 103 GrStencilFunc func, |
| 104 unsigned short funcMask, |
| 105 unsigned short funcRef, |
| 106 unsigned short writeMask) |
| 107 : fPassOps{(uint8_t)passOp, (uint8_t)passOp} |
| 108 , fFailOps{(uint8_t)failOp, (uint8_t)failOp} |
| 109 , fFuncs{(uint8_t)func, (uint8_t)func} |
| 110 , fPad0(0) |
| 111 , fPad1(0) |
| 112 , fFuncMasks{funcMask, funcMask} |
| 113 , fFuncRefs{funcRef, funcRef} |
| 114 , fWriteMasks{writeMask, writeMask} |
| 115 , fFlags(ComputeFlags(passOp, passOp, |
| 116 failOp, failOp, |
| 117 func, func, |
| 118 writeMask, writeMask)) { |
| 119 } |
| 120 |
| 121 constexpr GrStencilSettings(GrStencilOp frontPassOp, GrStencilOp backPassOp
, |
| 122 GrStencilOp frontFailOp, GrStencilOp backFailOp
, |
| 123 GrStencilFunc frontFunc, GrStencilFunc backFunc
, |
| 124 uint16_t frontFuncMask, uint16_t backFuncMask, |
| 125 uint16_t frontFuncRef, uint16_t backFuncRef, |
| 126 uint16_t frontWriteMask, uint16_t backWriteMask
) |
| 127 : fPassOps{(uint8_t)frontPassOp, (uint8_t)backPassOp} |
| 128 , fFailOps{(uint8_t)frontFailOp, (uint8_t)backFailOp} |
| 129 , fFuncs{(uint8_t)frontFunc, (uint8_t)backFunc} |
| 130 , fPad0(0) |
| 131 , fPad1(0) |
| 132 , fFuncMasks{frontFuncMask, backFuncMask} |
| 133 , fFuncRefs{frontFuncRef, backFuncRef} |
| 134 , fWriteMasks{frontWriteMask, backWriteMask} |
| 135 , fFlags(ComputeFlags(frontPassOp, backPassOp, |
| 136 frontFailOp, backFailOp, |
| 137 frontFunc, backFunc, |
| 138 frontWriteMask, backWriteMask)) { |
| 139 } |
| 140 |
| 141 GrStencilSettings() { |
| 142 fPad0 = fPad1 = 0; |
| 143 this->setDisabled(); |
| 144 } |
| 145 |
| 146 GrStencilOp passOp(Face f) const { return static_cast<GrStencilOp>(fPassOps[
f]); } |
| 147 GrStencilOp failOp(Face f) const { return static_cast<GrStencilOp>(fFailOps[
f]); } |
| 148 GrStencilFunc func(Face f) const { return static_cast<GrStencilFunc>(fFuncs[
f]); } |
| 149 uint16_t funcMask(Face f) const { return fFuncMasks[f]; } |
| 150 uint16_t funcRef(Face f) const { return fFuncRefs[f]; } |
| 151 uint16_t writeMask(Face f) const { return fWriteMasks[f]; } |
| 152 |
| 153 void setPassOp(Face f, GrStencilOp op) { fPassOps[f] = op; fFlags = 0;} |
| 154 void setFailOp(Face f, GrStencilOp op) { fFailOps[f] = op; fFlags = 0;} |
| 155 void setFunc(Face f, GrStencilFunc func) { fFuncs[f] = func; fFlags = 0;} |
| 156 void setFuncMask(Face f, unsigned short mask) { fFuncMasks[f] = mask; } |
| 157 void setFuncRef(Face f, unsigned short ref) { fFuncRefs[f] = ref; } |
| 158 void setWriteMask(Face f, unsigned short writeMask) { fWriteMasks[f] = write
Mask; } |
| 159 |
| 160 void copyFrontSettingsToBack() { |
| 161 fPassOps[kBack_Face] = fPassOps[kFront_Face]; |
| 162 fFailOps[kBack_Face] = fFailOps[kFront_Face]; |
| 163 fFuncs[kBack_Face] = fFuncs[kFront_Face]; |
| 164 fFuncMasks[kBack_Face] = fFuncMasks[kFront_Face]; |
| 165 fFuncRefs[kBack_Face] = fFuncRefs[kFront_Face]; |
| 166 fWriteMasks[kBack_Face] = fWriteMasks[kFront_Face]; |
| 167 fFlags = 0; |
| 168 } |
| 169 |
| 170 void setDisabled() { |
| 171 memset(this, 0, sizeof(*this)); |
| 172 GR_STATIC_ASSERT(0 == kKeep_StencilOp); |
| 173 GR_STATIC_ASSERT(0 == kAlways_StencilFunc); |
| 174 fFlags = kIsDisabled_StencilFlag | kDoesNotWrite_StencilFlag; |
| 175 } |
| 176 |
| 177 bool isTwoSided() const { |
| 178 return fPassOps[kFront_Face] != fPassOps[kBack_Face] || |
| 179 fFailOps[kFront_Face] != fFailOps[kBack_Face] || |
| 180 fFuncs[kFront_Face] != fFuncs[kBack_Face] || |
| 181 fFuncMasks[kFront_Face] != fFuncMasks[kBack_Face] || |
| 182 fFuncRefs[kFront_Face] != fFuncRefs[kBack_Face] || |
| 183 fWriteMasks[kFront_Face] != fWriteMasks[kBack_Face]; |
| 184 } |
| 185 |
| 186 bool usesWrapOp() const { |
| 187 return kIncWrap_StencilOp == fPassOps[kFront_Face] || |
| 188 kDecWrap_StencilOp == fPassOps[kFront_Face] || |
| 189 kIncWrap_StencilOp == fPassOps[kBack_Face] || |
| 190 kDecWrap_StencilOp == fPassOps[kBack_Face] || |
| 191 kIncWrap_StencilOp == fFailOps[kFront_Face] || |
| 192 kDecWrap_StencilOp == fFailOps[kFront_Face] || |
| 193 kIncWrap_StencilOp == fFailOps[kBack_Face] || |
| 194 kDecWrap_StencilOp == fFailOps[kBack_Face]; |
| 195 } |
| 196 |
| 197 bool isDisabled() const { |
| 198 if (fFlags & kIsDisabled_StencilFlag) { |
| 199 return true; |
| 200 } |
| 201 if (fFlags & kNotDisabled_StencilFlag) { |
| 202 return false; |
| 203 } |
| 204 bool disabled = this->computeIsDisabled(); |
| 205 fFlags |= disabled ? kIsDisabled_StencilFlag : kNotDisabled_StencilFlag; |
| 206 return disabled; |
| 207 } |
| 208 |
| 209 bool doesWrite() const { |
| 210 if (fFlags & kDoesWrite_StencilFlag) { |
| 211 return true; |
| 212 } |
| 213 if (fFlags & kDoesNotWrite_StencilFlag) { |
| 214 return false; |
| 215 } |
| 216 bool writes = this->computeDoesWrite(); |
| 217 fFlags |= writes ? kDoesWrite_StencilFlag : kDoesNotWrite_StencilFlag; |
| 218 return writes; |
| 219 } |
| 220 |
| 221 void invalidate() { |
| 222 // write an illegal value to the first member |
| 223 fPassOps[0] = kStencilOpCnt; |
| 224 fFlags = 0; |
| 225 } |
| 226 |
| 227 bool isValid() const { return fPassOps[0] < kStencilOpCnt; } |
| 228 |
| 229 void genKey(GrProcessorKeyBuilder* b) const; |
| 230 |
| 231 bool operator==(const GrStencilSettings& s) const { |
| 232 static const size_t gCompareSize = sizeof(GrStencilSettings) - |
| 233 sizeof(fFlags); |
| 234 SkASSERT((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; |
| 249 } |
| 250 |
| 251 private: |
| 252 friend class GrClipMaskManager; |
| 253 |
| 254 enum { |
| 255 kMaxStencilClipPasses = 2 // maximum number of passes to add a clip |
| 256 // element to the stencil buffer. |
| 257 }; |
| 258 |
| 259 /** |
| 260 * Given a thing to draw into the stencil clip, a fill type, and a set op |
| 261 * this function determines: |
| 262 * 1. Whether the thing can be draw directly to the stencil clip or |
| 263 * needs to be drawn to the client portion of the stencil first. |
| 264 * 2. How many passes are needed. |
| 265 * 3. What those passes are. |
| 266 * 4. The fill rule that should actually be used to render (will |
| 267 * always be non-inverted). |
| 268 * |
| 269 * @param op the set op to combine this element with the |
| 270 * existing clip |
| 271 * @param stencilClipMask mask with just the stencil bit used for clipping |
| 272 * enabled. |
| 273 * @param invertedFill is this path inverted |
| 274 * @param numPasses out: the number of passes needed to add the |
| 275 * element to the clip. |
| 276 * @param settings out: the stencil settings to use for each pass |
| 277 * |
| 278 * @return true if the clip element's geometry can be drawn directly to the |
| 279 * stencil clip bit. Will only be true if canBeDirect is true. |
| 280 * numPasses will be 1 if return value is true. |
| 281 */ |
| 282 static bool GetClipPasses(SkRegion::Op op, |
| 283 bool canBeDirect, |
| 284 unsigned int stencilClipMask, |
| 285 bool invertedFill, |
| 286 int* numPasses, |
| 287 GrStencilSettings settings[kMaxStencilClipPasses])
; |
| 288 |
| 289 constexpr static bool IsDisabled(GrStencilOp frontPassOp, GrStencilOp backP
assOp, |
| 290 GrStencilOp frontFailOp, GrStencilOp backF
ailOp, |
| 291 GrStencilFunc frontFunc, GrStencilFunc bac
kFunc) { |
| 292 return (((frontPassOp == kKeep_StencilOp && frontFailOp == kKeep_Stencil
Op)) && |
| 293 ((backPassOp == kKeep_StencilOp && backFailOp == kKeep_Stencil
Op)) && |
| 294 frontFunc == kAlways_StencilFunc && |
| 295 backFunc == kAlways_StencilFunc); |
| 296 } |
| 297 |
| 298 constexpr static bool DoesWrite(GrStencilOp frontPassOp, GrStencilOp backPa
ssOp, |
| 299 GrStencilOp frontFailOp, GrStencilOp backFa
ilOp, |
| 300 GrStencilFunc frontFunc, GrStencilFunc back
Func, |
| 301 uint16_t frontWriteMask, uint16_t backWrite
Mask) { |
| 302 return (0 != (frontWriteMask | backWriteMask)) && |
| 303 // Can we write due to a front face passing the stencil test? |
| 304 ((frontFunc != kNever_StencilFunc && frontPassOp != kKeep_Stenci
lOp) || |
| 305 // Can we write due to a back face passing the stencil test? |
| 306 (backFunc != kNever_StencilFunc && backPassOp != kKeep_Stenci
lOp) || |
| 307 // Can we write due to a front face failing the stencil test? |
| 308 (frontFunc != kAlways_StencilFunc && frontFailOp != kKeep_Stenci
lOp) || |
| 309 // Can we write due to a back face failing the stencil test? |
| 310 (backFunc != kAlways_StencilFunc && backFailOp != kKeep_Stenci
lOp)); |
| 311 } |
| 312 |
| 313 constexpr static uint32_t ComputeFlags(GrStencilOp frontPassOp, GrStencilOp
backPassOp, |
| 314 GrStencilOp frontFailOp, GrStencilOp
backFailOp, |
| 315 GrStencilFunc frontFunc, GrStencilFu
nc backFunc, |
| 316 uint16_t frontWriteMask, uint16_t ba
ckWriteMask) { |
| 317 return (IsDisabled(frontPassOp, backPassOp, frontFailOp, backFailOp, |
| 318 frontFunc, backFunc) |
| 319 ? kIsDisabled_StencilFlag |
| 320 : kNotDisabled_StencilFlag) | |
| 321 (DoesWrite(frontPassOp, backPassOp, frontFailOp, backFailOp, |
| 322 frontFunc, backFunc, frontWriteMask, backWriteMask) |
| 323 ? kDoesWrite_StencilFlag |
| 324 : kDoesNotWrite_StencilFlag); |
| 325 } |
| 326 |
| 327 bool computeIsDisabled() const { |
| 328 return IsDisabled((GrStencilOp) fPassOps[kFront_Face], (GrStencilOp) fPa
ssOps[kBack_Face], |
| 329 (GrStencilOp) fFailOps[kFront_Face], (GrStencilOp) fFa
ilOps[kBack_Face], |
| 330 (GrStencilFunc) fFuncs[kFront_Face], (GrStencilFunc) f
Funcs[kBack_Face]); |
| 331 } |
| 332 bool computeDoesWrite() const { |
| 333 return DoesWrite((GrStencilOp)fPassOps[kFront_Face], (GrStencilOp)fPassO
ps[kBack_Face], |
| 334 (GrStencilOp)fFailOps[kFront_Face], (GrStencilOp)fFailO
ps[kBack_Face], |
| 335 (GrStencilFunc)fFuncs[kFront_Face], (GrStencilFunc)fFun
cs[kBack_Face], |
| 336 fWriteMasks[kFront_Face], fWriteMasks[kBack_F
ace]); |
| 337 } |
| 338 |
| 339 enum GrStencilFlags { |
| 340 kIsDisabled_StencilFlag = 0x1, |
| 341 kNotDisabled_StencilFlag = 0x2, |
| 342 kDoesWrite_StencilFlag = 0x4, |
| 343 kDoesNotWrite_StencilFlag = 0x8, |
| 344 }; |
| 345 |
| 346 uint8_t fPassOps[2]; // op to perform when faces pass (GrStencilOp) |
| 347 uint8_t fFailOps[2]; // op to perform when faces fail (GrStencilOp) |
| 348 uint8_t fFuncs[2]; // test function for faces (GrStencilFunc) |
| 349 uint8_t fPad0; |
| 350 uint8_t fPad1; |
| 351 uint16_t fFuncMasks[2]; // mask for face tests |
| 352 uint16_t fFuncRefs[2]; // reference values for face tests |
| 353 uint16_t fWriteMasks[2]; // stencil write masks |
| 354 mutable uint32_t fFlags; |
| 355 |
| 356 }; |
| 357 |
| 358 // We rely on this being packed and aligned (memcmp'ed and memcpy'ed) |
| 359 GR_STATIC_ASSERT(sizeof(GrStencilSettings) % 4 == 0); |
| 360 GR_STATIC_ASSERT(sizeof(GrStencilSettings) == |
| 361 4*sizeof(uint8_t) + // ops |
| 362 2*sizeof(uint8_t) + // funcs |
| 363 2*sizeof(uint8_t) + // pads |
| 364 2*sizeof(uint16_t) + // func masks |
| 365 2*sizeof(uint16_t) + // ref values |
| 366 2*sizeof(uint16_t) + // write masks |
| 367 sizeof(uint32_t)); // flags |
| 368 |
| 369 #endif |
OLD | NEW |