From a320194e4242ef0e5e758aea896bfd52bcb3dac7 Mon Sep 17 00:00:00 2001 From: "bsalomon@google.com" Date: Thu, 21 Jun 2012 19:58:20 +0000 Subject: [PATCH] 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 --- gyp/gpu.gyp | 1 + include/gpu/GrClip.h | 3 +- include/gpu/GrTemplates.h | 17 +- src/gpu/GrClipMaskManager.cpp | 284 ++++++++++++++++++++++----------- src/gpu/GrClipMaskManager.h | 57 +++---- src/gpu/GrDrawTarget.h | 1 + src/gpu/GrGpu.cpp | 20 +-- src/gpu/GrGpu.h | 38 ++++- src/gpu/GrStencil.cpp | 126 +++++++++------ src/gpu/GrStencil.h | 149 +++++++++-------- src/gpu/SkGrFontScaler.cpp | 2 +- src/gpu/gl/GrGpuGL.cpp | 235 ++++++++++----------------- src/gpu/gl/GrGpuGL.h | 33 ++-- src/gpu/gl/GrGpuGL_program.cpp | 1 + 14 files changed, 527 insertions(+), 440 deletions(-) diff --git a/gyp/gpu.gyp b/gyp/gpu.gyp index ffe0e05f6..5acf24422 100644 --- a/gyp/gpu.gyp +++ b/gyp/gpu.gyp @@ -195,6 +195,7 @@ '../include/gpu/GrResource.h', '../include/gpu/GrSamplerState.h', '../include/gpu/GrScalar.h', + '../include/gpu/GrTemplates.h', '../include/gpu/GrTextContext.h', '../include/gpu/GrTexture.h', '../include/gpu/GrTypes.h', diff --git a/include/gpu/GrClip.h b/include/gpu/GrClip.h index 6f1c5d47b..3385c7474 100644 --- a/include/gpu/GrClip.h +++ b/include/gpu/GrClip.h @@ -13,7 +13,6 @@ #include "GrClipIterator.h" #include "GrRect.h" -#include "GrTemplates.h" #include "SkPath.h" #include "SkTArray.h" @@ -78,6 +77,8 @@ public: } } + // FIXME: This word "empty" is confusing. It means that the clip has no + // elements (it is the infinite plane) not that it has no area. bool isEmpty() const { return 0 == fList.count(); } /** diff --git a/include/gpu/GrTemplates.h b/include/gpu/GrTemplates.h index 63e43eed0..4378d7094 100644 --- a/include/gpu/GrTemplates.h +++ b/include/gpu/GrTemplates.h @@ -25,36 +25,37 @@ template Dst GrTCast(Src src) { } /** - * saves value of T* in and restores in destructor + * takes a T*, saves the value it points to, in and restores the value in the + * destructor * e.g.: * { - * GrAutoTPtrValueRestore autoCountRestore; + * GrAutoTRestore autoCountRestore; * if (useExtra) { - * autoCountRestore.save(&fCount); + * autoCountRestore.reset(&fCount); * fCount += fExtraCount; * } * ... * } // fCount is restored */ -template class GrAutoTPtrValueRestore : public GrNoncopyable { +template class GrAutoTRestore : public GrNoncopyable { public: - GrAutoTPtrValueRestore() : fPtr(NULL), fVal() {} + GrAutoTRestore() : fPtr(NULL), fVal() {} - GrAutoTPtrValueRestore(T* ptr) { + GrAutoTRestore(T* ptr) { fPtr = ptr; if (NULL != ptr) { fVal = *ptr; } } - ~GrAutoTPtrValueRestore() { + ~GrAutoTRestore() { if (NULL != fPtr) { *fPtr = fVal; } } // restores previously saved value (if any) and saves value for passed T* - void save(T* ptr) { + void reset(T* ptr) { if (NULL != fPtr) { *fPtr = fVal; } diff --git a/src/gpu/GrClipMaskManager.cpp b/src/gpu/GrClipMaskManager.cpp index 55a8192c3..c16b4106a 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; + // 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; } - 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! - } - 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; + GrStencilSettings::Face face = GrStencilSettings::kFront_Face; + bool twoSided = fGpu->getCaps().fTwoSidedStencilSupport; - 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"); + 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; + } + + 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; } - const GrStencilFunc* table = gSpecialToBasicStencilFunc[respectClip]; - func = table[func - kBasicStencilFuncCount]; - GrAssert(func >= 0 && func < kBasicStencilFuncCount); - } else { - *mask &= userBits; - *ref &= userBits; } - return func; + if (!twoSided) { + settings->copyFrontSettingsToBack(); + } } //////////////////////////////////////////////////////////////////////////////// diff --git a/src/gpu/GrClipMaskManager.h b/src/gpu/GrClipMaskManager.h index 1ceee16be..144c042a8 100644 --- a/src/gpu/GrClipMaskManager.h +++ b/src/gpu/GrClipMaskManager.h @@ -27,19 +27,6 @@ class SkPath; class GrTexture; class GrDrawState; -/** - * Scissoring needs special handling during stencil clip mask creation - * since the creation process re-entrantly invokes setupClipAndFlushState. - * During this process the call stack is used to keep - * track of (and apply to the GPU) the current scissor settings. - */ -struct ScissoringSettings { - bool fEnableScissoring; - GrIRect fScissorRect; - - void setupScissoring(GrGpu* gpu); -}; - /** * The stencil buffer stores the last clip path - providing a single entry * "cache". This class provides similar functionality for AA clip paths @@ -288,8 +275,12 @@ public: , fCurrClipMaskType(kNone_ClipMaskType) { } - bool createClipMask(const GrClip& clip, - ScissoringSettings* scissorSettings); + /** + * Creates a clip mask if necessary as a stencil buffer or alpha texture + * and sets the GrGpu's scissor and stencil state. If the return is false + * then the draw can be skipped. + */ + bool setupClipping(const GrClip& clip); void releaseResources(); @@ -325,6 +316,7 @@ public: return fAACache.getContext(); } +private: /** * Informs the helper function adjustStencilParams() about how the stencil * buffer clip is being used. @@ -339,21 +331,6 @@ public: kIgnoreClip_StencilClipMode, }; - /** - * The stencil func, mask, and reference value are specified by GrGpu's - * caller but the actual values passed to the API may have to be adjusted - * due to the stencil buffer simultaneously being used for clipping. This - * function should be called even when clipping is disabled in order to - * prevent the clip from being accidentally overwritten. - */ - GrStencilFunc adjustStencilParams(GrStencilFunc, - StencilClipMode mode, - unsigned int stencilBitCnt, - unsigned int* ref, - unsigned int* mask, - unsigned int* writeMask); - -private: GrGpu* fGpu; /** @@ -369,9 +346,8 @@ private: GrClipMaskCache fAACache; // cache for the AA path - bool createStencilClipMask(const GrClip& clip, - const GrRect& bounds, - ScissoringSettings* scissorSettings); + bool createStencilClipMask(const GrClip& clip, + const GrIRect& bounds); bool createAlphaClipMask(const GrClip& clipIn, GrTexture** result, GrIRect *resultBounds); @@ -396,6 +372,21 @@ private: void setupCache(const GrClip& clip, const GrIRect& bounds); + /** + * Called prior to return control back the GrGpu in setupClipping. It + * updates the GrGpu with stencil settings that account stencil-based + * clipping. + */ + void setGpuStencil(); + + /** + * Adjusts the stencil settings to account for interaction with stencil + * clipping. + */ + void adjustStencilParams(GrStencilSettings* settings, + StencilClipMode mode, + int stencilBitCnt); + typedef GrNoncopyable INHERITED; }; diff --git a/src/gpu/GrDrawTarget.h b/src/gpu/GrDrawTarget.h index 6e5bc6764..7bd330788 100644 --- a/src/gpu/GrDrawTarget.h +++ b/src/gpu/GrDrawTarget.h @@ -16,6 +16,7 @@ #include "GrIndexBuffer.h" #include "GrMatrix.h" #include "GrRefCnt.h" +#include "GrTemplates.h" #include "SkXfermode.h" #include "SkTLazy.h" diff --git a/src/gpu/GrGpu.cpp b/src/gpu/GrGpu.cpp index c8c983cbb..132d2ed4d 100644 --- a/src/gpu/GrGpu.cpp +++ b/src/gpu/GrGpu.cpp @@ -351,34 +351,16 @@ const GrVertexBuffer* GrGpu::getUnitSquareVertexBuffer() const { //////////////////////////////////////////////////////////////////////////////// -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); -} - -//////////////////////////////////////////////////////////////////////////////// - bool GrGpu::setupClipAndFlushState(DrawType type) { - ScissoringSettings scissoringSettings; - - if (!fClipMaskManager.createClipMask(fClip, &scissoringSettings)) { + if (!fClipMaskManager.setupClipping(fClip)) { return false; } - // Must flush the scissor after graphics state if (!this->flushGraphicsState(type)) { return false; } - scissoringSettings.setupScissoring(this); return true; } diff --git a/src/gpu/GrGpu.h b/src/gpu/GrGpu.h index edbad3413..53c74249d 100644 --- a/src/gpu/GrGpu.h +++ b/src/gpu/GrGpu.h @@ -323,8 +323,29 @@ public: return fConfigRenderSupport[config]; } - virtual void enableScissoring(const GrIRect& rect) = 0; - virtual void disableScissor() = 0; + /** + * These methods are called by the clip manager's setupClipping function + * which (called as part of GrGpu's implementation of onDraw* and + * onStencilPath member functions.) The GrGpu subclass should flush the + * stencil state to the 3D API in its implementation of flushGraphicsState. + */ + void enableScissor(const GrIRect& rect) { + fScissorState.fEnabled = true; + fScissorState.fRect = rect; + } + void disableScissor() { fScissorState.fEnabled = false; } + + /** + * Like the scissor methods above this is called by setupClipping and + * should be flushed by the GrGpu subclass in flushGraphicsState. These + * stencil settings should be used in place of those on the GrDrawState. + * They have been adjusted to account for any interactions between the + * GrDrawState's stencil settings and stencil clipping. + */ + void setStencilSettings(const GrStencilSettings& settings) { + fStencilSettings = settings; + } + void disableStencil() { fStencilSettings.setDisabled(); } // GrGpu subclass sets clip bit in the stencil buffer. The subclass is // free to clear the remaining bits to zero if masked clears are more @@ -385,10 +406,6 @@ protected: unsigned int* ref, unsigned int* mask); - // stencil settings to clip drawing when stencil clipping is in effect - // and the client isn't using the stencil test. - static const GrStencilSettings* GetClipStencilSettings(); - GrClipMaskManager fClipMaskManager; struct GeometryPoolState { @@ -402,6 +419,15 @@ protected: return fGeomPoolStateStack.back(); } + // The state of the scissor is controlled by the clip manager + struct ScissorState { + bool fEnabled; + GrIRect fRect; + } fScissorState; + + // The final stencil settings to use as determined by the clip manager. + GrStencilSettings fStencilSettings; + // Derived classes need access to this so they can fill it out in their // constructors bool fConfigRenderSupport[kGrPixelConfigCount]; diff --git a/src/gpu/GrStencil.cpp b/src/gpu/GrStencil.cpp index ab0e78c6a..8d7534aa4 100644 --- a/src/gpu/GrStencil.cpp +++ b/src/gpu/GrStencil.cpp @@ -220,12 +220,13 @@ GR_STATIC_CONST_SAME_STENCIL(gDiffClip, 0x0000 // set clip bit ); -bool GrStencilSettings::GetClipPasses(SkRegion::Op op, - bool canBeDirect, - unsigned int stencilClipMask, - bool invertedFill, - int* numPasses, - GrStencilSettings settings[kMaxStencilClipPasses]) { +bool GrStencilSettings::GetClipPasses( + SkRegion::Op op, + bool canBeDirect, + unsigned int stencilClipMask, + bool invertedFill, + int* numPasses, + GrStencilSettings settings[kMaxStencilClipPasses]) { if (canBeDirect && !invertedFill) { *numPasses = 0; switch (op) { @@ -249,10 +250,12 @@ bool GrStencilSettings::GetClipPasses(SkRegion::Op op, break; } if (1 == *numPasses) { - settings[0].fFrontFuncRef |= stencilClipMask; - settings[0].fFrontWriteMask |= stencilClipMask; - settings[0].fBackFuncRef = settings[0].fFrontFuncRef; - settings[0].fBackWriteMask = settings[0].fFrontWriteMask; + settings[0].fFuncRefs[kFront_Face] |= stencilClipMask; + settings[0].fWriteMasks[kFront_Face] |= stencilClipMask; + settings[0].fFuncRefs[kBack_Face] = + settings[0].fFuncRefs[kFront_Face]; + settings[0].fWriteMasks[kBack_Face] = + settings[0].fWriteMasks[kFront_Face]; return true; } } @@ -262,90 +265,111 @@ bool GrStencilSettings::GetClipPasses(SkRegion::Op op, // pass to select either the zeros or nonzeros. case SkRegion::kReplace_Op: *numPasses= 1; - settings[0] = invertedFill ? gInvUserToClipReplace : gUserToClipReplace; - settings[0].fFrontFuncMask &= ~stencilClipMask; - settings[0].fFrontFuncRef |= stencilClipMask; - settings[0].fBackFuncMask = settings[0].fFrontFuncMask; - settings[0].fBackFuncRef = settings[0].fFrontFuncRef; + settings[0] = invertedFill ? gInvUserToClipReplace : + gUserToClipReplace; + settings[0].fFuncMasks[kFront_Face] &= ~stencilClipMask; + settings[0].fFuncRefs[kFront_Face] |= stencilClipMask; + settings[0].fFuncMasks[kBack_Face] = + settings[0].fFuncMasks[kFront_Face]; + settings[0].fFuncRefs[kBack_Face] = + settings[0].fFuncRefs[kFront_Face]; break; case SkRegion::kIntersect_Op: *numPasses = 1; settings[0] = invertedFill ? gInvUserToClipIsect : gUserToClipIsect; - settings[0].fFrontFuncRef = stencilClipMask; - settings[0].fBackFuncRef = settings[0].fFrontFuncRef; + settings[0].fFuncRefs[kFront_Face] = stencilClipMask; + settings[0].fFuncRefs[kBack_Face] = + settings[0].fFuncRefs[kFront_Face]; break; case SkRegion::kUnion_Op: *numPasses = 2; if (invertedFill) { settings[0] = gInvUserToClipUnionPass0; - settings[0].fFrontFuncMask &= ~stencilClipMask; - settings[0].fBackFuncMask = settings[0].fFrontFuncMask; - settings[0].fFrontFuncRef |= stencilClipMask; - settings[0].fBackFuncRef = settings[0].fFrontFuncRef; - settings[0].fFrontWriteMask |= stencilClipMask; - settings[0].fBackWriteMask = settings[0].fFrontWriteMask; + settings[0].fFuncMasks[kFront_Face] &= ~stencilClipMask; + settings[0].fFuncMasks[kBack_Face] = + settings[0].fFuncMasks[kFront_Face]; + settings[0].fFuncRefs[kFront_Face] |= stencilClipMask; + settings[0].fFuncRefs[kBack_Face] = + settings[0].fFuncRefs[kFront_Face]; + settings[0].fWriteMasks[kFront_Face] |= stencilClipMask; + settings[0].fWriteMasks[kBack_Face] = + settings[0].fWriteMasks[kFront_Face]; settings[1] = gInvUserToClipUnionPass1; - settings[1].fFrontWriteMask &= ~stencilClipMask; - settings[1].fBackWriteMask &= settings[1].fFrontWriteMask; + settings[1].fWriteMasks[kFront_Face] &= ~stencilClipMask; + settings[1].fWriteMasks[kBack_Face] &= + settings[1].fWriteMasks[kFront_Face]; } else { settings[0] = gUserToClipUnionPass0; - settings[0].fFrontFuncMask &= ~stencilClipMask; - settings[0].fFrontFuncRef |= stencilClipMask; - settings[0].fBackFuncMask = settings[0].fFrontFuncMask; - settings[0].fBackFuncRef = settings[0].fFrontFuncRef; + settings[0].fFuncMasks[kFront_Face] &= ~stencilClipMask; + settings[0].fFuncRefs[kFront_Face] |= stencilClipMask; + settings[0].fFuncMasks[kBack_Face] = + settings[0].fFuncMasks[kFront_Face]; + settings[0].fFuncRefs[kBack_Face] = + settings[0].fFuncRefs[kFront_Face]; settings[1] = gUserToClipUnionPass1; - settings[1].fFrontFuncRef |= stencilClipMask; - settings[1].fBackFuncRef = settings[1].fFrontFuncRef; + settings[1].fFuncRefs[kFront_Face] |= stencilClipMask; + settings[1].fFuncRefs[kBack_Face] = + settings[1].fFuncRefs[kFront_Face]; } break; case SkRegion::kXOR_Op: *numPasses = 2; if (invertedFill) { settings[0] = gInvUserToClipXorPass0; - settings[0].fFrontFuncMask &= ~stencilClipMask; - settings[0].fBackFuncMask = settings[0].fFrontFuncMask; + settings[0].fFuncMasks[kFront_Face] &= ~stencilClipMask; + settings[0].fFuncMasks[kBack_Face] = + settings[0].fFuncMasks[kFront_Face]; settings[1] = gInvUserToClipXorPass1; - settings[1].fFrontFuncRef |= stencilClipMask; - settings[1].fBackFuncRef = settings[1].fFrontFuncRef; + settings[1].fFuncRefs[kFront_Face] |= stencilClipMask; + settings[1].fFuncRefs[kBack_Face] = + settings[1].fFuncRefs[kFront_Face]; } else { settings[0] = gUserToClipXorPass0; - settings[0].fFrontFuncMask &= ~stencilClipMask; - settings[0].fBackFuncMask = settings[0].fFrontFuncMask; + settings[0].fFuncMasks[kFront_Face] &= ~stencilClipMask; + settings[0].fFuncMasks[kBack_Face] = + settings[0].fFuncMasks[kFront_Face]; settings[1] = gUserToClipXorPass1; - settings[1].fFrontFuncRef |= stencilClipMask; - settings[1].fBackFuncRef = settings[1].fFrontFuncRef; + settings[1].fFuncRefs[kFront_Face] |= stencilClipMask; + settings[1].fFuncRefs[kBack_Face] = + settings[1].fFuncRefs[kFront_Face]; } break; case SkRegion::kDifference_Op: *numPasses = 1; settings[0] = invertedFill ? gInvUserToClipDiff : gUserToClipDiff; - settings[0].fFrontFuncRef |= stencilClipMask; - settings[0].fBackFuncRef = settings[0].fFrontFuncRef; + settings[0].fFuncRefs[kFront_Face] |= stencilClipMask; + settings[0].fFuncRefs[kBack_Face] = + settings[0].fFuncRefs[kFront_Face]; break; case SkRegion::kReverseDifference_Op: if (invertedFill) { *numPasses = 1; settings[0] = gInvUserToClipRDiff; - settings[0].fFrontWriteMask |= stencilClipMask; - settings[0].fBackWriteMask = settings[0].fFrontWriteMask; + settings[0].fWriteMasks[kFront_Face] |= stencilClipMask; + settings[0].fWriteMasks[kBack_Face] = + settings[0].fWriteMasks[kFront_Face]; } else { *numPasses = 2; settings[0] = gUserToClipRDiffPass0; - settings[0].fFrontFuncMask &= ~stencilClipMask; - settings[0].fBackFuncMask = settings[0].fFrontFuncMask; - settings[0].fFrontFuncRef |= stencilClipMask; - settings[0].fBackFuncRef = settings[0].fFrontFuncRef; + settings[0].fFuncMasks[kFront_Face] &= ~stencilClipMask; + settings[0].fFuncMasks[kBack_Face] = + settings[0].fFuncMasks[kFront_Face]; + settings[0].fFuncRefs[kFront_Face] |= stencilClipMask; + settings[0].fFuncRefs[kBack_Face] = + settings[0].fFuncRefs[kFront_Face]; settings[1] = gUserToClipRDiffPass1; - settings[1].fFrontFuncMask |= stencilClipMask; - settings[1].fFrontFuncRef |= stencilClipMask; - settings[1].fBackFuncMask = settings[1].fFrontFuncMask; - settings[1].fBackFuncRef = settings[1].fFrontFuncRef; + settings[1].fFuncMasks[kFront_Face] |= stencilClipMask; + settings[1].fFuncRefs[kFront_Face] |= stencilClipMask; + settings[1].fFuncMasks[kBack_Face] = + settings[1].fFuncMasks[kFront_Face]; + settings[1].fFuncRefs[kBack_Face] = + settings[1].fFuncRefs[kFront_Face]; } break; default: diff --git a/src/gpu/GrStencil.h b/src/gpu/GrStencil.h index bba5aa67b..3a7595a79 100644 --- a/src/gpu/GrStencil.h +++ b/src/gpu/GrStencil.h @@ -103,20 +103,14 @@ enum GrStencilFlags { * GrStencilSettings. (We hang our heads in shame.) */ struct GrStencilSettingsStruct { - GrStencilOp fFrontPassOp : 8; // op to perform when front faces pass - GrStencilOp fBackPassOp : 8; // op to perform when back faces pass - GrStencilOp fFrontFailOp : 8; // op to perform when front faces fail - GrStencilOp fBackFailOp : 8; // op to perform when back faces fail - GrStencilFunc fFrontFunc : 8; // test function for front faces - GrStencilFunc fBackFunc : 8; // test function for back faces - int fPad0 : 8; - int fPad1 : 8; - unsigned short fFrontFuncMask; // mask for front face test - unsigned short fBackFuncMask; // mask for back face test - unsigned short fFrontFuncRef; // reference value for front face test - unsigned short fBackFuncRef; // reference value for back face test - unsigned short fFrontWriteMask; // stencil write mask for front faces - unsigned short fBackWriteMask; // stencil write mask for back faces + 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) @@ -125,9 +119,9 @@ GR_STATIC_ASSERT(sizeof(GrStencilSettingsStruct) == 4*sizeof(uint8_t) + // ops 2*sizeof(uint8_t) + // funcs 2*sizeof(uint8_t) + // pads - 2*sizeof(unsigned short) + // func masks - 2*sizeof(unsigned short) + // ref values - 2*sizeof(unsigned short) + // write masks + 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 @@ -175,36 +169,65 @@ GR_STATIC_ASSERT(sizeof(GrStencilSettingsStruct) == class GrStencilSettings : private GrStencilSettingsStruct { public: + enum Face { + kFront_Face = 0, + kBack_Face = 1, + }; + GrStencilSettings() { fPad0 = fPad1 = 0; this->setDisabled(); } - GrStencilOp frontPassOp() const { return fFrontPassOp; } - GrStencilOp backPassOp() const { return fBackPassOp; } - GrStencilOp frontFailOp() const { return fFrontFailOp; } - GrStencilOp backFailOp() const { return fBackFailOp; } - GrStencilFunc frontFunc() const { return fFrontFunc; } - GrStencilFunc backFunc() const { return fBackFunc; } - unsigned short frontFuncMask() const { return fFrontFuncMask; } - unsigned short backFuncMask() const { return fBackFuncMask; } - unsigned short frontFuncRef() const { return fFrontFuncRef; } - unsigned short backFuncRef() const { return fBackFuncRef; } - unsigned short frontWriteMask() const {return fFrontWriteMask; } - unsigned short backWriteMask() const { return fBackWriteMask; } + GrStencilOp frontPassOp() const { return static_cast(fPassOps[kFront_Face]); } + GrStencilOp backPassOp() const { return static_cast(fPassOps[kBack_Face]); } + GrStencilOp frontFailOp() const { return static_cast(fFailOps[kFront_Face]); } + GrStencilOp backFailOp() const { return static_cast(fFailOps[kBack_Face]); } + GrStencilFunc frontFunc() const { return static_cast(fFuncs[kFront_Face]); } + GrStencilFunc backFunc() const { return static_cast(fFuncs[kBack_Face]); } + uint16_t frontFuncMask() const { return fFuncMasks[kFront_Face]; } + uint16_t backFuncMask() const { return fFuncMasks[kBack_Face]; } + uint16_t frontFuncRef() const { return fFuncRefs[kFront_Face]; } + uint16_t backFuncRef() const { return fFuncRefs[kBack_Face]; } + uint16_t frontWriteMask() const { return fWriteMasks[kFront_Face]; } + uint16_t backWriteMask() const { return fWriteMasks[kFront_Face]; } - void setFrontPassOp(GrStencilOp op) { fFrontPassOp = op; fFlags = 0;} - void setBackPassOp(GrStencilOp op) { fBackPassOp = op; fFlags = 0;} - void setFrontFailOp(GrStencilOp op) {fFrontFailOp = op; fFlags = 0;} - void setBackFailOp(GrStencilOp op) { fBackFailOp = op; fFlags = 0;} - void setFrontFunc(GrStencilFunc func) { fFrontFunc = func; fFlags = 0;} - void setBackFunc(GrStencilFunc func) { fBackFunc = func; fFlags = 0;} - void setFrontFuncMask(unsigned short mask) { fFrontFuncMask = mask; } - void setBackFuncMask(unsigned short mask) { fBackFuncMask = mask; } - void setFrontFuncRef(unsigned short ref) { fFrontFuncRef = ref; } - void setBackFuncRef(unsigned short ref) { fBackFuncRef = ref; } - void setFrontWriteMask(unsigned short writeMask) { fFrontWriteMask = writeMask; } - void setBackWriteMask(unsigned short writeMask) { fBackWriteMask = writeMask; } + 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 setFrontPassOp(GrStencilOp op) { fPassOps[kFront_Face] = op; fFlags = 0;} + void setBackPassOp(GrStencilOp op) { fPassOps[kBack_Face] = op; fFlags = 0;} + void setFrontFailOp(GrStencilOp op) { fFailOps[kFront_Face] = op; fFlags = 0;} + void setBackFailOp(GrStencilOp op) { fFailOps[kBack_Face] = op; fFlags = 0;} + void setFrontFunc(GrStencilFunc func) { fFuncs[kFront_Face] = func; fFlags = 0;} + void setBackFunc(GrStencilFunc func) { fFuncs[kBack_Face] = func; fFlags = 0;} + void setFrontFuncMask(unsigned short mask) { fFuncMasks[kFront_Face] = mask; } + void setBackFuncMask(unsigned short mask) { fFuncMasks[kBack_Face] = mask; } + void setFrontFuncRef(unsigned short ref) { fFuncRefs[kFront_Face] = ref; } + void setBackFuncRef(unsigned short ref) { fFuncRefs[kBack_Face] = ref; } + void setFrontWriteMask(unsigned short writeMask) { fWriteMasks[kFront_Face] = writeMask; } + void setBackWriteMask(unsigned short writeMask) { fWriteMasks[kBack_Face] = writeMask; } + + 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, @@ -212,18 +235,12 @@ public: unsigned short funcMask, unsigned short funcRef, unsigned short 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; + 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; } @@ -242,9 +259,9 @@ public: return false; } bool disabled = GR_STENCIL_SETTINGS_IS_DISABLED( - fFrontPassOp, fBackPassOp, - fFrontFailOp, fBackFailOp, - fFrontFunc ,fBackFunc); + 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; } @@ -257,16 +274,16 @@ public: return false; } bool writes = GR_STENCIL_SETTINGS_DOES_WRITE( - fFrontPassOp, fBackPassOp, - fFrontFailOp, fBackFailOp, - fFrontFunc, fBackFunc); + 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 - fFrontPassOp = (GrStencilOp)(uint8_t)-1; + fPassOps[0] = (GrStencilOp)(uint8_t)-1; fFlags = 0; } @@ -339,13 +356,13 @@ GR_STATIC_ASSERT(sizeof(GrStencilSettingsStruct) == sizeof(GrStencilSettings)); 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), \ + {(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), \ + {(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) \ diff --git a/src/gpu/SkGrFontScaler.cpp b/src/gpu/SkGrFontScaler.cpp index d2e099b03..430b5993e 100644 --- a/src/gpu/SkGrFontScaler.cpp +++ b/src/gpu/SkGrFontScaler.cpp @@ -7,7 +7,7 @@ */ - +#include "GrTemplates.h" #include "SkGr.h" #include "SkDescriptor.h" #include "SkGlyphCache.h" diff --git a/src/gpu/gl/GrGpuGL.cpp b/src/gpu/gl/GrGpuGL.cpp index 5c1764cf2..76a7a6336 100644 --- a/src/gpu/gl/GrGpuGL.cpp +++ b/src/gpu/gl/GrGpuGL.cpp @@ -9,6 +9,7 @@ #include "GrGpuGL.h" #include "GrGLStencilBuffer.h" #include "GrGLPath.h" +#include "GrTemplates.h" #include "GrTypes.h" #include "SkTemplates.h" @@ -496,21 +497,16 @@ void GrGpuGL::onResetContext() { fHWBoundTextures[s] = NULL; } - fHWBounds.fScissorRect.invalidate(); - // set to true to force disableScissor to make a GL call. - fHWBounds.fScissorEnabled = true; - this->disableScissor(); + fHWScissorSettings.invalidate(); - fHWBounds.fViewportRect.invalidate(); + fHWViewport.invalidate(); fHWStencilSettings.invalidate(); - // This is arbitrary. The above invalidate ensures a full setup of the - // stencil on the next draw. - fHWStencilClipMode = GrClipMaskManager::kRespectClip_StencilClipMode; + fHWStencilTestEnabled = kUnknown_TriState; fHWGeometryState.fIndexBuffer = NULL; fHWGeometryState.fVertexBuffer = NULL; - + fHWGeometryState.fArrayPtrsDirty = true; fHWBoundRenderTarget = NULL; @@ -1333,7 +1329,7 @@ GrPath* GrGpuGL::onCreatePath(const SkPath& inPath) { return path; } -void GrGpuGL::enableScissoring(const GrIRect& rect) { +void GrGpuGL::flushScissor() { const GrDrawState& drawState = this->getDrawState(); const GrGLRenderTarget* rt = static_cast(drawState.getRenderTarget()); @@ -1341,28 +1337,31 @@ void GrGpuGL::enableScissoring(const GrIRect& rect) { GrAssert(NULL != rt); const GrGLIRect& vp = rt->getViewport(); - GrGLIRect scissor; - scissor.setRelativeTo(vp, rect.fLeft, rect.fTop, - rect.width(), rect.height()); - if (scissor.contains(vp)) { - disableScissor(); - return; + if (fScissorState.fEnabled) { + GrGLIRect scissor; + scissor.setRelativeTo(vp, + fScissorState.fRect.fLeft, + fScissorState.fRect.fTop, + fScissorState.fRect.width(), + fScissorState.fRect.height()); + // if the scissor fully contains the viewport then we fall through and + // disable the scissor test. + if (!scissor.contains(vp)) { + if (fHWScissorSettings.fRect != scissor) { + scissor.pushToGLScissor(this->glInterface()); + fHWScissorSettings.fRect = scissor; + } + if (kYes_TriState != fHWScissorSettings.fEnabled) { + GL_CALL(Enable(GR_GL_SCISSOR_TEST)); + fHWScissorSettings.fEnabled = kYes_TriState; + } + return; + } } - - if (fHWBounds.fScissorRect != scissor) { - scissor.pushToGLScissor(this->glInterface()); - fHWBounds.fScissorRect = scissor; - } - if (!fHWBounds.fScissorEnabled) { - GL_CALL(Enable(GR_GL_SCISSOR_TEST)); - fHWBounds.fScissorEnabled = true; - } -} - -void GrGpuGL::disableScissor() { - if (fHWBounds.fScissorEnabled) { + if (kNo_TriState != fHWScissorSettings.fEnabled) { GL_CALL(Disable(GR_GL_SCISSOR_TEST)); - fHWBounds.fScissorEnabled = false; + fHWScissorSettings.fEnabled = kNo_TriState; + return; } } @@ -1384,10 +1383,12 @@ void GrGpuGL::onClear(const GrIRect* rect, GrColor color) { } } this->flushRenderTarget(rect); - if (NULL != rect) - this->enableScissoring(*rect); - else - this->disableScissor(); + GrAutoTRestore asr(&fScissorState); + fScissorState.fEnabled = (NULL != rect); + if (fScissorState.fEnabled) { + fScissorState.fRect = *rect; + } + this->flushScissor(); GrGLfloat r, g, b, a; static const GrGLfloat scale255 = 1.f / 255.f; @@ -1413,7 +1414,9 @@ void GrGpuGL::clearStencil() { this->flushRenderTarget(&GrIRect::EmptyIRect()); - this->disableScissor(); + GrAutoTRestore asr(&fScissorState); + fScissorState.fEnabled = false; + this->flushScissor(); GL_CALL(StencilMask(0xffffffff)); GL_CALL(ClearStencil(0)); @@ -1448,7 +1451,12 @@ void GrGpuGL::clearStencilClip(const GrIRect& rect, bool insideClip) { value = 0; } this->flushRenderTarget(&GrIRect::EmptyIRect()); - this->enableScissoring(rect); + + GrAutoTRestore asr(&fScissorState); + fScissorState.fEnabled = true; + fScissorState.fRect = rect; + this->flushScissor(); + GL_CALL(StencilMask((uint32_t) clipStencilMask)); GL_CALL(ClearStencil(value)); GL_CALL(Clear(GR_GL_STENCIL_BUFFER_BIT)); @@ -1625,9 +1633,9 @@ void GrGpuGL::flushRenderTarget(const GrIRect* bound) { #endif fHWBoundRenderTarget = rt; const GrGLIRect& vp = rt->getViewport(); - if (fHWBounds.fViewportRect != vp) { + if (fHWViewport != vp) { vp.pushToGLViewport(this->glInterface()); - fHWBounds.fViewportRect = vp; + fHWViewport = vp; } } if (NULL == bound || !bound->isEmpty()) { @@ -1747,28 +1755,25 @@ void GrGpuGL::onResolveRenderTarget(GrRenderTarget* target) { const GrGLIRect& vp = rt->getViewport(); const GrIRect dirtyRect = rt->getResolveRect(); GrGLIRect r; - r.setRelativeTo(vp, dirtyRect.fLeft, dirtyRect.fTop, + r.setRelativeTo(vp, dirtyRect.fLeft, dirtyRect.fTop, dirtyRect.width(), dirtyRect.height()); + GrAutoTRestore asr; if (GrGLCaps::kAppleES_MSFBOType == this->glCaps().msFBOType()) { // Apple's extension uses the scissor as the blit bounds. -#if 1 - GL_CALL(Enable(GR_GL_SCISSOR_TEST)); - GL_CALL(Scissor(r.fLeft, r.fBottom, - r.fWidth, r.fHeight)); + asr.reset(&fScissorState); + fScissorState.fEnabled = true; + fScissorState.fRect = dirtyRect; + this->flushScissor(); GL_CALL(ResolveMultisampleFramebuffer()); - fHWBounds.fScissorRect.invalidate(); - fHWBounds.fScissorEnabled = true; -#else - this->enableScissoring(dirtyRect); - GL_CALL(ResolveMultisampleFramebuffer()); -#endif } else { if (GrGLCaps::kDesktopARB_MSFBOType != this->glCaps().msFBOType()) { // this respects the scissor during the blit, so disable it. GrAssert(GrGLCaps::kDesktopEXT_MSFBOType == this->glCaps().msFBOType()); - this->disableScissor(); + asr.reset(&fScissorState); + fScissorState.fEnabled = false; + this->flushScissor(); } int right = r.fLeft + r.fWidth; int top = r.fBottom + r.fHeight; @@ -1832,16 +1837,16 @@ GrGLenum gr_to_gl_stencil_op(GrStencilOp op) { } void set_gl_stencil(const GrGLInterface* gl, + const GrStencilSettings& settings, GrGLenum glFace, - GrStencilFunc func, - GrStencilOp failOp, - GrStencilOp passOp, - unsigned int ref, - unsigned int mask, - unsigned int writeMask) { - GrGLenum glFunc = gr_to_gl_stencil_func(func); - GrGLenum glFailOp = gr_to_gl_stencil_op(failOp); - GrGLenum glPassOp = gr_to_gl_stencil_op(passOp); + GrStencilSettings::Face grFace) { + GrGLenum glFunc = gr_to_gl_stencil_func(settings.func(grFace)); + GrGLenum glFailOp = gr_to_gl_stencil_op(settings.failOp(grFace)); + GrGLenum glPassOp = gr_to_gl_stencil_op(settings.passOp(grFace)); + + GrGLint ref = settings.funcRef(grFace); + GrGLint mask = settings.funcMask(grFace); + GrGLint writeMask = settings.writeMask(grFace); if (GR_GL_FRONT_AND_BACK == glFace) { // we call the combined func just in case separate stencil is not @@ -1858,112 +1863,36 @@ void set_gl_stencil(const GrGLInterface* gl, } void GrGpuGL::flushStencil() { - const GrDrawState& drawState = this->getDrawState(); - - // use stencil for clipping if clipping is enabled and the clip - // has been written into the stencil. - GrClipMaskManager::StencilClipMode clipMode; - if (fClipMaskManager.isClipInStencil() && - drawState.isClipState()) { - clipMode = GrClipMaskManager::kRespectClip_StencilClipMode; - // We can't be modifying the clip and respecting it at the same time. - GrAssert(!drawState.isStateFlagEnabled(kModifyStencilClip_StateBit)); - } else if (drawState.isStateFlagEnabled(kModifyStencilClip_StateBit)) { - clipMode = GrClipMaskManager::kModifyClip_StencilClipMode; - } else { - clipMode = GrClipMaskManager::kIgnoreClip_StencilClipMode; - } - - // The caller may not be using the stencil buffer but we may need to enable - // it in order to respect a stencil clip. - const GrStencilSettings* settings = &drawState.getStencil(); - if (settings->isDisabled() && - GrClipMaskManager::kRespectClip_StencilClipMode == clipMode) { - settings = GetClipStencilSettings(); - } - - // TODO: dynamically attach a stencil buffer - int stencilBits = 0; - GrStencilBuffer* stencilBuffer = - drawState.getRenderTarget()->getStencilBuffer(); - if (NULL != stencilBuffer) { - stencilBits = stencilBuffer->bits(); - } - GrAssert(stencilBits || settings->isDisabled()); - - bool updateStencilSettings = stencilBits > 0 && - ((fHWStencilSettings != *settings) || - (fHWStencilClipMode != clipMode)); - if (updateStencilSettings) { - if (settings->isDisabled()) { + if (fStencilSettings.isDisabled()) { + if (kNo_TriState != fHWStencilTestEnabled) { GL_CALL(Disable(GR_GL_STENCIL_TEST)); - } else { + fHWStencilTestEnabled = kNo_TriState; + } + } else { + if (kYes_TriState != fHWStencilTestEnabled) { GL_CALL(Enable(GR_GL_STENCIL_TEST)); - #if GR_DEBUG - if (!this->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 - - unsigned int frontRef = settings->frontFuncRef(); - unsigned int frontMask = settings->frontFuncMask(); - unsigned int frontWriteMask = settings->frontWriteMask(); - - GrStencilFunc frontFunc = - fClipMaskManager.adjustStencilParams(settings->frontFunc(), - clipMode, - stencilBits, - &frontRef, - &frontMask, - &frontWriteMask); + fHWStencilTestEnabled = kYes_TriState; + } + } + if (fHWStencilSettings != fStencilSettings) { + if (!fStencilSettings.isDisabled()) { if (this->getCaps().fTwoSidedStencilSupport) { - unsigned int backRef = settings->backFuncRef(); - unsigned int backMask = settings->backFuncMask(); - unsigned int backWriteMask = settings->backWriteMask(); - - GrStencilFunc backFunc = - fClipMaskManager.adjustStencilParams(settings->frontFunc(), - clipMode, - stencilBits, - &backRef, - &backMask, - &backWriteMask); set_gl_stencil(this->glInterface(), + fStencilSettings, GR_GL_FRONT, - frontFunc, - settings->frontFailOp(), - settings->frontPassOp(), - frontRef, - frontMask, - frontWriteMask); + GrStencilSettings::kFront_Face); set_gl_stencil(this->glInterface(), + fStencilSettings, GR_GL_BACK, - backFunc, - settings->backFailOp(), - settings->backPassOp(), - backRef, - backMask, - backWriteMask); + GrStencilSettings::kBack_Face); } else { set_gl_stencil(this->glInterface(), + fStencilSettings, GR_GL_FRONT_AND_BACK, - frontFunc, - settings->frontFailOp(), - settings->frontPassOp(), - frontRef, - frontMask, - frontWriteMask); + GrStencilSettings::kFront_Face); } } - fHWStencilSettings = *settings; - fHWStencilClipMode = clipMode; + fHWStencilSettings = fStencilSettings; } } diff --git a/src/gpu/gl/GrGpuGL.h b/src/gpu/gl/GrGpuGL.h index 51e49ec1e..6220efafe 100644 --- a/src/gpu/gl/GrGpuGL.h +++ b/src/gpu/gl/GrGpuGL.h @@ -108,8 +108,6 @@ protected: uint32_t vertexCount, uint32_t numVertices) SK_OVERRIDE; virtual void onGpuStencilPath(const GrPath&, GrPathFill) SK_OVERRIDE; - virtual void enableScissoring(const GrIRect& rect) SK_OVERRIDE; - virtual void disableScissor() SK_OVERRIDE; virtual void clearStencil() SK_OVERRIDE; virtual void clearStencilClip(const GrIRect& rect, @@ -206,6 +204,10 @@ private: }; // binds the texture and sets its texture params + // This may also perform a downsample on the src texture which may or may + // not modify the scissor test and rect. So in flushGraphicsState a + // call to flushScissor must occur after all textures have been flushed via + // this function. void flushBoundTextureAndParams(int stage); // sets the texture matrix and domain for the currently bound program @@ -232,6 +234,10 @@ private: // flushes dithering, color-mask, and face culling stat void flushMiscFixedFunctionState(); + // flushes the scissor. see the note on flushBoundTextureAndParams about + // flushing the scissor after that function is called. + void flushScissor(); + static void DeleteProgram(const GrGLInterface* gl, CachedData* programData); @@ -304,19 +310,24 @@ private: GrColor fHWConstAttribColor; GrColor fHWConstAttribCoverage; - // last scissor / viewport scissor state seen by the GL. - struct { - bool fScissorEnabled; - GrGLIRect fScissorRect; - GrGLIRect fViewportRect; - } fHWBounds; - enum TriState { kNo_TriState, kYes_TriState, kUnknown_TriState }; + // last scissor / viewport scissor state seen by the GL. + struct { + TriState fEnabled; + GrGLIRect fRect; + void invalidate() { + fEnabled = kUnknown_TriState; + fRect.invalidate(); + } + } fHWScissorSettings; + + GrGLIRect fHWViewport; + struct { size_t fVertexOffset; GrVertexLayout fVertexLayout; @@ -349,8 +360,8 @@ private: } } fHWAAState; - GrClipMaskManager::StencilClipMode fHWStencilClipMode; - GrStencilSettings fHWStencilSettings; + GrStencilSettings fHWStencilSettings; + TriState fHWStencilTestEnabled; GrDrawState::DrawFace fHWDrawFace; TriState fHWWriteToColor; diff --git a/src/gpu/gl/GrGpuGL_program.cpp b/src/gpu/gl/GrGpuGL_program.cpp index f8d71ffbf..3ad352070 100644 --- a/src/gpu/gl/GrGpuGL_program.cpp +++ b/src/gpu/gl/GrGpuGL_program.cpp @@ -454,6 +454,7 @@ bool GrGpuGL::flushGraphicsState(DrawType type) { } } this->flushColorMatrix(); + this->flushScissor(); GrIRect* rect = NULL; GrIRect clipBounds;