blob: b8610f2017b85824f13d4adf137b68b9384e2beb [file] [log] [blame]
/*
* 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