diff -r 000000000000 -r 6474c204b198 gfx/skia/trunk/src/gpu/GrStencil.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gfx/skia/trunk/src/gpu/GrStencil.h Wed Dec 31 06:09:35 2014 +0100 @@ -0,0 +1,395 @@ + +/* + * 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" +#include "SkRegion.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 +}; + +enum GrStencilFlags { + kIsDisabled_StencilFlag = 0x1, + kNotDisabled_StencilFlag = 0x2, + kDoesWrite_StencilFlag = 0x4, + kDoesNotWrite_StencilFlag = 0x8, +}; + +/** + * GrStencilState needs to be a class with accessors and setters so that it + * can maintain flags related to its current state. However, we also want to + * be able to declare pre-made stencil settings at compile time (without + * inserting static initializer code). So all the data members are in this + * struct. A macro defined after the class can be used to jam an instance of + * this struct that is created from an initializer list into a + * GrStencilSettings. (We hang our heads in shame.) + */ +struct GrStencilSettingsStruct { + uint8_t fPassOps[2]; // op to perform when faces pass (GrStencilOp) + uint8_t fFailOps[2]; // op to perform when faces fail (GrStencilOp) + uint8_t fFuncs[2]; // test function for faces (GrStencilFunc) + uint8_t fPad0; + uint8_t fPad1; + uint16_t fFuncMasks[2]; // mask for face tests + uint16_t fFuncRefs[2]; // reference values for face tests + uint16_t fWriteMasks[2]; // stencil write masks + mutable uint32_t fFlags; +}; +// We rely on this being packed and aligned (memcmp'ed and memcpy'ed) +GR_STATIC_ASSERT(sizeof(GrStencilSettingsStruct) % 4 == 0); +GR_STATIC_ASSERT(sizeof(GrStencilSettingsStruct) == + 4*sizeof(uint8_t) + // ops + 2*sizeof(uint8_t) + // funcs + 2*sizeof(uint8_t) + // pads + 2*sizeof(uint16_t) + // func masks + 2*sizeof(uint16_t) + // ref values + 2*sizeof(uint16_t) + // write masks + sizeof(uint32_t)); // flags + +// This macro is used to compute the GrStencilSettingsStructs flags +// associated to disabling. It is used both to define constant structure +// initializers and inside GrStencilSettings::isDisabled() +// +#define GR_STENCIL_SETTINGS_IS_DISABLED( \ + FRONT_PASS_OP, BACK_PASS_OP, \ + FRONT_FAIL_OP, BACK_FAIL_OP, \ + FRONT_FUNC, BACK_FUNC) \ + ((FRONT_PASS_OP) == kKeep_StencilOp && \ + (BACK_PASS_OP) == kKeep_StencilOp && \ + (FRONT_FAIL_OP) == kKeep_StencilOp && \ + (BACK_FAIL_OP) == kKeep_StencilOp && \ + (FRONT_FUNC) == kAlways_StencilFunc && \ + (BACK_FUNC) == kAlways_StencilFunc) + +#define GR_STENCIL_SETTINGS_DOES_WRITE( \ + FRONT_PASS_OP, BACK_PASS_OP, \ + FRONT_FAIL_OP, BACK_FAIL_OP, \ + FRONT_FUNC, BACK_FUNC) \ + (!(((FRONT_FUNC) == kNever_StencilFunc || \ + (FRONT_PASS_OP) == kKeep_StencilOp) && \ + ((BACK_FUNC) == kNever_StencilFunc || \ + (BACK_PASS_OP) == kKeep_StencilOp) && \ + ((FRONT_FUNC) == kAlways_StencilFunc || \ + (FRONT_FAIL_OP) == kKeep_StencilOp) && \ + ((BACK_FUNC) == kAlways_StencilFunc || \ + (BACK_FAIL_OP) == kKeep_StencilOp))) + +#define GR_STENCIL_SETTINGS_DEFAULT_FLAGS( \ + FRONT_PASS_OP, BACK_PASS_OP, \ + FRONT_FAIL_OP, BACK_FAIL_OP, \ + FRONT_FUNC, BACK_FUNC) \ + ((GR_STENCIL_SETTINGS_IS_DISABLED(FRONT_PASS_OP,BACK_PASS_OP, \ + FRONT_FAIL_OP,BACK_FAIL_OP,FRONT_FUNC,BACK_FUNC) ? \ + kIsDisabled_StencilFlag : kNotDisabled_StencilFlag) | \ + (GR_STENCIL_SETTINGS_DOES_WRITE(FRONT_PASS_OP,BACK_PASS_OP, \ + FRONT_FAIL_OP,BACK_FAIL_OP,FRONT_FUNC,BACK_FUNC) ? \ + kDoesWrite_StencilFlag : kDoesNotWrite_StencilFlag)) + +/** + * Class representing stencil state. + */ +class GrStencilSettings : private GrStencilSettingsStruct { + +public: + enum Face { + kFront_Face = 0, + kBack_Face = 1, + }; + + GrStencilSettings() { + fPad0 = fPad1 = 0; + this->setDisabled(); + } + + GrStencilOp passOp(Face f) const { return static_cast(fPassOps[f]); } + GrStencilOp failOp(Face f) const { return static_cast(fFailOps[f]); } + GrStencilFunc func(Face f) const { return static_cast(fFuncs[f]); } + uint16_t funcMask(Face f) const { return fFuncMasks[f]; } + uint16_t funcRef(Face f) const { return fFuncRefs[f]; } + uint16_t writeMask(Face f) const { return fWriteMasks[f]; } + + void setPassOp(Face f, GrStencilOp op) { fPassOps[f] = op; fFlags = 0;} + void setFailOp(Face f, GrStencilOp op) { fFailOps[f] = op; fFlags = 0;} + void setFunc(Face f, GrStencilFunc func) { fFuncs[f] = func; fFlags = 0;} + void setFuncMask(Face f, unsigned short mask) { fFuncMasks[f] = mask; } + void setFuncRef(Face f, unsigned short ref) { fFuncRefs[f] = ref; } + void setWriteMask(Face f, unsigned short writeMask) { fWriteMasks[f] = writeMask; } + + void copyFrontSettingsToBack() { + fPassOps[kBack_Face] = fPassOps[kFront_Face]; + fFailOps[kBack_Face] = fFailOps[kFront_Face]; + fFuncs[kBack_Face] = fFuncs[kFront_Face]; + fFuncMasks[kBack_Face] = fFuncMasks[kFront_Face]; + fFuncRefs[kBack_Face] = fFuncRefs[kFront_Face]; + fWriteMasks[kBack_Face] = fWriteMasks[kFront_Face]; + fFlags = 0; + } + + void setSame(GrStencilOp passOp, + GrStencilOp failOp, + GrStencilFunc func, + unsigned short funcMask, + unsigned short funcRef, + unsigned short writeMask) { + fPassOps[kFront_Face] = fPassOps[kBack_Face] = passOp; + fFailOps[kFront_Face] = fFailOps[kBack_Face] = failOp; + fFuncs[kFront_Face] = fFuncs[kBack_Face] = func; + fFuncMasks[kFront_Face] = fFuncMasks[kBack_Face] = funcMask; + fFuncRefs[kFront_Face] = fFuncRefs[kBack_Face] = funcRef; + fWriteMasks[kFront_Face] = fWriteMasks[kBack_Face] = writeMask; + fFlags = 0; + } + + void setDisabled() { + memset(this, 0, sizeof(*this)); + GR_STATIC_ASSERT(0 == kKeep_StencilOp); + GR_STATIC_ASSERT(0 == kAlways_StencilFunc); + fFlags = kIsDisabled_StencilFlag | kDoesNotWrite_StencilFlag; + } + + bool isTwoSided() const { + return fPassOps[kFront_Face] != fPassOps[kBack_Face] || + fFailOps[kFront_Face] != fFailOps[kBack_Face] || + fFuncs[kFront_Face] != fFuncs[kBack_Face] || + fFuncMasks[kFront_Face] != fFuncMasks[kBack_Face] || + fFuncRefs[kFront_Face] != fFuncRefs[kBack_Face] || + fWriteMasks[kFront_Face] != fWriteMasks[kBack_Face]; + } + + bool usesWrapOp() const { + return kIncWrap_StencilOp == fPassOps[kFront_Face] || + kDecWrap_StencilOp == fPassOps[kFront_Face] || + kIncWrap_StencilOp == fPassOps[kBack_Face] || + kDecWrap_StencilOp == fPassOps[kBack_Face] || + kIncWrap_StencilOp == fFailOps[kFront_Face] || + kDecWrap_StencilOp == fFailOps[kFront_Face] || + kIncWrap_StencilOp == fFailOps[kBack_Face] || + kDecWrap_StencilOp == fFailOps[kBack_Face]; + } + + bool isDisabled() const { + if (fFlags & kIsDisabled_StencilFlag) { + return true; + } + if (fFlags & kNotDisabled_StencilFlag) { + return false; + } + bool disabled = GR_STENCIL_SETTINGS_IS_DISABLED( + fPassOps[kFront_Face], fPassOps[kBack_Face], + fFailOps[kFront_Face], fFailOps[kBack_Face], + fFuncs[kFront_Face], fFuncs[kBack_Face]); + fFlags |= disabled ? kIsDisabled_StencilFlag : kNotDisabled_StencilFlag; + return disabled; + } + + bool doesWrite() const { + if (fFlags & kDoesWrite_StencilFlag) { + return true; + } + if (fFlags & kDoesNotWrite_StencilFlag) { + return false; + } + bool writes = GR_STENCIL_SETTINGS_DOES_WRITE( + fPassOps[kFront_Face], fPassOps[kBack_Face], + fFailOps[kFront_Face], fFailOps[kBack_Face], + fFuncs[kFront_Face], fFuncs[kBack_Face]); + fFlags |= writes ? kDoesWrite_StencilFlag : kDoesNotWrite_StencilFlag; + return writes; + } + + void invalidate() { + // write an illegal value to the first member + fPassOps[0] = (GrStencilOp)(uint8_t)-1; + fFlags = 0; + } + + bool operator == (const GrStencilSettings& s) const { + static const size_t gCompareSize = sizeof(GrStencilSettings) - + sizeof(fFlags); + SkASSERT((const char*)&fFlags + sizeof(fFlags) == + (const char*)this + sizeof(GrStencilSettings)); + if (this->isDisabled() & s.isDisabled()) { // using & not && + return true; + } + return 0 == memcmp(this, &s, gCompareSize); + } + + bool operator != (const GrStencilSettings& s) const { + return !(*this == s); + } + + GrStencilSettings& operator =(const GrStencilSettings& s) { + memcpy(this, &s, sizeof(GrStencilSettings)); + return *this; + } + +private: + friend class GrClipMaskManager; + + 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(SkRegion::Op op, + bool canBeDirect, + unsigned int stencilClipMask, + bool invertedFill, + int* numPasses, + GrStencilSettings settings[kMaxStencilClipPasses]); +}; + +GR_STATIC_ASSERT(sizeof(GrStencilSettingsStruct) == sizeof(GrStencilSettings)); + +#define GR_STATIC_CONST_STENCIL_STRUCT(STRUCT_NAME, \ + FRONT_PASS_OP, BACK_PASS_OP, \ + FRONT_FAIL_OP, BACK_FAIL_OP, \ + FRONT_FUNC, BACK_FUNC, \ + FRONT_MASK, BACK_MASK, \ + FRONT_REF, BACK_REF, \ + FRONT_WRITE_MASK, BACK_WRITE_MASK) \ + static const GrStencilSettingsStruct STRUCT_NAME = { \ + {(FRONT_PASS_OP), (BACK_PASS_OP) }, \ + {(FRONT_FAIL_OP), (BACK_FAIL_OP) }, \ + {(FRONT_FUNC), (BACK_FUNC) }, \ + (0), (0), \ + {(FRONT_MASK), (BACK_MASK) }, \ + {(FRONT_REF), (BACK_REF) }, \ + {(FRONT_WRITE_MASK), (BACK_WRITE_MASK)}, \ + GR_STENCIL_SETTINGS_DEFAULT_FLAGS( \ + FRONT_PASS_OP, BACK_PASS_OP, FRONT_FAIL_OP, BACK_FAIL_OP, \ + FRONT_FUNC, BACK_FUNC) \ + }; + +#define GR_CONST_STENCIL_SETTINGS_PTR_FROM_STRUCT_PTR(STRUCT_PTR) \ + reinterpret_cast(STRUCT_PTR) + +#define GR_STATIC_CONST_SAME_STENCIL_STRUCT(STRUCT_NAME, \ + PASS_OP, FAIL_OP, FUNC, MASK, REF, WRITE_MASK) \ + GR_STATIC_CONST_STENCIL_STRUCT(STRUCT_NAME, (PASS_OP), (PASS_OP), \ + (FAIL_OP),(FAIL_OP), (FUNC), (FUNC), (MASK), (MASK), (REF), (REF), \ + (WRITE_MASK),(WRITE_MASK)) + +#define GR_STATIC_CONST_STENCIL(NAME, \ + FRONT_PASS_OP, BACK_PASS_OP, \ + FRONT_FAIL_OP, BACK_FAIL_OP, \ + FRONT_FUNC, BACK_FUNC, \ + FRONT_MASK, BACK_MASK, \ + FRONT_REF, BACK_REF, \ + FRONT_WRITE_MASK, BACK_WRITE_MASK) \ + GR_STATIC_CONST_STENCIL_STRUCT(NAME ## _STRUCT, \ + (FRONT_PASS_OP),(BACK_PASS_OP),(FRONT_FAIL_OP),(BACK_FAIL_OP), \ + (FRONT_FUNC),(BACK_FUNC),(FRONT_MASK),(BACK_MASK), \ + (FRONT_REF),(BACK_REF),(FRONT_WRITE_MASK),(BACK_WRITE_MASK)) \ + static const GrStencilSettings& NAME = \ + *GR_CONST_STENCIL_SETTINGS_PTR_FROM_STRUCT_PTR(&(NAME ## _STRUCT)); + + +#define GR_STATIC_CONST_SAME_STENCIL(NAME, \ + PASS_OP, FAIL_OP, FUNC, MASK, REF, WRITE_MASK) \ + GR_STATIC_CONST_STENCIL(NAME, (PASS_OP), (PASS_OP), (FAIL_OP), \ + (FAIL_OP), (FUNC), (FUNC), (MASK), (MASK), (REF), (REF), (WRITE_MASK), \ + (WRITE_MASK)) + +#endif