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:
parent
b095140596
commit
3008519e9f
@ -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;
|
||||
|
||||
|
15
gpu/src/GrAddPathRenderers_none.cpp
Normal file
15
gpu/src/GrAddPathRenderers_none.cpp
Normal 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*) {}
|
17
gpu/src/GrAddPathRenderers_tesselated.cpp
Normal file
17
gpu/src/GrAddPathRenderers_tesselated.cpp
Normal 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();
|
||||
}
|
@ -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,
|
||||
|
@ -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; }
|
@ -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(); }
|
562
gpu/src/GrDefaultPathRenderer.cpp
Normal file
562
gpu/src/GrDefaultPathRenderer.cpp
Normal 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);
|
||||
}
|
58
gpu/src/GrDefaultPathRenderer.h
Normal file
58
gpu/src/GrDefaultPathRenderer.h
Normal 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
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
|
65
gpu/src/GrPathRendererChain.cpp
Normal file
65
gpu/src/GrPathRendererChain.cpp
Normal 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;
|
||||
}
|
64
gpu/src/GrPathRendererChain.h
Normal file
64
gpu/src/GrPathRendererChain.h
Normal 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
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
};
|
||||
|
@ -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',
|
||||
|
Loading…
Reference in New Issue
Block a user