Use a prioritized list of path renderers in Gr.

http://codereview.appspot.com/4867058



git-svn-id: http://skia.googlecode.com/svn/trunk@2143 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
bsalomon@google.com 2011-08-19 15:42:31 +00:00
parent b095140596
commit 3008519e9f
17 changed files with 862 additions and 695 deletions

View File

@ -16,7 +16,6 @@
// remove.
#include "GrRenderTarget.h"
class GrDefaultPathRenderer;
class GrDrawTarget;
class GrFontCache;
class GrGpu;
@ -25,6 +24,7 @@ class GrIndexBuffer;
class GrIndexBufferAllocPool;
class GrInOrderDrawBuffer;
class GrPathRenderer;
class GrPathRendererChain;
class GrResourceEntry;
class GrResourceCache;
class GrStencilBuffer;
@ -556,8 +556,7 @@ private:
GrResourceCache* fTextureCache;
GrFontCache* fFontCache;
GrPathRenderer* fCustomPathRenderer;
GrDefaultPathRenderer* fDefaultPathRenderer;
GrPathRendererChain* fPathRendererChain;
GrVertexBufferAllocPool* fDrawBufferVBAllocPool;
GrIndexBufferAllocPool* fDrawBufferIBAllocPool;
@ -592,9 +591,9 @@ private:
GrDrawTarget* prepareToDraw(const GrPaint& paint, DrawCategory drawType);
void drawClipIntoStencil();
GrPathRenderer* getPathRenderer(const GrPath&, GrPathFill);
GrPathRenderer* getPathRenderer(const GrDrawTarget* target,
const GrPath& path,
GrPathFill fill);
struct OffscreenRecord;

View File

@ -0,0 +1,15 @@
/*
* Copyright 2011 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "GrPathRenderer.h"
void GrPathRenderer::AddPathRenderers(GrContext*,
GrPathRendererChain::UsageFlags,
GrPathRendererChain*) {}

View File

@ -0,0 +1,17 @@
/*
* Copyright 2011 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "GrTesselatedPathRenderer.h"
void GrPathRenderer::AddPathRenderers(GrContext*,
GrPathRendererChain::UsageFlags flags,
GrPathRendererChain* chain) {
chain->addPathRenderer(new GrTesselatedPathRenderer())->unref();
}

View File

@ -61,11 +61,11 @@ GrContext::~GrContext() {
delete fDrawBuffer;
delete fDrawBufferVBAllocPool;
delete fDrawBufferIBAllocPool;
GrSafeUnref(fDefaultPathRenderer);
GrSafeUnref(fCustomPathRenderer);
GrSafeUnref(fAAFillRectIndexBuffer);
GrSafeUnref(fAAStrokeRectIndexBuffer);
fGpu->unref();
GrSafeUnref(fPathRendererChain);
}
void GrContext::contextLost() {
@ -78,6 +78,10 @@ void GrContext::contextDestroyed() {
// don't try to free the resources in the API.
fGpu->abandonResources();
// a path renderer may be holding onto resources that
// are now unusable
GrSafeSetNull(fPathRendererChain);
delete fDrawBuffer;
fDrawBuffer = NULL;
@ -103,6 +107,8 @@ void GrContext::freeGpuResources() {
this->flush();
fTextureCache->removeAll();
fFontCache->freeAll();
// a path renderer may be holding onto resources
GrSafeSetNull(fPathRendererChain);
}
////////////////////////////////////////////////////////////////////////////////
@ -1411,7 +1417,12 @@ void GrContext::drawPath(const GrPaint& paint, const GrPath& path,
GrPathFill fill, const GrPoint* translate) {
GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
GrPathRenderer* pr = this->getPathRenderer(path, fill);
GrPathRenderer* pr = this->getPathRenderer(target, path, fill);
if (NULL == pr) {
GrPrintf("Unable to find path renderer compatible with path.\n");
return;
}
GrPathRenderer::AutoClearPath arp(pr, target, &path, fill, translate);
GrDrawTarget::StageBitfield stageMask = paint.getActiveStageMask();
@ -1658,6 +1669,16 @@ GrDrawTarget* GrContext::prepareToDraw(const GrPaint& paint,
return target;
}
GrPathRenderer* GrContext::getPathRenderer(const GrDrawTarget* target,
const GrPath& path,
GrPathFill fill) {
if (NULL == fPathRendererChain) {
fPathRendererChain =
new GrPathRendererChain(this, GrPathRendererChain::kNone_UsageFlag);
}
return fPathRendererChain->getPathRenderer(target, path, fill);
}
////////////////////////////////////////////////////////////////////////////////
void GrContext::setRenderTarget(GrRenderTarget* target) {
@ -1712,11 +1733,7 @@ GrContext::GrContext(GrGpu* gpu) {
fGpu->ref();
fGpu->setContext(this);
fDefaultPathRenderer =
new GrDefaultPathRenderer(gpu->supportsTwoSidedStencil(),
gpu->supportsStencilWrapOps());
fCustomPathRenderer = GrPathRenderer::CreatePathRenderer();
fGpu->setClipPathRenderer(fCustomPathRenderer);
fPathRendererChain = NULL;
fTextureCache = new GrResourceCache(MAX_TEXTURE_CACHE_COUNT,
MAX_TEXTURE_CACHE_BYTES);
@ -1780,17 +1797,6 @@ const GrIndexBuffer* GrContext::getQuadIndexBuffer() const {
return fGpu->getQuadIndexBuffer();
}
GrPathRenderer* GrContext::getPathRenderer(const GrPath& path,
GrPathFill fill) {
if (NULL != fCustomPathRenderer &&
fCustomPathRenderer->canDrawPath(path, fill)) {
return fCustomPathRenderer;
} else {
GrAssert(fDefaultPathRenderer->canDrawPath(path, fill));
return fDefaultPathRenderer;
}
}
void GrContext::convolveInX(GrTexture* texture,
const SkRect& rect,
const float* kernel,

View File

@ -1,13 +0,0 @@
/*
* Copyright 2011 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "GrPathRenderer.h"
GrPathRenderer* GrPathRenderer::CreatePathRenderer() { return NULL; }

View File

@ -1,13 +0,0 @@
/*
* Copyright 2011 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "GrTesselatedPathRenderer.h"
GrPathRenderer* GrPathRenderer::CreatePathRenderer() { return new GrTesselatedPathRenderer(); }

View File

@ -0,0 +1,562 @@
/*
* Copyright 2011 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "GrDefaultPathRenderer.h"
#include "GrContext.h"
#include "GrPathUtils.h"
#include "SkTrace.h"
GrDefaultPathRenderer::GrDefaultPathRenderer(bool separateStencilSupport,
bool stencilWrapOpsSupport)
: fSeparateStencil(separateStencilSupport)
, fStencilWrapOps(stencilWrapOpsSupport)
, fSubpathCount(0)
, fSubpathVertCount(0)
, fPreviousSrcTol(-GR_Scalar1)
, fPreviousStages(-1) {
fTarget = NULL;
}
////////////////////////////////////////////////////////////////////////////////
// Stencil rules for paths
////// Even/Odd
static const GrStencilSettings gEOStencilPass = {
kInvert_StencilOp, kInvert_StencilOp,
kKeep_StencilOp, kKeep_StencilOp,
kAlwaysIfInClip_StencilFunc, kAlwaysIfInClip_StencilFunc,
0xffffffff, 0xffffffff,
0xffffffff, 0xffffffff,
0xffffffff, 0xffffffff
};
// ok not to check clip b/c stencil pass only wrote inside clip
static const GrStencilSettings gEOColorPass = {
kZero_StencilOp, kZero_StencilOp,
kZero_StencilOp, kZero_StencilOp,
kNotEqual_StencilFunc, kNotEqual_StencilFunc,
0xffffffff, 0xffffffff,
0x0, 0x0,
0xffffffff, 0xffffffff
};
// have to check clip b/c outside clip will always be zero.
static const GrStencilSettings gInvEOColorPass = {
kZero_StencilOp, kZero_StencilOp,
kZero_StencilOp, kZero_StencilOp,
kEqualIfInClip_StencilFunc, kEqualIfInClip_StencilFunc,
0xffffffff, 0xffffffff,
0x0, 0x0,
0xffffffff, 0xffffffff
};
////// Winding
// when we have separate stencil we increment front faces / decrement back faces
// when we don't have wrap incr and decr we use the stencil test to simulate
// them.
static const GrStencilSettings gWindStencilSeparateWithWrap = {
kIncWrap_StencilOp, kDecWrap_StencilOp,
kKeep_StencilOp, kKeep_StencilOp,
kAlwaysIfInClip_StencilFunc, kAlwaysIfInClip_StencilFunc,
0xffffffff, 0xffffffff,
0xffffffff, 0xffffffff,
0xffffffff, 0xffffffff
};
// if inc'ing the max value, invert to make 0
// if dec'ing zero invert to make all ones.
// we can't avoid touching the stencil on both passing and
// failing, so we can't resctrict ourselves to the clip.
static const GrStencilSettings gWindStencilSeparateNoWrap = {
kInvert_StencilOp, kInvert_StencilOp,
kIncClamp_StencilOp, kDecClamp_StencilOp,
kEqual_StencilFunc, kEqual_StencilFunc,
0xffffffff, 0xffffffff,
0xffffffff, 0x0,
0xffffffff, 0xffffffff
};
// When there are no separate faces we do two passes to setup the winding rule
// stencil. First we draw the front faces and inc, then we draw the back faces
// and dec. These are same as the above two split into the incrementing and
// decrementing passes.
static const GrStencilSettings gWindSingleStencilWithWrapInc = {
kIncWrap_StencilOp, kIncWrap_StencilOp,
kKeep_StencilOp, kKeep_StencilOp,
kAlwaysIfInClip_StencilFunc, kAlwaysIfInClip_StencilFunc,
0xffffffff, 0xffffffff,
0xffffffff, 0xffffffff,
0xffffffff, 0xffffffff
};
static const GrStencilSettings gWindSingleStencilWithWrapDec = {
kDecWrap_StencilOp, kDecWrap_StencilOp,
kKeep_StencilOp, kKeep_StencilOp,
kAlwaysIfInClip_StencilFunc, kAlwaysIfInClip_StencilFunc,
0xffffffff, 0xffffffff,
0xffffffff, 0xffffffff,
0xffffffff, 0xffffffff
};
static const GrStencilSettings gWindSingleStencilNoWrapInc = {
kInvert_StencilOp, kInvert_StencilOp,
kIncClamp_StencilOp, kIncClamp_StencilOp,
kEqual_StencilFunc, kEqual_StencilFunc,
0xffffffff, 0xffffffff,
0xffffffff, 0xffffffff,
0xffffffff, 0xffffffff
};
static const GrStencilSettings gWindSingleStencilNoWrapDec = {
kInvert_StencilOp, kInvert_StencilOp,
kDecClamp_StencilOp, kDecClamp_StencilOp,
kEqual_StencilFunc, kEqual_StencilFunc,
0xffffffff, 0xffffffff,
0x0, 0x0,
0xffffffff, 0xffffffff
};
static const GrStencilSettings gWindColorPass = {
kZero_StencilOp, kZero_StencilOp,
kZero_StencilOp, kZero_StencilOp,
kNonZeroIfInClip_StencilFunc, kNonZeroIfInClip_StencilFunc,
0xffffffff, 0xffffffff,
0x0, 0x0,
0xffffffff, 0xffffffff
};
static const GrStencilSettings gInvWindColorPass = {
kZero_StencilOp, kZero_StencilOp,
kZero_StencilOp, kZero_StencilOp,
kEqualIfInClip_StencilFunc, kEqualIfInClip_StencilFunc,
0xffffffff, 0xffffffff,
0x0, 0x0,
0xffffffff, 0xffffffff
};
////// Normal render to stencil
// Sometimes the default path renderer can draw a path directly to the stencil
// buffer without having to first resolve the interior / exterior.
static const GrStencilSettings gDirectToStencil = {
kZero_StencilOp, kZero_StencilOp,
kIncClamp_StencilOp, kIncClamp_StencilOp,
kAlwaysIfInClip_StencilFunc, kAlwaysIfInClip_StencilFunc,
0xffffffff, 0xffffffff,
0x0, 0x0,
0xffffffff, 0xffffffff
};
////////////////////////////////////////////////////////////////////////////////
// Helpers for drawPath
static GrConvexHint getConvexHint(const SkPath& path) {
return path.isConvex() ? kConvex_ConvexHint : kConcave_ConvexHint;
}
#define STENCIL_OFF 0 // Always disable stencil (even when needed)
static inline bool single_pass_path(const GrDrawTarget& target,
const GrPath& path,
GrPathFill fill) {
#if STENCIL_OFF
return true;
#else
if (kEvenOdd_PathFill == fill) {
GrConvexHint hint = getConvexHint(path);
return hint == kConvex_ConvexHint ||
hint == kNonOverlappingConvexPieces_ConvexHint;
} else if (kWinding_PathFill == fill) {
GrConvexHint hint = getConvexHint(path);
return hint == kConvex_ConvexHint ||
hint == kNonOverlappingConvexPieces_ConvexHint ||
(hint == kSameWindingConvexPieces_ConvexHint &&
target.canDisableBlend() && !target.isDitherState());
}
return false;
#endif
}
bool GrDefaultPathRenderer::requiresStencilPass(const GrDrawTarget* target,
const GrPath& path,
GrPathFill fill) const {
return !single_pass_path(*target, path, fill);
}
void GrDefaultPathRenderer::pathWillClear() {
fSubpathVertCount.realloc(0);
fTarget->resetVertexSource();
if (fUseIndexedDraw) {
fTarget->resetIndexSource();
}
fPreviousSrcTol = -GR_Scalar1;
fPreviousStages = -1;
}
static inline void append_countour_edge_indices(GrPathFill fillType,
uint16_t fanCenterIdx,
uint16_t edgeV0Idx,
uint16_t** indices) {
// when drawing lines we're appending line segments along
// the contour. When applying the other fill rules we're
// drawing triangle fans around fanCenterIdx.
if (kHairLine_PathFill != fillType) {
*((*indices)++) = fanCenterIdx;
}
*((*indices)++) = edgeV0Idx;
*((*indices)++) = edgeV0Idx + 1;
}
bool GrDefaultPathRenderer::createGeom(GrScalar srcSpaceTol,
GrDrawTarget::StageBitfield stages) {
{
SK_TRACE_EVENT0("GrDefaultPathRenderer::createGeom");
GrScalar srcSpaceTolSqd = GrMul(srcSpaceTol, srcSpaceTol);
int maxPts = GrPathUtils::worstCasePointCount(*fPath, &fSubpathCount,
srcSpaceTol);
if (maxPts <= 0) {
return false;
}
if (maxPts > ((int)SK_MaxU16 + 1)) {
GrPrintf("Path not rendered, too many verts (%d)\n", maxPts);
return false;
}
GrVertexLayout layout = 0;
for (int s = 0; s < GrDrawTarget::kNumStages; ++s) {
if ((1 << s) & stages) {
layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(s);
}
}
fUseIndexedDraw = fSubpathCount > 1;
int maxIdxs = 0;
if (kHairLine_PathFill == fFill) {
if (fUseIndexedDraw) {
maxIdxs = 2 * maxPts;
fPrimitiveType = kLines_PrimitiveType;
} else {
fPrimitiveType = kLineStrip_PrimitiveType;
}
} else {
if (fUseIndexedDraw) {
maxIdxs = 3 * maxPts;
fPrimitiveType = kTriangles_PrimitiveType;
} else {
fPrimitiveType = kTriangleFan_PrimitiveType;
}
}
GrPoint* base;
if (!fTarget->reserveVertexSpace(layout, maxPts, (void**)&base)) {
return false;
}
GrAssert(NULL != base);
GrPoint* vert = base;
uint16_t* idxBase = NULL;
uint16_t* idx = NULL;
uint16_t subpathIdxStart = 0;
if (fUseIndexedDraw) {
if (!fTarget->reserveIndexSpace(maxIdxs, (void**)&idxBase)) {
fTarget->resetVertexSource();
return false;
}
GrAssert(NULL != idxBase);
idx = idxBase;
}
fSubpathVertCount.realloc(fSubpathCount);
GrPoint pts[4];
bool first = true;
int subpath = 0;
SkPath::Iter iter(*fPath, false);
for (;;) {
GrPathCmd cmd = (GrPathCmd)iter.next(pts);
switch (cmd) {
case kMove_PathCmd:
if (!first) {
uint16_t currIdx = (uint16_t) (vert - base);
fSubpathVertCount[subpath] = currIdx - subpathIdxStart;
subpathIdxStart = currIdx;
++subpath;
}
*vert = pts[0];
vert++;
break;
case kLine_PathCmd:
if (fUseIndexedDraw) {
uint16_t prevIdx = (uint16_t)(vert - base) - 1;
append_countour_edge_indices(fFill, subpathIdxStart,
prevIdx, &idx);
}
*(vert++) = pts[1];
break;
case kQuadratic_PathCmd: {
// first pt of quad is the pt we ended on in previous step
uint16_t firstQPtIdx = (uint16_t)(vert - base) - 1;
uint16_t numPts = (uint16_t)
GrPathUtils::generateQuadraticPoints(
pts[0], pts[1], pts[2],
srcSpaceTolSqd, &vert,
GrPathUtils::quadraticPointCount(pts, srcSpaceTol));
if (fUseIndexedDraw) {
for (uint16_t i = 0; i < numPts; ++i) {
append_countour_edge_indices(fFill, subpathIdxStart,
firstQPtIdx + i, &idx);
}
}
break;
}
case kCubic_PathCmd: {
// first pt of cubic is the pt we ended on in previous step
uint16_t firstCPtIdx = (uint16_t)(vert - base) - 1;
uint16_t numPts = (uint16_t) GrPathUtils::generateCubicPoints(
pts[0], pts[1], pts[2], pts[3],
srcSpaceTolSqd, &vert,
GrPathUtils::cubicPointCount(pts, srcSpaceTol));
if (fUseIndexedDraw) {
for (uint16_t i = 0; i < numPts; ++i) {
append_countour_edge_indices(fFill, subpathIdxStart,
firstCPtIdx + i, &idx);
}
}
break;
}
case kClose_PathCmd:
break;
case kEnd_PathCmd:
uint16_t currIdx = (uint16_t) (vert - base);
fSubpathVertCount[subpath] = currIdx - subpathIdxStart;
goto FINISHED;
}
first = false;
}
FINISHED:
GrAssert((vert - base) <= maxPts);
GrAssert((idx - idxBase) <= maxIdxs);
fVertexCnt = vert - base;
fIndexCnt = idx - idxBase;
if (fTranslate.fX || fTranslate.fY) {
int count = vert - base;
for (int i = 0; i < count; i++) {
base[i].offset(fTranslate.fX, fTranslate.fY);
}
}
}
// set these at the end so if we failed on first drawPath inside a
// setPath/clearPath block we won't assume geom was created on a subsequent
// drawPath in the same block.
fPreviousSrcTol = srcSpaceTol;
fPreviousStages = stages;
return true;
}
void GrDefaultPathRenderer::onDrawPath(GrDrawTarget::StageBitfield stages,
bool stencilOnly) {
SK_TRACE_EVENT1("GrDefaultPathRenderer::onDrawPath",
"points", SkStringPrintf("%i", path.countPoints()).c_str());
GrMatrix viewM = fTarget->getViewMatrix();
// In order to tesselate the path we get a bound on how much the matrix can
// stretch when mapping to screen coordinates.
GrScalar stretch = viewM.getMaxStretch();
bool useStretch = stretch > 0;
GrScalar tol = fCurveTolerance;
if (!useStretch) {
// TODO: deal with perspective in some better way.
tol /= 10;
} else {
tol = GrScalarDiv(tol, stretch);
}
// FIXME: It's really dumb that we recreate the verts for a new vertex
// layout. We only do that because the GrDrawTarget API doesn't allow
// us to change the vertex layout after reserveVertexSpace(). We won't
// actually change the vertex data when the layout changes since all the
// stages reference the positions (rather than having separate tex coords)
// and we don't ever have per-vert colors. In practice our call sites
// won't change the stages in use inside a setPath / removePath pair. But
// it is a silly limitation of the GrDrawTarget design that should be fixed.
if (tol != fPreviousSrcTol ||
stages != fPreviousStages) {
if (!this->createGeom(tol, stages)) {
return;
}
}
GrAssert(NULL != fTarget);
GrDrawTarget::AutoStateRestore asr(fTarget);
bool colorWritesWereDisabled = fTarget->isColorWriteDisabled();
// face culling doesn't make sense here
GrAssert(GrDrawTarget::kBoth_DrawFace == fTarget->getDrawFace());
int passCount = 0;
const GrStencilSettings* passes[3];
GrDrawTarget::DrawFace drawFace[3];
bool reverse = false;
bool lastPassIsBounds;
if (kHairLine_PathFill == fFill) {
passCount = 1;
if (stencilOnly) {
passes[0] = &gDirectToStencil;
} else {
passes[0] = NULL;
}
lastPassIsBounds = false;
drawFace[0] = GrDrawTarget::kBoth_DrawFace;
} else {
if (single_pass_path(*fTarget, *fPath, fFill)) {
passCount = 1;
if (stencilOnly) {
passes[0] = &gDirectToStencil;
} else {
passes[0] = NULL;
}
drawFace[0] = GrDrawTarget::kBoth_DrawFace;
lastPassIsBounds = false;
} else {
switch (fFill) {
case kInverseEvenOdd_PathFill:
reverse = true;
// fallthrough
case kEvenOdd_PathFill:
passes[0] = &gEOStencilPass;
if (stencilOnly) {
passCount = 1;
lastPassIsBounds = false;
} else {
passCount = 2;
lastPassIsBounds = true;
if (reverse) {
passes[1] = &gInvEOColorPass;
} else {
passes[1] = &gEOColorPass;
}
}
drawFace[0] = drawFace[1] = GrDrawTarget::kBoth_DrawFace;
break;
case kInverseWinding_PathFill:
reverse = true;
// fallthrough
case kWinding_PathFill:
if (fSeparateStencil) {
if (fStencilWrapOps) {
passes[0] = &gWindStencilSeparateWithWrap;
} else {
passes[0] = &gWindStencilSeparateNoWrap;
}
passCount = 2;
drawFace[0] = GrDrawTarget::kBoth_DrawFace;
} else {
if (fStencilWrapOps) {
passes[0] = &gWindSingleStencilWithWrapInc;
passes[1] = &gWindSingleStencilWithWrapDec;
} else {
passes[0] = &gWindSingleStencilNoWrapInc;
passes[1] = &gWindSingleStencilNoWrapDec;
}
// which is cw and which is ccw is arbitrary.
drawFace[0] = GrDrawTarget::kCW_DrawFace;
drawFace[1] = GrDrawTarget::kCCW_DrawFace;
passCount = 3;
}
if (stencilOnly) {
lastPassIsBounds = false;
--passCount;
} else {
lastPassIsBounds = true;
drawFace[passCount-1] = GrDrawTarget::kBoth_DrawFace;
if (reverse) {
passes[passCount-1] = &gInvWindColorPass;
} else {
passes[passCount-1] = &gWindColorPass;
}
}
break;
default:
GrAssert(!"Unknown path fFill!");
return;
}
}
}
{
SK_TRACE_EVENT1("GrDefaultPathRenderer::onDrawPath::renderPasses",
"verts", SkStringPrintf("%i", vert - base).c_str());
for (int p = 0; p < passCount; ++p) {
fTarget->setDrawFace(drawFace[p]);
if (NULL != passes[p]) {
fTarget->setStencil(*passes[p]);
}
if (lastPassIsBounds && (p == passCount-1)) {
if (!colorWritesWereDisabled) {
fTarget->disableState(GrDrawTarget::kNoColorWrites_StateBit);
}
GrRect bounds;
if (reverse) {
GrAssert(NULL != fTarget->getRenderTarget());
// draw over the whole world.
bounds.setLTRB(0, 0,
GrIntToScalar(fTarget->getRenderTarget()->width()),
GrIntToScalar(fTarget->getRenderTarget()->height()));
GrMatrix vmi;
if (fTarget->getViewInverse(&vmi)) {
vmi.mapRect(&bounds);
}
} else {
bounds = fPath->getBounds();
bounds.offset(fTranslate);
}
GrDrawTarget::AutoGeometryPush agp(fTarget);
fTarget->drawSimpleRect(bounds, NULL, stages);
} else {
if (passCount > 1) {
fTarget->enableState(GrDrawTarget::kNoColorWrites_StateBit);
}
if (fUseIndexedDraw) {
fTarget->drawIndexed(fPrimitiveType, 0, 0,
fVertexCnt, fIndexCnt);
} else {
int baseVertex = 0;
for (int sp = 0; sp < fSubpathCount; ++sp) {
fTarget->drawNonIndexed(fPrimitiveType, baseVertex,
fSubpathVertCount[sp]);
baseVertex += fSubpathVertCount[sp];
}
}
}
}
}
}
void GrDefaultPathRenderer::drawPath(GrDrawTarget::StageBitfield stages) {
this->onDrawPath(stages, false);
}
void GrDefaultPathRenderer::drawPathToStencil() {
GrAssert(kInverseEvenOdd_PathFill != fFill);
GrAssert(kInverseWinding_PathFill != fFill);
this->onDrawPath(0, true);
}

View File

@ -0,0 +1,58 @@
/*
* Copyright 2011 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef GrDefaultPathRenderer_DEFINED
#define GrDefaultPathRenderer_DEFINED
#include "GrPathRenderer.h"
#include "SkTemplates.h"
/**
* Subclass that renders the path using the stencil buffer to resolve fill
* rules (e.g. winding, even-odd)
*/
class GR_API GrDefaultPathRenderer : public GrPathRenderer {
public:
GrDefaultPathRenderer(bool separateStencilSupport,
bool stencilWrapOpsSupport);
virtual bool canDrawPath(const SkPath& path,
GrPathFill fill) const { return true; }
virtual bool requiresStencilPass(const GrDrawTarget* target,
const SkPath& path,
GrPathFill fill) const;
virtual void drawPath(GrDrawTarget::StageBitfield stages);
virtual void drawPathToStencil();
protected:
virtual void pathWillClear();
private:
void onDrawPath(GrDrawTarget::StageBitfield stages, bool stencilOnly);
bool createGeom(GrScalar srcSpaceTol,
GrDrawTarget::StageBitfield stages);
bool fSeparateStencil;
bool fStencilWrapOps;
int fSubpathCount;
SkAutoSTMalloc<8, uint16_t> fSubpathVertCount;
int fIndexCnt;
int fVertexCnt;
GrScalar fPreviousSrcTol;
GrDrawTarget::StageBitfield fPreviousStages;
GrPrimitiveType fPrimitiveType;
bool fUseIndexedDraw;
typedef GrPathRenderer INHERITED;
};
#endif

View File

@ -40,8 +40,7 @@ GrGpu::GrGpu()
, fGeomPoolStateStack(&fGeoSrcStateStackStorage)
, fQuadIndexBuffer(NULL)
, fUnitSquareVertexBuffer(NULL)
, fDefaultPathRenderer(NULL)
, fClientPathRenderer(NULL)
, fPathRendererChain(NULL)
, fContextIsDirty(true)
, fResourceHead(NULL) {
@ -62,8 +61,6 @@ GrGpu::GrGpu()
GrGpu::~GrGpu() {
this->releaseResources();
GrSafeUnref(fDefaultPathRenderer);
GrSafeUnref(fClientPathRenderer);
}
void GrGpu::abandonResources() {
@ -81,6 +78,8 @@ void GrGpu::abandonResources() {
fVertexPool = NULL;
delete fIndexPool;
fIndexPool = NULL;
// in case path renderer has any GrResources, start from scratch
GrSafeSetNull(fPathRendererChain);
}
void GrGpu::releaseResources() {
@ -98,6 +97,8 @@ void GrGpu::releaseResources() {
fVertexPool = NULL;
delete fIndexPool;
fIndexPool = NULL;
// in case path renderer has any GrResources, start from scratch
GrSafeSetNull(fPathRendererChain);
}
void GrGpu::insertResource(GrResource* resource) {
@ -521,6 +522,11 @@ bool GrGpu::setupClipAndFlushState(GrPrimitiveType type) {
fill = NonInvertedFill(fill);
clipPath = &clip.getPath(c);
pr = this->getClipPathRenderer(*clipPath, fill);
if (NULL == pr) {
fClipInStencil = false;
fClip = clip;
return false;
}
canRenderDirectToStencil =
!pr->requiresStencilPass(this, *clipPath, fill);
arp.set(pr, this, clipPath, fill, NULL);
@ -602,18 +608,12 @@ bool GrGpu::setupClipAndFlushState(GrPrimitiveType type) {
GrPathRenderer* GrGpu::getClipPathRenderer(const GrPath& path,
GrPathFill fill) {
if (NULL != fClientPathRenderer &&
fClientPathRenderer->canDrawPath(path, fill)) {
return fClientPathRenderer;
} else {
if (NULL == fDefaultPathRenderer) {
fDefaultPathRenderer =
new GrDefaultPathRenderer(this->supportsTwoSidedStencil(),
this->supportsStencilWrapOps());
}
GrAssert(fDefaultPathRenderer->canDrawPath(path, fill));
return fDefaultPathRenderer;
if (NULL == fPathRendererChain) {
fPathRendererChain =
new GrPathRendererChain(this->getContext(),
GrPathRendererChain::kNonAAOnly_UsageFlag);
}
return fPathRendererChain->getPathRenderer(this, path, fill);
}

View File

@ -11,13 +11,14 @@
#define GrGpu_DEFINED
#include "GrDrawTarget.h"
#include "GrPathRenderer.h"
#include "GrRect.h"
#include "GrRefCnt.h"
#include "GrTexture.h"
class GrContext;
class GrIndexBufferAllocPool;
class GrPathRenderer;
class GrPathRendererChain;
class GrResource;
class GrStencilBuffer;
class GrVertexBufferAllocPool;
@ -258,14 +259,6 @@ public:
virtual void clear(const GrIRect* rect, GrColor color);
/**
* Installs a path renderer that will be used to draw paths that are
* part of the clip.
*/
void setClipPathRenderer(GrPathRenderer* pathRenderer) {
GrSafeAssign(fClientPathRenderer, pathRenderer);
}
/**
* Returns an index buffer that can be used to render quads.
* Six indices per quad: 0, 1, 2, 0, 2, 3, etc.
@ -520,8 +513,9 @@ private:
mutable GrVertexBuffer* fUnitSquareVertexBuffer; // mutable so it can be
// created on-demand
GrDefaultPathRenderer* fDefaultPathRenderer;
GrPathRenderer* fClientPathRenderer;
// 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;

View File

@ -5,24 +5,15 @@
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "GrPathRenderer.h"
#include "GrPoint.h"
#include "GrDrawTarget.h"
#include "GrPathUtils.h"
#include "GrTexture.h"
#include "SkString.h"
#include "SkTemplates.h"
#include "SkTrace.h"
GrPathRenderer::GrPathRenderer()
: fCurveTolerance (GR_Scalar1)
, fPath(NULL)
, fTarget(NULL) {
}
void GrPathRenderer::setPath(GrDrawTarget* target,
const SkPath* path,
GrPathFill fill,
@ -49,553 +40,3 @@ void GrPathRenderer::clearPath() {
fTarget = NULL;
fPath = NULL;
}
////////////////////////////////////////////////////////////////////////////////
GrDefaultPathRenderer::GrDefaultPathRenderer(bool separateStencilSupport,
bool stencilWrapOpsSupport)
: fSeparateStencil(separateStencilSupport)
, fStencilWrapOps(stencilWrapOpsSupport)
, fSubpathCount(0)
, fSubpathVertCount(0)
, fPreviousSrcTol(-GR_Scalar1)
, fPreviousStages(-1) {
fTarget = NULL;
}
////////////////////////////////////////////////////////////////////////////////
// Stencil rules for paths
////// Even/Odd
static const GrStencilSettings gEOStencilPass = {
kInvert_StencilOp, kInvert_StencilOp,
kKeep_StencilOp, kKeep_StencilOp,
kAlwaysIfInClip_StencilFunc, kAlwaysIfInClip_StencilFunc,
0xffffffff, 0xffffffff,
0xffffffff, 0xffffffff,
0xffffffff, 0xffffffff
};
// ok not to check clip b/c stencil pass only wrote inside clip
static const GrStencilSettings gEOColorPass = {
kZero_StencilOp, kZero_StencilOp,
kZero_StencilOp, kZero_StencilOp,
kNotEqual_StencilFunc, kNotEqual_StencilFunc,
0xffffffff, 0xffffffff,
0x0, 0x0,
0xffffffff, 0xffffffff
};
// have to check clip b/c outside clip will always be zero.
static const GrStencilSettings gInvEOColorPass = {
kZero_StencilOp, kZero_StencilOp,
kZero_StencilOp, kZero_StencilOp,
kEqualIfInClip_StencilFunc, kEqualIfInClip_StencilFunc,
0xffffffff, 0xffffffff,
0x0, 0x0,
0xffffffff, 0xffffffff
};
////// Winding
// when we have separate stencil we increment front faces / decrement back faces
// when we don't have wrap incr and decr we use the stencil test to simulate
// them.
static const GrStencilSettings gWindStencilSeparateWithWrap = {
kIncWrap_StencilOp, kDecWrap_StencilOp,
kKeep_StencilOp, kKeep_StencilOp,
kAlwaysIfInClip_StencilFunc, kAlwaysIfInClip_StencilFunc,
0xffffffff, 0xffffffff,
0xffffffff, 0xffffffff,
0xffffffff, 0xffffffff
};
// if inc'ing the max value, invert to make 0
// if dec'ing zero invert to make all ones.
// we can't avoid touching the stencil on both passing and
// failing, so we can't resctrict ourselves to the clip.
static const GrStencilSettings gWindStencilSeparateNoWrap = {
kInvert_StencilOp, kInvert_StencilOp,
kIncClamp_StencilOp, kDecClamp_StencilOp,
kEqual_StencilFunc, kEqual_StencilFunc,
0xffffffff, 0xffffffff,
0xffffffff, 0x0,
0xffffffff, 0xffffffff
};
// When there are no separate faces we do two passes to setup the winding rule
// stencil. First we draw the front faces and inc, then we draw the back faces
// and dec. These are same as the above two split into the incrementing and
// decrementing passes.
static const GrStencilSettings gWindSingleStencilWithWrapInc = {
kIncWrap_StencilOp, kIncWrap_StencilOp,
kKeep_StencilOp, kKeep_StencilOp,
kAlwaysIfInClip_StencilFunc, kAlwaysIfInClip_StencilFunc,
0xffffffff, 0xffffffff,
0xffffffff, 0xffffffff,
0xffffffff, 0xffffffff
};
static const GrStencilSettings gWindSingleStencilWithWrapDec = {
kDecWrap_StencilOp, kDecWrap_StencilOp,
kKeep_StencilOp, kKeep_StencilOp,
kAlwaysIfInClip_StencilFunc, kAlwaysIfInClip_StencilFunc,
0xffffffff, 0xffffffff,
0xffffffff, 0xffffffff,
0xffffffff, 0xffffffff
};
static const GrStencilSettings gWindSingleStencilNoWrapInc = {
kInvert_StencilOp, kInvert_StencilOp,
kIncClamp_StencilOp, kIncClamp_StencilOp,
kEqual_StencilFunc, kEqual_StencilFunc,
0xffffffff, 0xffffffff,
0xffffffff, 0xffffffff,
0xffffffff, 0xffffffff
};
static const GrStencilSettings gWindSingleStencilNoWrapDec = {
kInvert_StencilOp, kInvert_StencilOp,
kDecClamp_StencilOp, kDecClamp_StencilOp,
kEqual_StencilFunc, kEqual_StencilFunc,
0xffffffff, 0xffffffff,
0x0, 0x0,
0xffffffff, 0xffffffff
};
static const GrStencilSettings gWindColorPass = {
kZero_StencilOp, kZero_StencilOp,
kZero_StencilOp, kZero_StencilOp,
kNonZeroIfInClip_StencilFunc, kNonZeroIfInClip_StencilFunc,
0xffffffff, 0xffffffff,
0x0, 0x0,
0xffffffff, 0xffffffff
};
static const GrStencilSettings gInvWindColorPass = {
kZero_StencilOp, kZero_StencilOp,
kZero_StencilOp, kZero_StencilOp,
kEqualIfInClip_StencilFunc, kEqualIfInClip_StencilFunc,
0xffffffff, 0xffffffff,
0x0, 0x0,
0xffffffff, 0xffffffff
};
////// Normal render to stencil
// Sometimes the default path renderer can draw a path directly to the stencil
// buffer without having to first resolve the interior / exterior.
static const GrStencilSettings gDirectToStencil = {
kZero_StencilOp, kZero_StencilOp,
kIncClamp_StencilOp, kIncClamp_StencilOp,
kAlwaysIfInClip_StencilFunc, kAlwaysIfInClip_StencilFunc,
0xffffffff, 0xffffffff,
0x0, 0x0,
0xffffffff, 0xffffffff
};
////////////////////////////////////////////////////////////////////////////////
// Helpers for drawPath
static GrConvexHint getConvexHint(const SkPath& path) {
return path.isConvex() ? kConvex_ConvexHint : kConcave_ConvexHint;
}
#define STENCIL_OFF 0 // Always disable stencil (even when needed)
static inline bool single_pass_path(const GrDrawTarget& target,
const GrPath& path,
GrPathFill fill) {
#if STENCIL_OFF
return true;
#else
if (kEvenOdd_PathFill == fill) {
GrConvexHint hint = getConvexHint(path);
return hint == kConvex_ConvexHint ||
hint == kNonOverlappingConvexPieces_ConvexHint;
} else if (kWinding_PathFill == fill) {
GrConvexHint hint = getConvexHint(path);
return hint == kConvex_ConvexHint ||
hint == kNonOverlappingConvexPieces_ConvexHint ||
(hint == kSameWindingConvexPieces_ConvexHint &&
target.canDisableBlend() && !target.isDitherState());
}
return false;
#endif
}
bool GrDefaultPathRenderer::requiresStencilPass(const GrDrawTarget* target,
const GrPath& path,
GrPathFill fill) const {
return !single_pass_path(*target, path, fill);
}
void GrDefaultPathRenderer::pathWillClear() {
fSubpathVertCount.realloc(0);
fTarget->resetVertexSource();
if (fUseIndexedDraw) {
fTarget->resetIndexSource();
}
fPreviousSrcTol = -GR_Scalar1;
fPreviousStages = -1;
}
static inline void append_countour_edge_indices(GrPathFill fillType,
uint16_t fanCenterIdx,
uint16_t edgeV0Idx,
uint16_t** indices) {
// when drawing lines we're appending line segments along
// the contour. When applying the other fill rules we're
// drawing triangle fans around fanCenterIdx.
if (kHairLine_PathFill != fillType) {
*((*indices)++) = fanCenterIdx;
}
*((*indices)++) = edgeV0Idx;
*((*indices)++) = edgeV0Idx + 1;
}
bool GrDefaultPathRenderer::createGeom(GrScalar srcSpaceTol,
GrDrawTarget::StageBitfield stages) {
{
SK_TRACE_EVENT0("GrDefaultPathRenderer::createGeom");
GrScalar srcSpaceTolSqd = GrMul(srcSpaceTol, srcSpaceTol);
int maxPts = GrPathUtils::worstCasePointCount(*fPath, &fSubpathCount,
srcSpaceTol);
if (maxPts <= 0) {
return false;
}
if (maxPts > ((int)SK_MaxU16 + 1)) {
GrPrintf("Path not rendered, too many verts (%d)\n", maxPts);
return false;
}
GrVertexLayout layout = 0;
for (int s = 0; s < GrDrawTarget::kNumStages; ++s) {
if ((1 << s) & stages) {
layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(s);
}
}
fUseIndexedDraw = fSubpathCount > 1;
int maxIdxs = 0;
if (kHairLine_PathFill == fFill) {
if (fUseIndexedDraw) {
maxIdxs = 2 * maxPts;
fPrimitiveType = kLines_PrimitiveType;
} else {
fPrimitiveType = kLineStrip_PrimitiveType;
}
} else {
if (fUseIndexedDraw) {
maxIdxs = 3 * maxPts;
fPrimitiveType = kTriangles_PrimitiveType;
} else {
fPrimitiveType = kTriangleFan_PrimitiveType;
}
}
GrPoint* base;
if (!fTarget->reserveVertexSpace(layout, maxPts, (void**)&base)) {
return false;
}
GrAssert(NULL != base);
GrPoint* vert = base;
uint16_t* idxBase = NULL;
uint16_t* idx = NULL;
uint16_t subpathIdxStart = 0;
if (fUseIndexedDraw) {
if (!fTarget->reserveIndexSpace(maxIdxs, (void**)&idxBase)) {
fTarget->resetVertexSource();
return false;
}
GrAssert(NULL != idxBase);
idx = idxBase;
}
fSubpathVertCount.realloc(fSubpathCount);
GrPoint pts[4];
bool first = true;
int subpath = 0;
SkPath::Iter iter(*fPath, false);
for (;;) {
GrPathCmd cmd = (GrPathCmd)iter.next(pts);
switch (cmd) {
case kMove_PathCmd:
if (!first) {
uint16_t currIdx = (uint16_t) (vert - base);
fSubpathVertCount[subpath] = currIdx - subpathIdxStart;
subpathIdxStart = currIdx;
++subpath;
}
*vert = pts[0];
vert++;
break;
case kLine_PathCmd:
if (fUseIndexedDraw) {
uint16_t prevIdx = (uint16_t)(vert - base) - 1;
append_countour_edge_indices(fFill, subpathIdxStart,
prevIdx, &idx);
}
*(vert++) = pts[1];
break;
case kQuadratic_PathCmd: {
// first pt of quad is the pt we ended on in previous step
uint16_t firstQPtIdx = (uint16_t)(vert - base) - 1;
uint16_t numPts = (uint16_t)
GrPathUtils::generateQuadraticPoints(
pts[0], pts[1], pts[2],
srcSpaceTolSqd, &vert,
GrPathUtils::quadraticPointCount(pts, srcSpaceTol));
if (fUseIndexedDraw) {
for (uint16_t i = 0; i < numPts; ++i) {
append_countour_edge_indices(fFill, subpathIdxStart,
firstQPtIdx + i, &idx);
}
}
break;
}
case kCubic_PathCmd: {
// first pt of cubic is the pt we ended on in previous step
uint16_t firstCPtIdx = (uint16_t)(vert - base) - 1;
uint16_t numPts = (uint16_t) GrPathUtils::generateCubicPoints(
pts[0], pts[1], pts[2], pts[3],
srcSpaceTolSqd, &vert,
GrPathUtils::cubicPointCount(pts, srcSpaceTol));
if (fUseIndexedDraw) {
for (uint16_t i = 0; i < numPts; ++i) {
append_countour_edge_indices(fFill, subpathIdxStart,
firstCPtIdx + i, &idx);
}
}
break;
}
case kClose_PathCmd:
break;
case kEnd_PathCmd:
uint16_t currIdx = (uint16_t) (vert - base);
fSubpathVertCount[subpath] = currIdx - subpathIdxStart;
goto FINISHED;
}
first = false;
}
FINISHED:
GrAssert((vert - base) <= maxPts);
GrAssert((idx - idxBase) <= maxIdxs);
fVertexCnt = vert - base;
fIndexCnt = idx - idxBase;
if (fTranslate.fX || fTranslate.fY) {
int count = vert - base;
for (int i = 0; i < count; i++) {
base[i].offset(fTranslate.fX, fTranslate.fY);
}
}
}
// set these at the end so if we failed on first drawPath inside a
// setPath/clearPath block we won't assume geom was created on a subsequent
// drawPath in the same block.
fPreviousSrcTol = srcSpaceTol;
fPreviousStages = stages;
return true;
}
void GrDefaultPathRenderer::onDrawPath(GrDrawTarget::StageBitfield stages,
bool stencilOnly) {
SK_TRACE_EVENT1("GrDefaultPathRenderer::onDrawPath",
"points", SkStringPrintf("%i", path.countPoints()).c_str());
GrMatrix viewM = fTarget->getViewMatrix();
// In order to tesselate the path we get a bound on how much the matrix can
// stretch when mapping to screen coordinates.
GrScalar stretch = viewM.getMaxStretch();
bool useStretch = stretch > 0;
GrScalar tol = fCurveTolerance;
if (!useStretch) {
// TODO: deal with perspective in some better way.
tol /= 10;
} else {
tol = GrScalarDiv(tol, stretch);
}
// FIXME: It's really dumb that we recreate the verts for a new vertex
// layout. We only do that because the GrDrawTarget API doesn't allow
// us to change the vertex layout after reserveVertexSpace(). We won't
// actually change the vertex data when the layout changes since all the
// stages reference the positions (rather than having separate tex coords)
// and we don't ever have per-vert colors. In practice our call sites
// won't change the stages in use inside a setPath / removePath pair. But
// it is a silly limitation of the GrDrawTarget design that should be fixed.
if (tol != fPreviousSrcTol ||
stages != fPreviousStages) {
if (!this->createGeom(tol, stages)) {
return;
}
}
GrAssert(NULL != fTarget);
GrDrawTarget::AutoStateRestore asr(fTarget);
bool colorWritesWereDisabled = fTarget->isColorWriteDisabled();
// face culling doesn't make sense here
GrAssert(GrDrawTarget::kBoth_DrawFace == fTarget->getDrawFace());
int passCount = 0;
const GrStencilSettings* passes[3];
GrDrawTarget::DrawFace drawFace[3];
bool reverse = false;
bool lastPassIsBounds;
if (kHairLine_PathFill == fFill) {
passCount = 1;
if (stencilOnly) {
passes[0] = &gDirectToStencil;
} else {
passes[0] = NULL;
}
lastPassIsBounds = false;
drawFace[0] = GrDrawTarget::kBoth_DrawFace;
} else {
if (single_pass_path(*fTarget, *fPath, fFill)) {
passCount = 1;
if (stencilOnly) {
passes[0] = &gDirectToStencil;
} else {
passes[0] = NULL;
}
drawFace[0] = GrDrawTarget::kBoth_DrawFace;
lastPassIsBounds = false;
} else {
switch (fFill) {
case kInverseEvenOdd_PathFill:
reverse = true;
// fallthrough
case kEvenOdd_PathFill:
passes[0] = &gEOStencilPass;
if (stencilOnly) {
passCount = 1;
lastPassIsBounds = false;
} else {
passCount = 2;
lastPassIsBounds = true;
if (reverse) {
passes[1] = &gInvEOColorPass;
} else {
passes[1] = &gEOColorPass;
}
}
drawFace[0] = drawFace[1] = GrDrawTarget::kBoth_DrawFace;
break;
case kInverseWinding_PathFill:
reverse = true;
// fallthrough
case kWinding_PathFill:
if (fSeparateStencil) {
if (fStencilWrapOps) {
passes[0] = &gWindStencilSeparateWithWrap;
} else {
passes[0] = &gWindStencilSeparateNoWrap;
}
passCount = 2;
drawFace[0] = GrDrawTarget::kBoth_DrawFace;
} else {
if (fStencilWrapOps) {
passes[0] = &gWindSingleStencilWithWrapInc;
passes[1] = &gWindSingleStencilWithWrapDec;
} else {
passes[0] = &gWindSingleStencilNoWrapInc;
passes[1] = &gWindSingleStencilNoWrapDec;
}
// which is cw and which is ccw is arbitrary.
drawFace[0] = GrDrawTarget::kCW_DrawFace;
drawFace[1] = GrDrawTarget::kCCW_DrawFace;
passCount = 3;
}
if (stencilOnly) {
lastPassIsBounds = false;
--passCount;
} else {
lastPassIsBounds = true;
drawFace[passCount-1] = GrDrawTarget::kBoth_DrawFace;
if (reverse) {
passes[passCount-1] = &gInvWindColorPass;
} else {
passes[passCount-1] = &gWindColorPass;
}
}
break;
default:
GrAssert(!"Unknown path fFill!");
return;
}
}
}
{
SK_TRACE_EVENT1("GrDefaultPathRenderer::onDrawPath::renderPasses",
"verts", SkStringPrintf("%i", vert - base).c_str());
for (int p = 0; p < passCount; ++p) {
fTarget->setDrawFace(drawFace[p]);
if (NULL != passes[p]) {
fTarget->setStencil(*passes[p]);
}
if (lastPassIsBounds && (p == passCount-1)) {
if (!colorWritesWereDisabled) {
fTarget->disableState(GrDrawTarget::kNoColorWrites_StateBit);
}
GrRect bounds;
if (reverse) {
GrAssert(NULL != fTarget->getRenderTarget());
// draw over the whole world.
bounds.setLTRB(0, 0,
GrIntToScalar(fTarget->getRenderTarget()->width()),
GrIntToScalar(fTarget->getRenderTarget()->height()));
GrMatrix vmi;
if (fTarget->getViewInverse(&vmi)) {
vmi.mapRect(&bounds);
}
} else {
bounds = fPath->getBounds();
bounds.offset(fTranslate);
}
GrDrawTarget::AutoGeometryPush agp(fTarget);
fTarget->drawSimpleRect(bounds, NULL, stages);
} else {
if (passCount > 1) {
fTarget->enableState(GrDrawTarget::kNoColorWrites_StateBit);
}
if (fUseIndexedDraw) {
fTarget->drawIndexed(fPrimitiveType, 0, 0,
fVertexCnt, fIndexCnt);
} else {
int baseVertex = 0;
for (int sp = 0; sp < fSubpathCount; ++sp) {
fTarget->drawNonIndexed(fPrimitiveType, baseVertex,
fSubpathVertCount[sp]);
baseVertex += fSubpathVertCount[sp];
}
}
}
}
}
}
void GrDefaultPathRenderer::drawPath(GrDrawTarget::StageBitfield stages) {
this->onDrawPath(stages, false);
}
void GrDefaultPathRenderer::drawPathToStencil() {
GrAssert(kInverseEvenOdd_PathFill != fFill);
GrAssert(kInverseWinding_PathFill != fFill);
this->onDrawPath(0, true);
}

View File

@ -11,9 +11,11 @@
#define GrPathRenderer_DEFINED
#include "GrDrawTarget.h"
#include "SkTemplates.h"
#include "GrTArray.h"
#include "GrPathRendererChain.h"
class SkPath;
struct GrPoint;
/**
@ -29,6 +31,23 @@ struct GrPoint;
*/
class GR_API GrPathRenderer : public GrRefCnt {
public:
/**
* This is called to install custom path renderers in every GrContext at
* create time. The default implementation in GrCreatePathRenderer_none.cpp
* does not add any additional renderers. Link against another
* implementation to install your own. The most recently added is the
* most preferred path renderer.
*
* @param context the context that will use the path renderer
* @param flags flags indicating how path renderers will be used
* @param prChain the chain to add path renderers to.
*/
static void AddPathRenderers(GrContext* context,
GrPathRendererChain::UsageFlags flags,
GrPathRendererChain* prChain);
GrPathRenderer(void);
/**
* Returns true if this path renderer is able to render the path.
@ -71,7 +90,7 @@ public:
* having FSAA enabled for a render target). Target is provided to
* communicate the draw state (blend mode, stage settings, etc).
*/
virtual bool supportsAA(GrDrawTarget* target,
virtual bool supportsAA(const GrDrawTarget* target,
const SkPath& path,
GrPathFill fill) { return false; }
@ -135,13 +154,6 @@ public:
GrCrash("Unexpected call to drawPathToStencil.");
}
/**
* This is called to install a custom path renderer in every GrContext at
* create time. The default implementation in GrCreatePathRenderer_none.cpp
* returns NULL. Link against another implementation to install your own.
*/
static GrPathRenderer* CreatePathRenderer();
/**
* Multiply curve tolerance by the given value, increasing or decreasing
* the maximum error permitted in tesselating curves with short straight
@ -208,49 +220,5 @@ private:
typedef GrRefCnt INHERITED;
};
/**
* Subclass that renders the path using the stencil buffer to resolve fill
* rules (e.g. winding, even-odd)
*/
class GR_API GrDefaultPathRenderer : public GrPathRenderer {
public:
GrDefaultPathRenderer(bool separateStencilSupport,
bool stencilWrapOpsSupport);
virtual bool canDrawPath(const SkPath& path,
GrPathFill fill) const { return true; }
virtual bool requiresStencilPass(const GrDrawTarget* target,
const SkPath& path,
GrPathFill fill) const;
virtual void drawPath(GrDrawTarget::StageBitfield stages);
virtual void drawPathToStencil();
protected:
virtual void pathWillClear();
private:
void onDrawPath(GrDrawTarget::StageBitfield stages, bool stencilOnly);
bool createGeom(GrScalar srcSpaceTol,
GrDrawTarget::StageBitfield stages);
bool fSeparateStencil;
bool fStencilWrapOps;
int fSubpathCount;
SkAutoSTMalloc<8, uint16_t> fSubpathVertCount;
int fIndexCnt;
int fVertexCnt;
GrScalar fPreviousSrcTol;
GrDrawTarget::StageBitfield fPreviousStages;
GrPrimitiveType fPrimitiveType;
bool fUseIndexedDraw;
typedef GrPathRenderer INHERITED;
};
#endif

View File

@ -0,0 +1,65 @@
/*
* Copyright 2011 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "GrPathRendererChain.h"
#include "GrContext.h"
#include "GrDefaultPathRenderer.h"
#include "GrGpu.h"
GrPathRendererChain::GrPathRendererChain(GrContext* context, UsageFlags flags)
: fInit(false)
, fFlags(flags)
, fOwner(context)
, fChain(fStorage.get(), kPreAllocCount) {
fInit = false;
}
GrPathRendererChain::~GrPathRendererChain() {
for (int i = 0; i < fChain.count(); ++i) {
fChain[i]->unref();
}
}
GrPathRenderer* GrPathRendererChain::addPathRenderer(GrPathRenderer* pr) {
fChain.push_back() = pr;
pr->ref();
return pr;
}
GrPathRenderer* GrPathRendererChain::getPathRenderer(const GrDrawTarget* target,
const GrPath& path,
GrPathFill fill) {
if (!fInit) {
this->init();
}
bool preferAA = target->isAntialiasState() &&
!target->getRenderTarget()->isMultisampled();
GrPathRenderer* nonAAPR = NULL;
for (int i = 0; i < fChain.count(); ++i) {
if (fChain[i]->canDrawPath(path, fill)) {
if (!preferAA || fChain[i]->supportsAA(target, path, fill)) {
return fChain[i];
} else {
nonAAPR = fChain[i];
}
}
}
return nonAAPR;
}
void GrPathRendererChain::init() {
GrAssert(!fInit);
GrGpu* gpu = fOwner->getGpu();
this->addPathRenderer(
new GrDefaultPathRenderer(gpu->supportsTwoSidedStencil(),
gpu->supportsStencilWrapOps()))->unref();
GrPathRenderer::AddPathRenderers(fOwner, fFlags, this);
fInit = true;
}

View File

@ -0,0 +1,64 @@
/*
* Copyright 2011 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef GrPathRendererChain_DEFINED
#define GrPathRendererChain_DEFINED
#include "GrRefCnt.h"
#include "GrTArray.h"
class GrContext;
class GrDrawTarget;
class SkPath;
class GrPathRenderer;
/**
* Keeps track of a ordered list of path renderers. When a path needs to be
* drawn this list is scanned to find the most preferred renderer. To add your
* path renderer to the list implement the GrPathRenderer::AddPathRenderers
* function.
*/
class GrPathRendererChain : public SkRefCnt {
public:
enum UsageFlags {
kNone_UsageFlag = 0,
kNonAAOnly_UsageFlag = 1,
};
GrPathRendererChain(GrContext* context, UsageFlags flags);
~GrPathRendererChain();
// takes a ref and unrefs in destructor
GrPathRenderer* addPathRenderer(GrPathRenderer* pr);
GrPathRenderer* getPathRenderer(const GrDrawTarget* target,
const SkPath& path,
GrPathFill fill);
private:
GrPathRendererChain();
void init();
enum {
kPreAllocCount = 8,
};
bool fInit;
GrContext* fOwner;
UsageFlags fFlags;
GrAlignedSTStorage<kPreAllocCount, GrPathRenderer*> fStorage;
GrTArray<GrPathRenderer*, true> fChain;
};
GR_MAKE_BITFIELD_OPS(GrPathRendererChain::UsageFlags)
#endif

View File

@ -608,8 +608,8 @@ void GrTesselatedPathRenderer::drawPathToStencil() {
GrAlwaysAssert(!"multipass stencil should not be needed");
}
bool GrTesselatedPathRenderer::supportsAA(GrDrawTarget* target,
const SkPath& path,
GrPathFill fill) {
bool GrTesselatedPathRenderer::supportsAA(const GrDrawTarget* target,
const SkPath& path,
GrPathFill fill) {
return true;
}

View File

@ -24,7 +24,7 @@ public:
const GrPath& path,
GrPathFill fill) const { return false; }
virtual void drawPathToStencil();
virtual bool supportsAA(GrDrawTarget* target,
virtual bool supportsAA(const GrDrawTarget* target,
const GrPath& path,
GrPathFill fill);
};

View File

@ -126,6 +126,7 @@
'../gpu/include/GrTypes.h',
'../gpu/include/GrUserConfig.h',
'../gpu/src/GrAddPathRenderers_none.cpp',
'../gpu/src/GrAllocPool.cpp',
'../gpu/src/GrAtlas.cpp',
'../gpu/src/GrBinHashKey.h',
@ -133,7 +134,8 @@
'../gpu/src/GrBufferAllocPool.h',
'../gpu/src/GrClip.cpp',
'../gpu/src/GrContext.cpp',
'../gpu/src/GrCreatePathRenderer_none.cpp',
'../gpu/src/GrDefaultPathRenderer.cpp',
'../gpu/src/GrDefaultPathRenderer.h',
'../gpu/src/GrDrawTarget.cpp',
'../gpu/src/GrDrawTarget.h',
'../gpu/src/GrGeometryBuffer.h',
@ -167,6 +169,8 @@
'../gpu/src/GrInOrderDrawBuffer.h',
'../gpu/src/GrMatrix.cpp',
'../gpu/src/GrMemory.cpp',
'../gpu/src/GrPathRendererChain.cpp',
'../gpu/src/GrPathRendererChain.h',
'../gpu/src/GrPathRenderer.cpp',
'../gpu/src/GrPathRenderer.h',
'../gpu/src/GrPathUtils.cpp',