aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/gpu/GrClipMaskManager.cpp
diff options
context:
space:
mode:
authorGravatar bsalomon@google.com <bsalomon@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2012-06-21 19:58:20 +0000
committerGravatar bsalomon@google.com <bsalomon@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2012-06-21 19:58:20 +0000
commita320194e4242ef0e5e758aea896bfd52bcb3dac7 (patch)
treef2025d8395a55204d523463c923f820c7a1ced02 /src/gpu/GrClipMaskManager.cpp
parent8f7e1dac5c92bf1f53feb603a9bd249d53afa81a (diff)
Make GrClipMaskManager configure the stencil and scissor on GrGpu
Review URL: http://codereview.appspot.com/6308096/ git-svn-id: http://skia.googlecode.com/svn/trunk@4288 2bbb7eff-a529-9590-31e7-b0007b416f81
Diffstat (limited to 'src/gpu/GrClipMaskManager.cpp')
-rw-r--r--src/gpu/GrClipMaskManager.cpp286
1 files changed, 194 insertions, 92 deletions
diff --git a/src/gpu/GrClipMaskManager.cpp b/src/gpu/GrClipMaskManager.cpp
index 55a8192c3f..c16b4106a1 100644
--- a/src/gpu/GrClipMaskManager.cpp
+++ b/src/gpu/GrClipMaskManager.cpp
@@ -23,15 +23,6 @@
//#define GR_SW_CLIP 1
////////////////////////////////////////////////////////////////////////////////
-void ScissoringSettings::setupScissoring(GrGpu* gpu) {
- if (!fEnableScissoring) {
- gpu->disableScissor();
- return;
- }
-
- gpu->enableScissoring(fScissorRect);
-}
-
namespace {
// set up the draw state to enable the aa clipping mask. Besides setting up the
// sampler matrix this also alters the vertex layout
@@ -113,37 +104,50 @@ bool GrClipMaskManager::useSWOnlyPath(const GrClip& clipIn) {
////////////////////////////////////////////////////////////////////////////////
// sort out what kind of clip mask needs to be created: alpha, stencil,
// scissor, or entirely software
-bool GrClipMaskManager::createClipMask(const GrClip& clipIn,
- ScissoringSettings* scissorSettings) {
-
- GrAssert(scissorSettings);
-
- scissorSettings->fEnableScissoring = false;
-
+bool GrClipMaskManager::setupClipping(const GrClip& clipIn) {
fCurrClipMaskType = kNone_ClipMaskType;
-
+
GrDrawState* drawState = fGpu->drawState();
- if (!drawState->isClipState()) {
+ if (!drawState->isClipState() || clipIn.isEmpty()) {
+ fGpu->disableScissor();
+ this->setGpuStencil();
return true;
}
GrRenderTarget* rt = drawState->getRenderTarget();
-
// GrDrawTarget should have filtered this for us
GrAssert(NULL != rt);
+ GrIRect bounds;
+ GrIRect rtRect;
+ rtRect.setLTRB(0, 0, rt->width(), rt->height());
+ if (clipIn.hasConservativeBounds()) {
+ GrRect softBounds = clipIn.getConservativeBounds();
+ softBounds.roundOut(&bounds);
+ if (!bounds.intersect(rtRect)) {
+ bounds.setEmpty();
+ }
+ if (bounds.isEmpty()) {
+ return false;
+ }
+ } else {
+ bounds = rtRect;
+ }
+
#if GR_SW_CLIP
// If MSAA is enabled we can do everything in the stencil buffer.
// Otherwise check if we should just create the entire clip mask
// in software (this will only happen if the clip mask is anti-aliased
// and too complex for the gpu to handle in its entirety)
- if (0 == rt->numSamples() && useSWOnlyPath(gpu, clipIn)) {
+ if (0 == rt->numSamples() && this->useSWOnlyPath(clipIn)) {
// The clip geometry is complex enough that it will be more
// efficient to create it entirely in software
GrTexture* result = NULL;
GrIRect bound;
- if (this->createSoftwareClipMask(fGpu, clipIn, &result, &bound)) {
+ if (this->createSoftwareClipMask(clipIn, &result, &bound)) {
setup_drawstate_aaclip(fGpu, result, bound);
+ fGpu->disableScissor();
+ this->setGpuStencil();
return true;
}
@@ -162,8 +166,10 @@ bool GrClipMaskManager::createClipMask(const GrClip& clipIn,
// path does (see scissorSettings below)
GrTexture* result = NULL;
GrIRect bound;
- if (this->createAlphaClipMask(fGpu, clipIn, &result, &bound)) {
+ if (this->createAlphaClipMask(clipIn, &result, &bound)) {
setup_drawstate_aaclip(fGpu, result, bound);
+ fGpu->disableScissor();
+ this->setGpuStencil();
return true;
}
@@ -181,36 +187,27 @@ bool GrClipMaskManager::createClipMask(const GrClip& clipIn,
// AA cache.
fAACache.reset();
- GrRect bounds;
- GrRect rtRect;
- rtRect.setLTRB(0, 0,
- GrIntToScalar(rt->width()), GrIntToScalar(rt->height()));
- if (clipIn.hasConservativeBounds()) {
- bounds = clipIn.getConservativeBounds();
- if (!bounds.intersect(rtRect)) {
- bounds.setEmpty();
- }
- } else {
- bounds = rtRect;
- }
-
- bounds.roundOut(&scissorSettings->fScissorRect);
- if (scissorSettings->fScissorRect.isEmpty()) {
- scissorSettings->fScissorRect.setLTRB(0,0,0,0);
- // TODO: I think we can do an early exit here - after refactoring try:
- // set fEnableScissoring to true but leave fClipMaskInStencil false
- // and return - everything is going to be scissored away anyway!
+ // If the clip is a rectangle then just set the scissor. Otherwise, create
+ // a stencil mask.
+ if (clipIn.isRect()) {
+ fGpu->enableScissor(bounds);
+ this->setGpuStencil();
+ return true;
}
- scissorSettings->fEnableScissoring = true;
// use the stencil clip if we can't represent the clip as a rectangle.
bool useStencil = !clipIn.isRect() && !clipIn.isEmpty() &&
!bounds.isEmpty();
if (useStencil) {
- return this->createStencilClipMask(clipIn, bounds, scissorSettings);
+ this->createStencilClipMask(clipIn, bounds);
}
-
+ // This must occur after createStencilClipMask. That function may change
+ // the scissor. Also, it only guarantees that the stencil mask is correct
+ // within the bounds it was passed, so we must use both stencil and scissor
+ // test to the bounds for the final draw.
+ fGpu->enableScissor(bounds);
+ this->setGpuStencil();
return true;
}
@@ -663,8 +660,7 @@ bool GrClipMaskManager::createAlphaClipMask(const GrClip& clipIn,
////////////////////////////////////////////////////////////////////////////////
// Create a 1-bit clip mask in the stencil buffer
bool GrClipMaskManager::createStencilClipMask(const GrClip& clipIn,
- const GrRect& bounds,
- ScissoringSettings* scissorSettings) {
+ const GrIRect& bounds) {
GrAssert(kNone_ClipMaskType == fCurrClipMaskType);
@@ -696,7 +692,6 @@ bool GrClipMaskManager::createStencilClipMask(const GrClip& clipIn,
drawState->setRenderTarget(rt);
GrDrawTarget::AutoGeometryPush agp(fGpu);
- fGpu->disableScissor();
#if !VISUALIZE_COMPLEX_CLIP
drawState->enableState(GrDrawState::kNoColorWrites_StateBit);
#endif
@@ -716,7 +711,7 @@ bool GrClipMaskManager::createStencilClipMask(const GrClip& clipIn,
&clearToInside,
&startOp);
- fGpu->clearStencilClip(scissorSettings->fScissorRect, clearToInside);
+ fGpu->clearStencilClip(bounds, clearToInside);
// walk through each clip element and perform its set op
// with the existing clip.
@@ -814,7 +809,12 @@ bool GrClipMaskManager::createStencilClipMask(const GrClip& clipIn,
}
} else {
SET_RANDOM_COLOR
- fGpu->drawSimpleRect(bounds, NULL, 0);
+ GrRect rect = GrRect::MakeLTRB(
+ SkIntToScalar(bounds.fLeft),
+ SkIntToScalar(bounds.fTop),
+ SkIntToScalar(bounds.fRight),
+ SkIntToScalar(bounds.fBottom));
+ fGpu->drawSimpleRect(rect, NULL, 0);
}
}
}
@@ -863,60 +863,162 @@ static const GrStencilFunc
}
};
-GrStencilFunc GrClipMaskManager::adjustStencilParams(GrStencilFunc func,
- StencilClipMode mode,
- unsigned int stencilBitCnt,
- unsigned int* ref,
- unsigned int* mask,
- unsigned int* writeMask) {
+namespace {
+// Sets the settings to clip against the stencil buffer clip while ignoring the
+// client bits.
+const GrStencilSettings& basic_apply_stencil_clip_settings() {
+ // stencil settings to use when clip is in stencil
+ GR_STATIC_CONST_SAME_STENCIL_STRUCT(gSettings,
+ kKeep_StencilOp,
+ kKeep_StencilOp,
+ kAlwaysIfInClip_StencilFunc,
+ 0x0000,
+ 0x0000,
+ 0x0000);
+ return *GR_CONST_STENCIL_SETTINGS_PTR_FROM_STRUCT_PTR(&gSettings);
+}
+}
+
+void GrClipMaskManager::setGpuStencil() {
+ // We make two copies of the StencilSettings here (except in the early
+ // exit scenario. One copy from draw state to the stack var. Then another
+ // from the stack var to the gpu. We could make this class hold a ptr to
+ // GrGpu's fStencilSettings and eliminate the stack copy here.
+
+ const GrDrawState& drawState = fGpu->getDrawState();
+
+ // use stencil for clipping if clipping is enabled and the clip
+ // has been written into the stencil.
+ GrClipMaskManager::StencilClipMode clipMode;
+ if (this->isClipInStencil() && drawState.isClipState()) {
+ clipMode = GrClipMaskManager::kRespectClip_StencilClipMode;
+ // We can't be modifying the clip and respecting it at the same time.
+ GrAssert(!drawState.isStateFlagEnabled(
+ GrGpu::kModifyStencilClip_StateBit));
+ } else if (drawState.isStateFlagEnabled(
+ GrGpu::kModifyStencilClip_StateBit)) {
+ clipMode = GrClipMaskManager::kModifyClip_StencilClipMode;
+ } else {
+ clipMode = GrClipMaskManager::kIgnoreClip_StencilClipMode;
+ }
+
+ GrStencilSettings settings;
+ // The GrGpu client may not be using the stencil buffer but we may need to
+ // enable it in order to respect a stencil clip.
+ if (drawState.getStencil().isDisabled()) {
+ if (GrClipMaskManager::kRespectClip_StencilClipMode == clipMode) {
+ settings = basic_apply_stencil_clip_settings();
+ } else {
+ fGpu->disableStencil();
+ return;
+ }
+ } else {
+ settings = drawState.getStencil();
+ }
+
+ // TODO: dynamically attach a stencil buffer
+ int stencilBits = 0;
+ GrStencilBuffer* stencilBuffer =
+ drawState.getRenderTarget()->getStencilBuffer();
+ if (NULL != stencilBuffer) {
+ stencilBits = stencilBuffer->bits();
+ }
+
+#if GR_DEBUG
+ if (!fGpu->getCaps().fStencilWrapOpsSupport) {
+ GrAssert(settings.frontPassOp() != kIncWrap_StencilOp);
+ GrAssert(settings.frontPassOp() != kDecWrap_StencilOp);
+ GrAssert(settings.frontFailOp() != kIncWrap_StencilOp);
+ GrAssert(settings.backFailOp() != kDecWrap_StencilOp);
+ GrAssert(settings.backPassOp() != kIncWrap_StencilOp);
+ GrAssert(settings.backPassOp() != kDecWrap_StencilOp);
+ GrAssert(settings.backFailOp() != kIncWrap_StencilOp);
+ GrAssert(settings.frontFailOp() != kDecWrap_StencilOp);
+ }
+#endif
+ this->adjustStencilParams(&settings, clipMode, stencilBits);
+ fGpu->setStencilSettings(settings);
+}
+
+void GrClipMaskManager::adjustStencilParams(GrStencilSettings* settings,
+ StencilClipMode mode,
+ int stencilBitCnt) {
GrAssert(stencilBitCnt > 0);
- GrAssert((unsigned) func < kStencilFuncCount);
if (kModifyClip_StencilClipMode == mode) {
- // We assume that this class is the client/draw-caller of the GrGpu and
- // has already setup the correct values
- return func;
+ // We assume that this clip manager itself is drawing to the GrGpu and
+ // has already setup the correct values.
+ return;
}
+
unsigned int clipBit = (1 << (stencilBitCnt - 1));
unsigned int userBits = clipBit - 1;
- *writeMask &= userBits;
-
- if (func >= kBasicStencilFuncCount) {
- int respectClip = kRespectClip_StencilClipMode == mode;
- if (respectClip) {
- // The GrGpu class should have checked this
- GrAssert(this->isClipInStencil());
- switch (func) {
- case kAlwaysIfInClip_StencilFunc:
- *mask = clipBit;
- *ref = clipBit;
- break;
- case kEqualIfInClip_StencilFunc:
- case kLessIfInClip_StencilFunc:
- case kLEqualIfInClip_StencilFunc:
- *mask = (*mask & userBits) | clipBit;
- *ref = (*ref & userBits) | clipBit;
- break;
- case kNonZeroIfInClip_StencilFunc:
- *mask = (*mask & userBits) | clipBit;
- *ref = clipBit;
- break;
- default:
- GrCrash("Unknown stencil func");
+ GrStencilSettings::Face face = GrStencilSettings::kFront_Face;
+ bool twoSided = fGpu->getCaps().fTwoSidedStencilSupport;
+
+ bool finished = false;
+ while (!finished) {
+ GrStencilFunc func = settings->func(face);
+ uint16_t writeMask = settings->writeMask(face);
+ uint16_t funcMask = settings->funcMask(face);
+ uint16_t funcRef = settings->funcRef(face);
+
+ GrAssert((unsigned) func < kStencilFuncCount);
+
+ writeMask &= userBits;
+
+ if (func >= kBasicStencilFuncCount) {
+ int respectClip = kRespectClip_StencilClipMode == mode;
+ if (respectClip) {
+ // The GrGpu class should have checked this
+ GrAssert(this->isClipInStencil());
+ switch (func) {
+ case kAlwaysIfInClip_StencilFunc:
+ funcMask = clipBit;
+ funcRef = clipBit;
+ break;
+ case kEqualIfInClip_StencilFunc:
+ case kLessIfInClip_StencilFunc:
+ case kLEqualIfInClip_StencilFunc:
+ funcMask = (funcMask & userBits) | clipBit;
+ funcRef = (funcRef & userBits) | clipBit;
+ break;
+ case kNonZeroIfInClip_StencilFunc:
+ funcMask = (funcMask & userBits) | clipBit;
+ funcRef = clipBit;
+ break;
+ default:
+ GrCrash("Unknown stencil func");
+ }
+ } else {
+ funcMask &= userBits;
+ funcRef &= userBits;
}
+ const GrStencilFunc* table =
+ gSpecialToBasicStencilFunc[respectClip];
+ func = table[func - kBasicStencilFuncCount];
+ GrAssert(func >= 0 && func < kBasicStencilFuncCount);
} else {
- *mask &= userBits;
- *ref &= userBits;
+ funcMask &= userBits;
+ funcRef &= userBits;
}
- const GrStencilFunc* table = gSpecialToBasicStencilFunc[respectClip];
- func = table[func - kBasicStencilFuncCount];
- GrAssert(func >= 0 && func < kBasicStencilFuncCount);
- } else {
- *mask &= userBits;
- *ref &= userBits;
+
+ settings->setFunc(face, func);
+ settings->setWriteMask(face, writeMask);
+ settings->setFuncMask(face, funcMask);
+ settings->setFuncRef(face, funcRef);
+
+ if (GrStencilSettings::kFront_Face == face) {
+ face = GrStencilSettings::kBack_Face;
+ finished = !twoSided;
+ } else {
+ finished = true;
+ }
+ }
+ if (!twoSided) {
+ settings->copyFrontSettingsToBack();
}
- return func;
}
////////////////////////////////////////////////////////////////////////////////