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:
parent
a90aa53498
commit
730ebe5e00
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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.
|
||||
|
@ -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) ||
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user