Remove on static initializer in GrGpu.cpp

This is another go for the patch that was initially
submitted at http://codereview.appspot.com/5504073/ but
crashed the 'gm' unit test.

A problem with the previous implementation is that the
GrStencilSettings ::isDisabled() and ::doesWrite() methods can
modify the object's fFlags member if it is 0, and this will
crash at runtime when doing this for a static constant
object/structure.

I'm not sure why this wasn't triggered previously.

We solve the issue by modifying the implementation of
GR_STATIC_CONST_STENCIL and GR_STATIC_CONST_STENCIL macros to
compute the correct default values for fFlags (which prevents
any member modifications in the above methods).

This requires moving the definition of the disabled/write flags
out of the GrStencilSettings class definition's private section.
Note that the flags are renamed to avoid any confusion and
conflicts, i.e.:

  SkIsDisabled_Flag  -> SkIsDisabled_StencilFlag
  SkNotDisabled_Flag -> SkNotDisabled_StencilFlag
  ...
Review URL: https://codereview.appspot.com/5616051

git-svn-id: http://skia.googlecode.com/svn/trunk@3214 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
digit@google.com 2012-02-16 22:03:26 +00:00
parent 128cd221b1
commit 9b482c4d33
4 changed files with 105 additions and 45 deletions

View File

@ -343,15 +343,17 @@ const GrVertexBuffer* GrGpu::getUnitSquareVertexBuffer() const {
////////////////////////////////////////////////////////////////////////////////
// stencil settings to use when clip is in stencil
GR_STATIC_CONST_SAME_STENCIL(gClipStencilSettings,
kKeep_StencilOp,
kKeep_StencilOp,
kAlwaysIfInClip_StencilFunc,
0x0000,
0x0000,
0x0000);
const GrStencilSettings& GrGpu::gClipStencilSettings = ::gClipStencilSettings;
const GrStencilSettings* GrGpu::GetClipStencilSettings(void) {
// stencil settings to use when clip is in stencil
GR_STATIC_CONST_SAME_STENCIL_STRUCT(sClipStencilSettings,
kKeep_StencilOp,
kKeep_StencilOp,
kAlwaysIfInClip_StencilFunc,
0x0000,
0x0000,
0x0000);
return GR_CONST_STENCIL_SETTINGS_PTR_FROM_STRUCT_PTR(&sClipStencilSettings);
}
// mapping of clip-respecting stencil funcs to normal stencil funcs
// mapping depends on whether stencil-clipping is in effect.

View File

@ -355,7 +355,7 @@ protected:
// stencil settings to clip drawing when stencil clipping is in effect
// and the client isn't using the stencil test.
static const GrStencilSettings& gClipStencilSettings;
static const GrStencilSettings* GetClipStencilSettings();
GrGpuStats fStats;

View File

@ -84,6 +84,13 @@ enum GrStencilOp {
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
@ -121,6 +128,45 @@ GR_STATIC_ASSERT(sizeof(GrStencilSettingsStruct) ==
2*sizeof(unsigned short) + // 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.
*/
@ -183,42 +229,36 @@ public:
memset(this, 0, sizeof(*this));
GR_STATIC_ASSERT(0 == kKeep_StencilOp);
GR_STATIC_ASSERT(0 == kAlways_StencilFunc);
fFlags = kIsDisabled_Flag | kDoesNotWrite_Flag;
fFlags = kIsDisabled_StencilFlag | kDoesNotWrite_StencilFlag;
}
bool isDisabled() const {
if (fFlags & kIsDisabled_Flag) {
if (fFlags & kIsDisabled_StencilFlag) {
return true;
}
if (fFlags & kNotDisabled_Flag) {
if (fFlags & kNotDisabled_StencilFlag) {
return false;
}
bool disabled = kKeep_StencilOp == fFrontPassOp &&
kKeep_StencilOp == fBackPassOp &&
kKeep_StencilOp == fFrontFailOp &&
kKeep_StencilOp == fBackFailOp &&
kAlways_StencilFunc == fFrontFunc &&
kAlways_StencilFunc == fBackFunc;
fFlags |= disabled ? kIsDisabled_Flag : kNotDisabled_Flag;
bool disabled = GR_STENCIL_SETTINGS_IS_DISABLED(
fFrontPassOp, fBackPassOp,
fFrontFailOp, fBackFailOp,
fFrontFunc ,fBackFunc);
fFlags |= disabled ? kIsDisabled_StencilFlag : kNotDisabled_StencilFlag;
return disabled;
}
bool doesWrite() const {
if (fFlags & kDoesWrite_Flag) {
if (fFlags & kDoesWrite_StencilFlag) {
return true;
}
if (fFlags & kDoesNotWrite_Flag) {
if (fFlags & kDoesNotWrite_StencilFlag) {
return false;
}
bool writes = !((kNever_StencilFunc == fFrontFunc ||
kKeep_StencilOp == fFrontPassOp) &&
(kNever_StencilFunc == fBackFunc ||
kKeep_StencilOp == fBackPassOp) &&
(kAlways_StencilFunc == fFrontFunc ||
kKeep_StencilOp == fFrontFailOp) &&
(kAlways_StencilFunc == fBackFunc ||
kKeep_StencilOp == fBackFailOp));
fFlags |= writes ? kDoesWrite_Flag : kDoesNotWrite_Flag;
bool writes = GR_STENCIL_SETTINGS_DOES_WRITE(
fFrontPassOp, fBackPassOp,
fFrontFailOp, fBackFailOp,
fFrontFunc, fBackFunc);
fFlags |= writes ? kDoesWrite_StencilFlag : kDoesNotWrite_StencilFlag;
return writes;
}
@ -250,13 +290,6 @@ public:
private:
friend class GrGpu;
enum {
kIsDisabled_Flag = 0x1,
kNotDisabled_Flag = 0x2,
kDoesWrite_Flag = 0x4,
kDoesNotWrite_Flag = 0x8,
};
enum {
kMaxStencilClipPasses = 2 // maximum number of passes to add a clip
// element to the stencil buffer.
@ -295,14 +328,14 @@ private:
GR_STATIC_ASSERT(sizeof(GrStencilSettingsStruct) == sizeof(GrStencilSettings));
#define GR_STATIC_CONST_STENCIL(NAME, \
#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 NAME ## _STRUCT = { \
static const GrStencilSettingsStruct STRUCT_NAME = { \
(FRONT_PASS_OP), (BACK_PASS_OP), \
(FRONT_FAIL_OP), (BACK_FAIL_OP), \
(FRONT_FUNC), (BACK_FUNC), \
@ -310,14 +343,39 @@ GR_STATIC_ASSERT(sizeof(GrStencilSettingsStruct) == sizeof(GrStencilSettings));
(FRONT_MASK), (BACK_MASK), \
(FRONT_REF), (BACK_REF), \
(FRONT_WRITE_MASK), (BACK_WRITE_MASK), \
0 \
}; \
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<const GrStencilSettings*>(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 = \
*reinterpret_cast<const GrStencilSettings*>(&(NAME ## _STRUCT))
#endif
*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

View File

@ -1642,7 +1642,7 @@ void GrGpuGL::flushStencil() {
if (settings->isDisabled()) {
if (stencilClip) {
settings = &gClipStencilSettings;
settings = GetClipStencilSettings();
}
}