First pass at stencil clip mask refactoring

http://codereview.appspot.com/6031043/



git-svn-id: http://skia.googlecode.com/svn/trunk@3692 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
robertphillips@google.com 2012-04-16 16:33:13 +00:00
parent a90aa53498
commit 730ebe5e00
5 changed files with 348 additions and 222 deletions

View File

@ -31,8 +31,7 @@ extern void gr_run_unittests();
#define DEBUG_INVAL_START_IDX -1
GrGpu::GrGpu()
: fClipInStencil(false)
, fContext(NULL)
: fContext(NULL)
, fResetTimestamp(kExpiredTimestamp+1)
, fVertexPool(NULL)
, fIndexPool(NULL)
@ -40,7 +39,6 @@ GrGpu::GrGpu()
, fIndexPoolUseCnt(0)
, fQuadIndexBuffer(NULL)
, fUnitSquareVertexBuffer(NULL)
, fPathRendererChain(NULL)
, fContextIsDirty(true)
, fResourceHead(NULL) {
@ -82,8 +80,8 @@ void GrGpu::abandonResources() {
fVertexPool = NULL;
delete fIndexPool;
fIndexPool = NULL;
// in case path renderer has any GrResources, start from scratch
GrSafeSetNull(fPathRendererChain);
fClipMaskManager.freeResources();
}
void GrGpu::releaseResources() {
@ -101,8 +99,8 @@ void GrGpu::releaseResources() {
fVertexPool = NULL;
delete fIndexPool;
fIndexPool = NULL;
// in case path renderer has any GrResources, start from scratch
GrSafeSetNull(fPathRendererChain);
fClipMaskManager.freeResources();
}
void GrGpu::insertResource(GrResource* resource) {
@ -543,206 +541,255 @@ int process_initial_clip_elements(const GrClip& clip,
}
}
bool GrGpu::setupClipAndFlushState(GrPrimitiveType type) {
const GrIRect* r = NULL;
GrIRect clipRect;
GrDrawState* drawState = this->drawState();
// sort out what kind of clip mask needs to be created: A8/R8, stencil or scissor
bool GrClipMaskManager::createClipMask(GrGpu* gpu,
const GrClip& clipIn,
ScissoringSettings* scissorSettings) {
GrAssert(scissorSettings);
scissorSettings->fEnableScissoring = false;
fClipMaskInStencil = false;
GrDrawState* drawState = gpu->drawState();
if (!drawState->isClipState()) {
return true;
}
GrRenderTarget* rt = drawState->getRenderTarget();
// GrDrawTarget should have filtered this for us
GrAssert(NULL != rt);
if (drawState->isClipState()) {
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!
}
scissorSettings->fEnableScissoring = true;
// use the stencil clip if we can't represent the clip as a rectangle.
fClipMaskInStencil = !clipIn.isRect() && !clipIn.isEmpty() &&
!bounds.isEmpty();
if (fClipMaskInStencil) {
return this->createStencilClipMask(gpu, clipIn, bounds, scissorSettings);
}
return true;
}
// Create a 1-bit clip mask in the stencil buffer
bool GrClipMaskManager::createStencilClipMask(GrGpu* gpu,
const GrClip& clipIn,
const GrRect& bounds,
ScissoringSettings* scissorSettings) {
GrAssert(fClipMaskInStencil);
GrDrawState* drawState = gpu->drawState();
GrAssert(drawState->isClipState());
GrRenderTarget* rt = drawState->getRenderTarget();
GrAssert(NULL != rt);
// TODO: dynamically attach a SB when needed.
GrStencilBuffer* stencilBuffer = rt->getStencilBuffer();
if (NULL == stencilBuffer) {
return false;
}
if (stencilBuffer->mustRenderClip(clipIn, rt->width(), rt->height())) {
stencilBuffer->setLastClip(clipIn, rt->width(), rt->height());
// we set the current clip to the bounds so that our recursive
// draws are scissored to them. We use the copy of the complex clip
// we just stashed on the SB to render from. We set it back after
// we finish drawing it into the stencil.
const GrClip& clipCopy = stencilBuffer->getLastClip();
gpu->setClip(GrClip(bounds));
GrDrawTarget::AutoStateRestore asr(gpu, GrDrawTarget::kReset_ASRInit);
drawState = gpu->drawState();
drawState->setRenderTarget(rt);
GrDrawTarget::AutoGeometryPush agp(gpu);
gpu->disableScissor();
#if !VISUALIZE_COMPLEX_CLIP
drawState->enableState(GrDrawState::kNoColorWrites_StateBit);
#endif
int count = clipCopy.getElementCount();
int clipBit = stencilBuffer->bits();
SkASSERT((clipBit <= 16) &&
"Ganesh only handles 16b or smaller stencil buffers");
clipBit = (1 << (clipBit-1));
GrRect bounds;
GrRect rtRect;
rtRect.setLTRB(0, 0,
GrIntToScalar(rt->width()), GrIntToScalar(rt->height()));
if (fClip.hasConservativeBounds()) {
bounds = fClip.getConservativeBounds();
if (!bounds.intersect(rtRect)) {
bounds.setEmpty();
bool clearToInside;
GrSetOp startOp = kReplace_SetOp; // suppress warning
int start = process_initial_clip_elements(clipCopy,
rtRect,
&clearToInside,
&startOp);
gpu->clearStencilClip(scissorSettings->fScissorRect, clearToInside);
// walk through each clip element and perform its set op
// with the existing clip.
for (int c = start; c < count; ++c) {
GrPathFill fill;
bool fillInverted;
// enabled at bottom of loop
drawState->disableState(GrGpu::kModifyStencilClip_StateBit);
bool canRenderDirectToStencil; // can the clip element be drawn
// directly to the stencil buffer
// with a non-inverted fill rule
// without extra passes to
// resolve in/out status.
GrPathRenderer* pr = NULL;
const GrPath* clipPath = NULL;
if (kRect_ClipType == clipCopy.getElementType(c)) {
canRenderDirectToStencil = true;
fill = kEvenOdd_PathFill;
fillInverted = false;
// there is no point in intersecting a screen filling
// rectangle.
if (kIntersect_SetOp == clipCopy.getOp(c) &&
clipCopy.getRect(c).contains(rtRect)) {
continue;
}
} else {
fill = clipCopy.getPathFill(c);
fillInverted = GrIsFillInverted(fill);
fill = GrNonInvertedFill(fill);
clipPath = &clipCopy.getPath(c);
pr = this->getClipPathRenderer(gpu, *clipPath, fill);
if (NULL == pr) {
fClipMaskInStencil = false;
gpu->setClip(clipCopy); // restore to the original
return false;
}
canRenderDirectToStencil =
!pr->requiresStencilPass(*clipPath, fill, gpu);
}
} else {
bounds = rtRect;
}
bounds.roundOut(&clipRect);
if (clipRect.isEmpty()) {
clipRect.setLTRB(0,0,0,0);
}
r = &clipRect;
GrSetOp op = (c == start) ? startOp : clipCopy.getOp(c);
int passes;
GrStencilSettings stencilSettings[GrStencilSettings::kMaxStencilClipPasses];
// use the stencil clip if we can't represent the clip as a rectangle.
fClipInStencil = !fClip.isRect() && !fClip.isEmpty() &&
!bounds.isEmpty();
bool canDrawDirectToClip; // Given the renderer, the element,
// fill rule, and set operation can
// we render the element directly to
// stencil bit used for clipping.
canDrawDirectToClip =
GrStencilSettings::GetClipPasses(op,
canRenderDirectToStencil,
clipBit,
fillInverted,
&passes, stencilSettings);
// TODO: dynamically attach a SB when needed.
GrStencilBuffer* stencilBuffer = rt->getStencilBuffer();
if (fClipInStencil && NULL == stencilBuffer) {
return false;
}
if (fClipInStencil &&
stencilBuffer->mustRenderClip(fClip, rt->width(), rt->height())) {
stencilBuffer->setLastClip(fClip, rt->width(), rt->height());
// we set the current clip to the bounds so that our recursive
// draws are scissored to them. We use the copy of the complex clip
// we just stashed on the SB to render from. We set it back after
// we finish drawing it into the stencil.
const GrClip& clip = stencilBuffer->getLastClip();
fClip.setFromRect(bounds);
AutoStateRestore asr(this, GrDrawTarget::kReset_ASRInit);
drawState = this->drawState();
drawState->setRenderTarget(rt);
AutoGeometryPush agp(this);
this->flushScissor(NULL);
#if !VISUALIZE_COMPLEX_CLIP
drawState->enableState(GrDrawState::kNoColorWrites_StateBit);
#endif
int count = clip.getElementCount();
int clipBit = stencilBuffer->bits();
SkASSERT((clipBit <= 16) &&
"Ganesh only handles 16b or smaller stencil buffers");
clipBit = (1 << (clipBit-1));
bool clearToInside;
GrSetOp startOp = kReplace_SetOp; // suppress warning
int start = process_initial_clip_elements(clip,
rtRect,
&clearToInside,
&startOp);
this->clearStencilClip(clipRect, clearToInside);
// walk through each clip element and perform its set op
// with the existing clip.
for (int c = start; c < count; ++c) {
GrPathFill fill;
bool fillInverted;
// enabled at bottom of loop
drawState->disableState(kModifyStencilClip_StateBit);
bool canRenderDirectToStencil; // can the clip element be drawn
// directly to the stencil buffer
// with a non-inverted fill rule
// without extra passes to
// resolve in/out status.
GrPathRenderer* pr = NULL;
const GrPath* clipPath = NULL;
if (kRect_ClipType == clip.getElementType(c)) {
canRenderDirectToStencil = true;
fill = kEvenOdd_PathFill;
fillInverted = false;
// there is no point in intersecting a screen filling
// rectangle.
if (kIntersect_SetOp == clip.getOp(c) &&
clip.getRect(c).contains(rtRect)) {
continue;
}
// draw the element to the client stencil bits if necessary
if (!canDrawDirectToClip) {
GR_STATIC_CONST_SAME_STENCIL(gDrawToStencil,
kIncClamp_StencilOp,
kIncClamp_StencilOp,
kAlways_StencilFunc,
0xffff,
0x0000,
0xffff);
SET_RANDOM_COLOR
if (kRect_ClipType == clipCopy.getElementType(c)) {
*drawState->stencil() = gDrawToStencil;
gpu->drawSimpleRect(clipCopy.getRect(c), NULL, 0);
} else {
fill = clip.getPathFill(c);
fillInverted = GrIsFillInverted(fill);
fill = GrNonInvertedFill(fill);
clipPath = &clip.getPath(c);
pr = this->getClipPathRenderer(*clipPath, fill);
if (NULL == pr) {
fClipInStencil = false;
fClip = clip;
return false;
}
canRenderDirectToStencil =
!pr->requiresStencilPass(*clipPath, fill, this);
}
GrSetOp op = (c == start) ? startOp : clip.getOp(c);
int passes;
GrStencilSettings stencilSettings[GrStencilSettings::kMaxStencilClipPasses];
bool canDrawDirectToClip; // Given the renderer, the element,
// fill rule, and set operation can
// we render the element directly to
// stencil bit used for clipping.
canDrawDirectToClip =
GrStencilSettings::GetClipPasses(op,
canRenderDirectToStencil,
clipBit,
fillInverted,
&passes, stencilSettings);
// draw the element to the client stencil bits if necessary
if (!canDrawDirectToClip) {
GR_STATIC_CONST_SAME_STENCIL(gDrawToStencil,
kIncClamp_StencilOp,
kIncClamp_StencilOp,
kAlways_StencilFunc,
0xffff,
0x0000,
0xffff);
SET_RANDOM_COLOR
if (kRect_ClipType == clip.getElementType(c)) {
if (canRenderDirectToStencil) {
*drawState->stencil() = gDrawToStencil;
this->drawSimpleRect(clip.getRect(c), NULL, 0);
pr->drawPath(*clipPath, fill, NULL, gpu, 0, false);
} else {
if (canRenderDirectToStencil) {
*drawState->stencil() = gDrawToStencil;
pr->drawPath(*clipPath, fill, NULL, this, 0, false);
} else {
pr->drawPathToStencil(*clipPath, fill, this);
}
pr->drawPathToStencil(*clipPath, fill, gpu);
}
}
}
// now we modify the clip bit by rendering either the clip
// element directly or a bounding rect of the entire clip.
drawState->enableState(kModifyStencilClip_StateBit);
for (int p = 0; p < passes; ++p) {
*drawState->stencil() = stencilSettings[p];
if (canDrawDirectToClip) {
if (kRect_ClipType == clip.getElementType(c)) {
SET_RANDOM_COLOR
this->drawSimpleRect(clip.getRect(c), NULL, 0);
} else {
SET_RANDOM_COLOR
pr->drawPath(*clipPath, fill, NULL, this, 0, false);
}
// now we modify the clip bit by rendering either the clip
// element directly or a bounding rect of the entire clip.
drawState->enableState(GrGpu::kModifyStencilClip_StateBit);
for (int p = 0; p < passes; ++p) {
*drawState->stencil() = stencilSettings[p];
if (canDrawDirectToClip) {
if (kRect_ClipType == clipCopy.getElementType(c)) {
SET_RANDOM_COLOR
gpu->drawSimpleRect(clipCopy.getRect(c), NULL, 0);
} else {
SET_RANDOM_COLOR
this->drawSimpleRect(bounds, NULL, 0);
pr->drawPath(*clipPath, fill, NULL, gpu, 0, false);
}
} else {
SET_RANDOM_COLOR
gpu->drawSimpleRect(bounds, NULL, 0);
}
}
// restore clip
fClip = clip;
// recusive draws would have disabled this since they drew with
// the clip bounds as clip.
fClipInStencil = true;
}
// restore clip
gpu->setClip(clipCopy);
// recusive draws would have disabled this since they drew with
// the clip bounds as clip.
fClipMaskInStencil = true;
}
return true;
}
bool GrGpu::setupClipAndFlushState(GrPrimitiveType type) {
ScissoringSettings scissoringSettings;
if (!fClipMaskManager.createClipMask(this, fClip, &scissoringSettings)) {
return false;
}
// Must flush the scissor after graphics state
if (!this->flushGraphicsState(type)) {
return false;
}
this->flushScissor(r);
scissoringSettings.setupScissoring(this);
return true;
}
GrPathRenderer* GrGpu::getClipPathRenderer(const GrPath& path,
GrPathFill fill) {
GrPathRenderer* GrClipMaskManager::getClipPathRenderer(GrGpu* gpu,
const GrPath& path,
GrPathFill fill) {
if (NULL == fPathRendererChain) {
fPathRendererChain =
new GrPathRendererChain(this->getContext(),
new GrPathRendererChain(gpu->getContext(),
GrPathRendererChain::kNonAAOnly_UsageFlag);
}
return fPathRendererChain->getPathRenderer(path, fill, this, false);
return fPathRendererChain->getPathRenderer(path, fill, gpu, false);
}
@ -982,3 +1029,19 @@ void GrGpu::printStats() const {
}
}
////////////////////////////////////////////////////////////////////////////////
void ScissoringSettings::setupScissoring(GrGpu* gpu) {
if (!fEnableScissoring) {
gpu->disableScissor();
return;
}
gpu->enableScissoring(fScissorRect);
}
void GrClipMaskManager::freeResources() {
// in case path renderer has any GrResources, start from scratch
GrSafeSetNull(fPathRendererChain);
}

View File

@ -51,6 +51,66 @@ struct GrGpuStats {
uint32_t fRenderTargetCreateCnt;
};
/**
* 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 clip mask creator handles the generation of the clip mask. If anti
* aliasing is requested it will (in the future) generate a single channel
* (8bit) mask. If no anti aliasing is requested it will generate a 1-bit
* mask in the stencil buffer. In the non anti-aliasing case, if the clip
* mask can be represented as a rectangle then scissoring is used. In all
* cases scissoring is used to bound the range of the clip mask.
*/
class GrClipMaskManager {
public:
GrClipMaskManager()
: fClipMaskInStencil(false)
, fPathRendererChain(NULL) {
}
bool createClipMask(GrGpu* gpu,
const GrClip& clip,
ScissoringSettings* scissorSettings);
void freeResources();
bool isClipInStencil() const { return fClipMaskInStencil; }
void resetMask() {
fClipMaskInStencil = false;
}
protected:
private:
bool fClipMaskInStencil; // is the clip mask in the stencil buffer?
// must be instantiated after GrGpu object has been given its owning
// GrContext ptr. (GrGpu is constructed first then handed off to GrContext).
GrPathRendererChain* fPathRendererChain;
bool createStencilClipMask(GrGpu* gpu,
const GrClip& clip,
const GrRect& bounds,
ScissoringSettings* scissorSettings);
// determines the path renderer used to draw a clip path element.
GrPathRenderer* getClipPathRenderer(GrGpu* gpu,
const SkPath& path,
GrPathFill fill);
};
class GrGpu : public GrDrawTarget {
public:
@ -341,7 +401,14 @@ public:
return fConfigRenderSupport[config];
}
protected:
virtual void enableScissoring(const GrIRect& rect) = 0;
virtual void disableScissor() = 0;
// 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
// expensive than clearing all bits.
virtual void clearStencilClip(const GrIRect& rect, bool insideClip) = 0;
enum PrivateDrawStateStateBits {
kFirstBit = (GrDrawState::kLastPublicStateBit << 1),
@ -350,10 +417,7 @@ protected:
// clipping.
};
// keep track of whether we are using stencil clipping (as opposed to
// scissor).
bool fClipInStencil;
protected:
// prepares clip flushes gpu state before a draw
bool setupClipAndFlushState(GrPrimitiveType type);
@ -374,6 +438,8 @@ protected:
GrGpuStats fStats;
GrClipMaskManager fClipMaskManager;
struct GeometryPoolState {
const GrVertexBuffer* fPoolVertexBuffer;
int fPoolStartVertex;
@ -485,14 +551,6 @@ protected:
// returns false if current state is unsupported.
virtual bool flushGraphicsState(GrPrimitiveType type) = 0;
// Sets the scissor rect, or disables if rect is NULL.
virtual void flushScissor(const GrIRect* rect) = 0;
// 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
// expensive than clearing all bits.
virtual void clearStencilClip(const GrIRect& rect, bool insideClip) = 0;
// clears the entire stencil buffer to 0
virtual void clearStencil() = 0;
@ -521,10 +579,6 @@ private:
mutable GrVertexBuffer* fUnitSquareVertexBuffer; // mutable so it can be
// created on-demand
// must be instantiated after GrGpu object has been given its owning
// GrContext ptr. (GrGpu is constructed first then handed off to GrContext).
GrPathRendererChain* fPathRendererChain;
bool fContextIsDirty;
GrResource* fResourceHead;
@ -546,9 +600,6 @@ private:
void prepareVertexPool();
void prepareIndexPool();
// determines the path renderer used to draw a clip path element.
GrPathRenderer* getClipPathRenderer(const SkPath& path, GrPathFill fill);
void resetContext() {
this->onResetContext();
++fResetTimestamp;

View File

@ -289,7 +289,8 @@ public:
}
private:
friend class GrGpu;
friend class GrClipMaskManager;
enum {
kMaxStencilClipPasses = 2 // maximum number of passes to add a clip
// element to the stencil buffer.

View File

@ -516,13 +516,16 @@ void GrGpuGL::onResetContext() {
}
fHWBounds.fScissorRect.invalidate();
fHWBounds.fScissorEnabled = false;
GL_CALL(Disable(GR_GL_SCISSOR_TEST));
this->disableScissor();
fHWBounds.fViewportRect.invalidate();
fHWDrawState.stencil()->invalidate();
fHWStencilClip = false;
fClipInStencil = false;
// TODO: I believe this should actually go in GrGpu::onResetContext
// rather than here
fClipMaskManager.resetMask();
fHWGeometryState.fIndexBuffer = NULL;
fHWGeometryState.fVertexBuffer = NULL;
@ -1311,7 +1314,7 @@ GrIndexBuffer* GrGpuGL::onCreateIndexBuffer(uint32_t size, bool dynamic) {
return NULL;
}
void GrGpuGL::flushScissor(const GrIRect* rect) {
void GrGpuGL::enableScissoring(const GrIRect& rect) {
const GrDrawState& drawState = this->getDrawState();
const GrGLRenderTarget* rt =
static_cast<const GrGLRenderTarget*>(drawState.getRenderTarget());
@ -1320,28 +1323,28 @@ void GrGpuGL::flushScissor(const GrIRect* rect) {
const GrGLIRect& vp = rt->getViewport();
GrGLIRect scissor;
if (NULL != rect) {
scissor.setRelativeTo(vp, rect->fLeft, rect->fTop,
rect->width(), rect->height());
if (scissor.contains(vp)) {
rect = NULL;
}
scissor.setRelativeTo(vp, rect.fLeft, rect.fTop,
rect.width(), rect.height());
if (scissor.contains(vp)) {
disableScissor();
return;
}
if (NULL != rect) {
if (fHWBounds.fScissorRect != scissor) {
scissor.pushToGLScissor(this->glInterface());
fHWBounds.fScissorRect = scissor;
}
if (!fHWBounds.fScissorEnabled) {
GL_CALL(Enable(GR_GL_SCISSOR_TEST));
fHWBounds.fScissorEnabled = true;
}
} else {
if (fHWBounds.fScissorEnabled) {
GL_CALL(Disable(GR_GL_SCISSOR_TEST));
fHWBounds.fScissorEnabled = false;
}
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) {
GL_CALL(Disable(GR_GL_SCISSOR_TEST));
fHWBounds.fScissorEnabled = false;
// fHWBounds.fScissorRect.invalidate();
}
}
@ -1363,7 +1366,10 @@ void GrGpuGL::onClear(const GrIRect* rect, GrColor color) {
}
}
this->flushRenderTarget(rect);
this->flushScissor(rect);
if (NULL != rect)
this->enableScissoring(*rect);
else
this->disableScissor();
GrGLfloat r, g, b, a;
static const GrGLfloat scale255 = 1.f / 255.f;
@ -1389,10 +1395,8 @@ void GrGpuGL::clearStencil() {
this->flushRenderTarget(&GrIRect::EmptyIRect());
if (fHWBounds.fScissorEnabled) {
GL_CALL(Disable(GR_GL_SCISSOR_TEST));
fHWBounds.fScissorEnabled = false;
}
this->disableScissor();
GL_CALL(StencilMask(0xffffffff));
GL_CALL(ClearStencil(0));
GL_CALL(Clear(GR_GL_STENCIL_BUFFER_BIT));
@ -1426,7 +1430,7 @@ void GrGpuGL::clearStencilClip(const GrIRect& rect, bool insideClip) {
value = 0;
}
this->flushRenderTarget(&GrIRect::EmptyIRect());
this->flushScissor(&rect);
this->enableScissoring(rect);
GL_CALL(StencilMask(clipStencilMask));
GL_CALL(ClearStencil(value));
GL_CALL(Clear(GR_GL_STENCIL_BUFFER_BIT));
@ -1733,18 +1737,23 @@ void GrGpuGL::onResolveRenderTarget(GrRenderTarget* target) {
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));
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->flushScissor(NULL);
this->disableScissor();
}
int right = r.fLeft + r.fWidth;
int top = r.fBottom + r.fHeight;
@ -1803,7 +1812,7 @@ void GrGpuGL::flushStencil() {
// use stencil for clipping if clipping is enabled and the clip
// has been written into the stencil.
bool stencilClip = fClipInStencil && drawState.isClipState();
bool stencilClip = fClipMaskManager.isClipInStencil() && drawState.isClipState();
bool drawClipToStencil =
drawState.isStateFlagEnabled(kModifyStencilClip_StateBit);
bool stencilChange = (fHWDrawState.getStencil() != *settings) ||

View File

@ -140,7 +140,9 @@ protected:
virtual void onGpuDrawNonIndexed(GrPrimitiveType type,
uint32_t vertexCount,
uint32_t numVertices);
virtual void flushScissor(const GrIRect* rect);
virtual void enableScissoring(const GrIRect& rect);
virtual void disableScissor();
virtual void clearStencil();
virtual void clearStencilClip(const GrIRect& rect, bool insideClip);
virtual int getMaxEdges() const;