Tesselate path once for tiled offscreen AA
Review URL: http://codereview.appspot.com/4661062/ git-svn-id: http://skia.googlecode.com/svn/trunk@1777 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
parent
db2a09f240
commit
ee435122d7
@ -580,7 +580,7 @@ private:
|
||||
|
||||
void drawClipIntoStencil();
|
||||
|
||||
GrPathRenderer* getPathRenderer(const GrDrawTarget*, const GrPath&, GrPathFill);
|
||||
GrPathRenderer* getPathRenderer(const GrPath&, GrPathFill);
|
||||
|
||||
struct OffscreenRecord;
|
||||
|
||||
|
@ -18,57 +18,46 @@
|
||||
#define GrPathRenderer_DEFINED
|
||||
|
||||
#include "GrDrawTarget.h"
|
||||
#include "SkTemplates.h"
|
||||
|
||||
class SkPath;
|
||||
struct GrPoint;
|
||||
|
||||
/**
|
||||
* Base class for drawing paths into a GrDrawTarget.
|
||||
* Paths may be drawn multiple times as when tiling for supersampling. The
|
||||
* calls on GrPathRenderer to draw a path will look like this:
|
||||
*
|
||||
* pr->setPath(target, path, fill, translate); // sets the path to draw
|
||||
* pr->drawPath(...); // draw the path
|
||||
* pr->drawPath(...);
|
||||
* ...
|
||||
* pr->clearPath(); // finished with the path
|
||||
*/
|
||||
class GR_API GrPathRenderer : public GrRefCnt {
|
||||
public:
|
||||
GrPathRenderer(void);
|
||||
|
||||
/**
|
||||
* Returns true if this path renderer is able to render the path.
|
||||
* Returning false allows the caller to fallback to another path renderer.
|
||||
*
|
||||
* @param target The target to draw into
|
||||
* @param path The path to draw
|
||||
* @param fill The fill rule to use
|
||||
*
|
||||
* @return true if the path can be drawn by this object, false otherwise.
|
||||
*/
|
||||
virtual bool canDrawPath(const GrDrawTarget* target, const SkPath& path,
|
||||
GrPathFill fill) const = 0;
|
||||
|
||||
/**
|
||||
* Draws a path into the draw target. The target will already have its draw
|
||||
* state configured for the draw.
|
||||
* @param target the target to draw into.
|
||||
* @param stages indicates which stages the are already
|
||||
* in use. All enabled stages expect positions
|
||||
* as texture coordinates. The path renderer
|
||||
* use the remaining stages for its path
|
||||
* filling algorithm.
|
||||
* @param path the path to draw.
|
||||
* @param fill the fill rule to apply.
|
||||
* @param translate optional additional translation to apply to
|
||||
* the path. NULL means (0,0).
|
||||
*/
|
||||
virtual void drawPath(GrDrawTarget* target,
|
||||
GrDrawTarget::StageBitfield stages,
|
||||
const SkPath& path,
|
||||
GrPathFill fill,
|
||||
const GrPoint* translate) = 0;
|
||||
virtual bool canDrawPath(const SkPath& path, GrPathFill fill) const = 0;
|
||||
|
||||
/**
|
||||
* For complex clips Gr uses the stencil buffer. The path renderer must be
|
||||
* able to render paths into the stencil buffer. However, the path renderer
|
||||
* itself may require the stencil buffer to resolve the path fill rule. This
|
||||
* function queries whether the path render needs its own stencil
|
||||
* itself may require the stencil buffer to resolve the path fill rule.
|
||||
* This function queries whether the path render needs its own stencil
|
||||
* pass. If this returns false then drawPath() should not modify the
|
||||
* the target's stencil settings but use those already set on target.
|
||||
* the target's stencil settings but use those already set on target. The
|
||||
* target is passed as a param in case the answer depends upon draw state.
|
||||
* The view matrix and render target set on the draw target may change
|
||||
* before setPath/drawPath is called and so shouldn't be considered.
|
||||
*
|
||||
* @param target target that the path will be rendered to
|
||||
* @param path the path that will be drawn
|
||||
@ -85,7 +74,59 @@ public:
|
||||
GrPathFill fill) const { return false; }
|
||||
|
||||
/**
|
||||
* Draws a path to the stencil buffer. Assume the writable stencil bits
|
||||
* @return true if the path renderer can perform anti-aliasing (aside from
|
||||
* 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,
|
||||
const SkPath& path,
|
||||
GrPathFill fill) { return false; }
|
||||
|
||||
/**
|
||||
* Sets the path to render and target to render into. All calls to drawPath
|
||||
* and drawPathToStencil must occur between setPath and clearPath. The
|
||||
* path cannot be modified externally between setPath and clearPath. The
|
||||
* path may be drawn several times (e.g. tiled supersampler). The target's
|
||||
* state may change between setPath and drawPath* calls. However, if the
|
||||
* path renderer specified vertices/indices during setPath or drawPath*
|
||||
* they will still be set at subsequent drawPath* calls until the next
|
||||
* clearPath. The target's draw state may change between drawPath* calls
|
||||
* so if the subclass does any caching of tesselation, etc. then it must
|
||||
* validate that target parameters that guided the decisions still hold.
|
||||
*
|
||||
* @param target the target to draw into.
|
||||
* @param path the path to draw.
|
||||
* @param fill the fill rule to apply.
|
||||
* @param translate optional additional translation to apply to
|
||||
* the path. NULL means (0,0).
|
||||
*/
|
||||
void setPath(GrDrawTarget* target,
|
||||
const SkPath* path,
|
||||
GrPathFill fill,
|
||||
const GrPoint* translate);
|
||||
|
||||
/**
|
||||
* Notifies path renderer that path set in setPath is no longer in use.
|
||||
*/
|
||||
void clearPath();
|
||||
|
||||
/**
|
||||
* Draws the path into the draw target. If requiresStencilBuffer returned
|
||||
* false then the target may be setup for stencil rendering (since the
|
||||
* path renderer didn't claim that it needs to use the stencil internally).
|
||||
*
|
||||
* Only called between setPath / clearPath.
|
||||
*
|
||||
* @param stages bitfield that indicates which stages are
|
||||
* in use. All enabled stages expect positions
|
||||
* as texture coordinates. The path renderer
|
||||
* use the remaining stages for its path
|
||||
* filling algorithm.
|
||||
*/
|
||||
virtual void drawPath(GrDrawTarget::StageBitfield stages) = 0;
|
||||
|
||||
/**
|
||||
* Draws the path to the stencil buffer. Assume the writable stencil bits
|
||||
* are already initialized to zero. Fill will always be either
|
||||
* kWinding_PathFill or kEvenOdd_PathFill.
|
||||
*
|
||||
@ -95,28 +136,12 @@ public:
|
||||
* The default implementation assumes the path filling algorithm doesn't
|
||||
* require a separate stencil pass and so crashes.
|
||||
*
|
||||
*
|
||||
* @param target the target to draw into.
|
||||
* @param path the path to draw.
|
||||
* @param fill the fill rule to apply.
|
||||
* @param translate optional additional translation to apply to
|
||||
* the path. NULL means (0,0).
|
||||
* Only called between setPath / clearPath.
|
||||
*/
|
||||
virtual void drawPathToStencil(GrDrawTarget* target,
|
||||
const SkPath& path,
|
||||
GrPathFill fill,
|
||||
const GrPoint* translate) {
|
||||
virtual void drawPathToStencil() {
|
||||
GrCrash("Unexpected call to drawPathToStencil.");
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if the path renderer can perform anti-aliasing (aside from
|
||||
* having FSAA enabled for a render target)
|
||||
*/
|
||||
virtual bool supportsAA(GrDrawTarget* target,
|
||||
const SkPath& path,
|
||||
GrPathFill fill) { return false; }
|
||||
|
||||
/**
|
||||
* This is called to install a custom path renderer in every GrContext at
|
||||
* create time. The default implementation in GrCreatePathRenderer_none.cpp
|
||||
@ -134,8 +159,56 @@ public:
|
||||
fCurveTolerance = SkScalarMul(fCurveTolerance, multiplier);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper that sets a path and automatically remove it in destructor.
|
||||
*/
|
||||
class AutoClearPath {
|
||||
public:
|
||||
AutoClearPath() {
|
||||
fPathRenderer = NULL;
|
||||
}
|
||||
AutoClearPath(GrPathRenderer* pr,
|
||||
GrDrawTarget* target,
|
||||
const SkPath* path,
|
||||
GrPathFill fill,
|
||||
const GrPoint* translate) {
|
||||
GrAssert(NULL != pr);
|
||||
pr->setPath(target, path, fill, translate);
|
||||
fPathRenderer = pr;
|
||||
}
|
||||
void set(GrPathRenderer* pr,
|
||||
GrDrawTarget* target,
|
||||
const SkPath* path,
|
||||
GrPathFill fill,
|
||||
const GrPoint* translate) {
|
||||
if (NULL != fPathRenderer) {
|
||||
fPathRenderer->clearPath();
|
||||
}
|
||||
GrAssert(NULL != pr);
|
||||
pr->setPath(target, path, fill, translate);
|
||||
fPathRenderer = pr;
|
||||
}
|
||||
~AutoClearPath() {
|
||||
if (NULL != fPathRenderer) {
|
||||
fPathRenderer->clearPath();
|
||||
}
|
||||
}
|
||||
private:
|
||||
GrPathRenderer* fPathRenderer;
|
||||
};
|
||||
|
||||
protected:
|
||||
|
||||
// subclass can override these to be notified just after a path is set
|
||||
// and just before the path is cleared.
|
||||
virtual void pathWasSet() {}
|
||||
virtual void pathWillClear() {}
|
||||
|
||||
GrScalar fCurveTolerance;
|
||||
const SkPath* fPath;
|
||||
GrDrawTarget* fTarget;
|
||||
GrPathFill fFill;
|
||||
GrPoint fTranslate;
|
||||
|
||||
private:
|
||||
|
||||
@ -151,35 +224,37 @@ public:
|
||||
GrDefaultPathRenderer(bool separateStencilSupport,
|
||||
bool stencilWrapOpsSupport);
|
||||
|
||||
virtual bool canDrawPath(const GrDrawTarget* target,
|
||||
const SkPath& path,
|
||||
virtual bool canDrawPath(const SkPath& path,
|
||||
GrPathFill fill) const { return true; }
|
||||
|
||||
virtual void drawPath(GrDrawTarget* target,
|
||||
GrDrawTarget::StageBitfield stages,
|
||||
const SkPath& path,
|
||||
GrPathFill fill,
|
||||
const GrPoint* translate);
|
||||
virtual bool requiresStencilPass(const GrDrawTarget* target,
|
||||
const SkPath& path,
|
||||
GrPathFill fill) const;
|
||||
virtual void drawPathToStencil(GrDrawTarget* target,
|
||||
const SkPath& path,
|
||||
GrPathFill fill,
|
||||
const GrPoint* translate);
|
||||
|
||||
virtual void drawPath(GrDrawTarget::StageBitfield stages);
|
||||
virtual void drawPathToStencil();
|
||||
|
||||
protected:
|
||||
virtual void pathWillClear();
|
||||
|
||||
private:
|
||||
|
||||
void onDrawPath(GrDrawTarget* target,
|
||||
GrDrawTarget::StageBitfield stages,
|
||||
const SkPath& path,
|
||||
GrPathFill fill,
|
||||
const GrPoint* translate,
|
||||
bool stencilOnly);
|
||||
void onDrawPath(GrDrawTarget::StageBitfield stages, bool stencilOnly);
|
||||
|
||||
void createGeom(GrScalar srcSpaceTolSqd,
|
||||
GrDrawTarget::StageBitfield stages);
|
||||
|
||||
bool fSeparateStencil;
|
||||
bool fStencilWrapOps;
|
||||
|
||||
int fSubpathCount;
|
||||
SkAutoSTMalloc<8, uint16_t> fSubpathVertCount;
|
||||
GrScalar fPreviousSrcTol;
|
||||
GrDrawTarget::StageBitfield fPreviousStages;
|
||||
|
||||
|
||||
typedef GrPathRenderer INHERITED;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -39,7 +39,8 @@
|
||||
#define GrIntToScalar(a) SkIntToScalar(a)
|
||||
#define GrScalarHalf(a) SkScalarHalf(a)
|
||||
#define GrScalarAve(a,b) SkScalarAve(a,b)
|
||||
#define GrMul(a,b) SkScalarMul(a,b)
|
||||
#define GrMul(a,b) SkScalarMul(a,b) // deprecated, prefer GrScalarMul
|
||||
#define GrScalarMul(a,b) SkScalarMul(a,b)
|
||||
#define GrScalarDiv(a,b) SkScalarDiv(a, b)
|
||||
#define GrScalarToFloat(a) SkScalarToFloat(a)
|
||||
#define GrFloatToScalar(a) SkScalarToFloat(a)
|
||||
|
@ -23,22 +23,14 @@ class GrTesselatedPathRenderer : public GrPathRenderer {
|
||||
public:
|
||||
GrTesselatedPathRenderer();
|
||||
|
||||
virtual void drawPath(GrDrawTarget* target,
|
||||
GrDrawTarget::StageBitfield stages,
|
||||
const GrPath& path,
|
||||
GrPathFill fill,
|
||||
const GrPoint* translate);
|
||||
virtual bool canDrawPath(const GrDrawTarget* target,
|
||||
const GrPath& path,
|
||||
virtual void drawPath(GrDrawTarget::StageBitfield stages);
|
||||
virtual bool canDrawPath(const GrPath& path,
|
||||
GrPathFill fill) const;
|
||||
|
||||
virtual bool requiresStencilPass(const GrDrawTarget* target,
|
||||
const GrPath& path,
|
||||
GrPathFill fill) const { return false; }
|
||||
virtual void drawPathToStencil(GrDrawTarget* target,
|
||||
const GrPath& path,
|
||||
GrPathFill fill,
|
||||
const GrPoint* translate);
|
||||
virtual void drawPathToStencil();
|
||||
virtual bool supportsAA(GrDrawTarget* target,
|
||||
const GrPath& path,
|
||||
GrPathFill fill);
|
||||
|
@ -715,7 +715,7 @@ void GrContext::doOffscreenAAPass2(GrDrawTarget* target,
|
||||
OffscreenRecord* record) {
|
||||
SK_TRACE_EVENT0("GrContext::doOffscreenAAPass2");
|
||||
GrAssert(NULL != record->fEntry0);
|
||||
|
||||
GrDrawTarget::AutoGeometryPush agp(target);
|
||||
GrIRect tileRect;
|
||||
tileRect.fLeft = boundRect.fLeft + tileX * record->fTileSizeX;
|
||||
tileRect.fTop = boundRect.fTop + tileY * record->fTileSizeY,
|
||||
@ -1321,7 +1321,9 @@ 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(target, path, fill);
|
||||
GrPathRenderer* pr = this->getPathRenderer(path, fill);
|
||||
GrPathRenderer::AutoClearPath arp(pr, target, &path, fill, translate);
|
||||
GrDrawTarget::StageBitfield stageMask = paint.getActiveStageMask();
|
||||
|
||||
if (!pr->supportsAA(target, path, fill) &&
|
||||
this->doOffscreenAA(target, paint, kHairLine_PathFill == fill)) {
|
||||
@ -1357,13 +1359,12 @@ void GrContext::drawPath(const GrPaint& paint, const GrPath& path,
|
||||
for (int tx = 0; tx < record.fTileCountX; ++tx) {
|
||||
for (int ty = 0; ty < record.fTileCountY; ++ty) {
|
||||
this->setupOffscreenAAPass1(target, bound, tx, ty, &record);
|
||||
pr->drawPath(target, 0, path, fill, translate);
|
||||
pr->drawPath(0);
|
||||
this->doOffscreenAAPass2(target, paint, bound, tx, ty, &record);
|
||||
}
|
||||
}
|
||||
this->cleanupOffscreenAA(target, pr, &record);
|
||||
if (IsFillInverted(fill) && bound != clipIBounds) {
|
||||
int stageMask = paint.getActiveStageMask();
|
||||
GrDrawTarget::AutoDeviceCoordDraw adcd(target, stageMask);
|
||||
GrRect rect;
|
||||
if (clipIBounds.fTop < bound.fTop) {
|
||||
@ -1390,10 +1391,7 @@ void GrContext::drawPath(const GrPaint& paint, const GrPath& path,
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
GrDrawTarget::StageBitfield enabledStages = paint.getActiveStageMask();
|
||||
|
||||
pr->drawPath(target, enabledStages, path, fill, translate);
|
||||
pr->drawPath(stageMask);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@ -1690,14 +1688,13 @@ const GrIndexBuffer* GrContext::getQuadIndexBuffer() const {
|
||||
return fGpu->getQuadIndexBuffer();
|
||||
}
|
||||
|
||||
GrPathRenderer* GrContext::getPathRenderer(const GrDrawTarget* target,
|
||||
const GrPath& path,
|
||||
GrPathRenderer* GrContext::getPathRenderer(const GrPath& path,
|
||||
GrPathFill fill) {
|
||||
if (NULL != fCustomPathRenderer &&
|
||||
fCustomPathRenderer->canDrawPath(target, path, fill)) {
|
||||
fCustomPathRenderer->canDrawPath(path, fill)) {
|
||||
return fCustomPathRenderer;
|
||||
} else {
|
||||
GrAssert(fDefaultPathRenderer.canDrawPath(target, path, fill));
|
||||
GrAssert(fDefaultPathRenderer.canDrawPath(path, fill));
|
||||
return &fDefaultPathRenderer;
|
||||
}
|
||||
}
|
||||
|
@ -24,9 +24,8 @@
|
||||
#include "GrPathRenderer.h"
|
||||
|
||||
// probably makes no sense for this to be less than a page
|
||||
static const size_t VERTEX_POOL_VB_SIZE = 1 << 12;
|
||||
static const int VERTEX_POOL_VB_COUNT = 1;
|
||||
|
||||
static const size_t VERTEX_POOL_VB_SIZE = 1 << 18;
|
||||
static const int VERTEX_POOL_VB_COUNT = 4;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@ -454,6 +453,7 @@ bool GrGpu::setupClipAndFlushState(GrPrimitiveType type) {
|
||||
// with the existing clip.
|
||||
for (int c = firstElement; c < count; ++c) {
|
||||
GrPathFill fill;
|
||||
bool fillInverted;
|
||||
// enabled at bottom of loop
|
||||
this->disableState(kModifyStencilClip_StateBit);
|
||||
|
||||
@ -465,16 +465,20 @@ bool GrGpu::setupClipAndFlushState(GrPrimitiveType type) {
|
||||
|
||||
GrPathRenderer* pr = NULL;
|
||||
const GrPath* clipPath = NULL;
|
||||
GrPathRenderer::AutoClearPath arp;
|
||||
if (kRect_ClipType == clip.getElementType(c)) {
|
||||
canRenderDirectToStencil = true;
|
||||
fill = kEvenOdd_PathFill;
|
||||
fillInverted = false;
|
||||
} else {
|
||||
fill = clip.getPathFill(c);
|
||||
fillInverted = IsFillInverted(fill);
|
||||
fill = NonInvertedFill(fill);
|
||||
clipPath = &clip.getPath(c);
|
||||
pr = this->getClipPathRenderer(*clipPath, NonInvertedFill(fill));
|
||||
pr = this->getClipPathRenderer(*clipPath, fill);
|
||||
canRenderDirectToStencil =
|
||||
!pr->requiresStencilPass(this, *clipPath,
|
||||
NonInvertedFill(fill));
|
||||
!pr->requiresStencilPass(this, *clipPath, fill);
|
||||
arp.set(pr, this, clipPath, fill, NULL);
|
||||
}
|
||||
|
||||
GrSetOp op = firstElement == c ? kReplace_SetOp : clip.getOp(c);
|
||||
@ -489,7 +493,7 @@ bool GrGpu::setupClipAndFlushState(GrPrimitiveType type) {
|
||||
GrStencilSettings::GetClipPasses(op,
|
||||
canRenderDirectToStencil,
|
||||
clipBit,
|
||||
IsFillInverted(fill),
|
||||
fillInverted,
|
||||
&passes, stencilSettings);
|
||||
|
||||
// draw the element to the client stencil bits if necessary
|
||||
@ -509,12 +513,9 @@ bool GrGpu::setupClipAndFlushState(GrPrimitiveType type) {
|
||||
} else {
|
||||
if (canRenderDirectToStencil) {
|
||||
this->setStencil(gDrawToStencil);
|
||||
pr->drawPath(this, 0, *clipPath, NonInvertedFill(fill),
|
||||
NULL);
|
||||
pr->drawPath(0);
|
||||
} else {
|
||||
pr->drawPathToStencil(this, *clipPath,
|
||||
NonInvertedFill(fill),
|
||||
NULL);
|
||||
pr->drawPathToStencil();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -530,8 +531,7 @@ bool GrGpu::setupClipAndFlushState(GrPrimitiveType type) {
|
||||
this->drawSimpleRect(clip.getRect(c), NULL, 0);
|
||||
} else {
|
||||
SET_RANDOM_COLOR
|
||||
GrAssert(!IsFillInverted(fill));
|
||||
pr->drawPath(this, 0, *clipPath, fill, NULL);
|
||||
pr->drawPath(0);
|
||||
}
|
||||
} else {
|
||||
SET_RANDOM_COLOR
|
||||
@ -558,7 +558,7 @@ bool GrGpu::setupClipAndFlushState(GrPrimitiveType type) {
|
||||
GrPathRenderer* GrGpu::getClipPathRenderer(const GrPath& path,
|
||||
GrPathFill fill) {
|
||||
if (NULL != fClientPathRenderer &&
|
||||
fClientPathRenderer->canDrawPath(this, path, fill)) {
|
||||
fClientPathRenderer->canDrawPath(path, fill)) {
|
||||
return fClientPathRenderer;
|
||||
} else {
|
||||
if (NULL == fDefaultPathRenderer) {
|
||||
@ -566,7 +566,7 @@ GrPathRenderer* GrGpu::getClipPathRenderer(const GrPath& path,
|
||||
new GrDefaultPathRenderer(this->supportsTwoSidedStencil(),
|
||||
this->supportsStencilWrapOps());
|
||||
}
|
||||
GrAssert(fDefaultPathRenderer->canDrawPath(this, path, fill));
|
||||
GrAssert(fDefaultPathRenderer->canDrawPath(path, fill));
|
||||
return fDefaultPathRenderer;
|
||||
}
|
||||
}
|
||||
|
@ -11,15 +11,49 @@
|
||||
#include SK_USER_TRACE_INCLUDE_FILE
|
||||
|
||||
GrPathRenderer::GrPathRenderer()
|
||||
: fCurveTolerance (GR_Scalar1) {
|
||||
|
||||
: fCurveTolerance (GR_Scalar1)
|
||||
, fPath(NULL)
|
||||
, fTarget(NULL) {
|
||||
}
|
||||
|
||||
|
||||
void GrPathRenderer::setPath(GrDrawTarget* target,
|
||||
const SkPath* path,
|
||||
GrPathFill fill,
|
||||
const GrPoint* translate) {
|
||||
GrAssert(NULL == fPath);
|
||||
GrAssert(NULL == fTarget);
|
||||
GrAssert(NULL != target);
|
||||
|
||||
fTarget = target;
|
||||
fPath = path;
|
||||
fFill = fill;
|
||||
if (NULL != translate) {
|
||||
fTranslate = *translate;
|
||||
} else {
|
||||
fTranslate.fX = fTranslate.fY = 0;
|
||||
}
|
||||
this->pathWasSet();
|
||||
}
|
||||
|
||||
void GrPathRenderer::clearPath() {
|
||||
this->pathWillClear();
|
||||
fTarget->resetVertexSource();
|
||||
fTarget = NULL;
|
||||
fPath = NULL;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
GrDefaultPathRenderer::GrDefaultPathRenderer(bool separateStencilSupport,
|
||||
bool stencilWrapOpsSupport)
|
||||
: fSeparateStencil(separateStencilSupport)
|
||||
, fStencilWrapOps(stencilWrapOpsSupport) {
|
||||
|
||||
, fStencilWrapOps(stencilWrapOpsSupport)
|
||||
, fSubpathCount(0)
|
||||
, fSubpathVertCount(0)
|
||||
, fPreviousSrcTol(-GR_Scalar1)
|
||||
, fPreviousStages(-1) {
|
||||
fTarget = NULL;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@ -189,21 +223,105 @@ bool GrDefaultPathRenderer::requiresStencilPass(const GrDrawTarget* target,
|
||||
return !single_pass_path(*target, path, fill);
|
||||
}
|
||||
|
||||
void GrDefaultPathRenderer::onDrawPath(GrDrawTarget* target,
|
||||
GrDrawTarget::StageBitfield stages,
|
||||
const GrPath& path,
|
||||
GrPathFill fill,
|
||||
const GrPoint* translate,
|
||||
void GrDefaultPathRenderer::pathWillClear() {
|
||||
fSubpathVertCount.realloc(0);
|
||||
fTarget->resetVertexSource();
|
||||
fPreviousSrcTol = -GR_Scalar1;
|
||||
fPreviousStages = -1;
|
||||
}
|
||||
|
||||
void GrDefaultPathRenderer::createGeom(GrScalar srcSpaceTol,
|
||||
GrDrawTarget::StageBitfield stages) {
|
||||
{
|
||||
SK_TRACE_EVENT0("GrDefaultPathRenderer::createGeom");
|
||||
|
||||
fPreviousSrcTol = srcSpaceTol;
|
||||
fPreviousStages = stages;
|
||||
|
||||
GrScalar srcSpaceTolSqd = GrMul(srcSpaceTol, srcSpaceTol);
|
||||
int maxPts = GrPathUtils::worstCasePointCount(*fPath, &fSubpathCount,
|
||||
srcSpaceTol);
|
||||
|
||||
GrVertexLayout layout = 0;
|
||||
for (int s = 0; s < GrDrawTarget::kNumStages; ++s) {
|
||||
if ((1 << s) & stages) {
|
||||
layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(s);
|
||||
}
|
||||
}
|
||||
|
||||
// add 4 to hold the bounding rect
|
||||
GrPoint* base;
|
||||
fTarget->reserveVertexSpace(layout, maxPts + 4, (void**)&base);
|
||||
|
||||
GrPoint* vert = base;
|
||||
GrPoint* subpathBase = base;
|
||||
|
||||
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) {
|
||||
fSubpathVertCount[subpath] = vert-subpathBase;
|
||||
subpathBase = vert;
|
||||
++subpath;
|
||||
}
|
||||
*vert = pts[0];
|
||||
vert++;
|
||||
break;
|
||||
case kLine_PathCmd:
|
||||
*vert = pts[1];
|
||||
vert++;
|
||||
break;
|
||||
case kQuadratic_PathCmd: {
|
||||
GrPathUtils::generateQuadraticPoints(pts[0], pts[1], pts[2],
|
||||
srcSpaceTolSqd, &vert,
|
||||
GrPathUtils::quadraticPointCount(pts, srcSpaceTol));
|
||||
break;
|
||||
}
|
||||
case kCubic_PathCmd: {
|
||||
GrPathUtils::generateCubicPoints(pts[0], pts[1], pts[2], pts[3],
|
||||
srcSpaceTolSqd, &vert,
|
||||
GrPathUtils::cubicPointCount(pts, srcSpaceTol));
|
||||
break;
|
||||
}
|
||||
case kClose_PathCmd:
|
||||
break;
|
||||
case kEnd_PathCmd:
|
||||
fSubpathVertCount[subpath] = vert-subpathBase;
|
||||
++subpath; // this could be only in debug
|
||||
goto FINISHED;
|
||||
}
|
||||
first = false;
|
||||
}
|
||||
FINISHED:
|
||||
GrAssert(subpath == fSubpathCount);
|
||||
GrAssert((vert - base) <= maxPts);
|
||||
|
||||
if (fTranslate.fX || fTranslate.fY) {
|
||||
int count = vert - base;
|
||||
for (int i = 0; i < count; i++) {
|
||||
base[i].offset(fTranslate.fX, fTranslate.fY);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GrDefaultPathRenderer::onDrawPath(GrDrawTarget::StageBitfield stages,
|
||||
bool stencilOnly) {
|
||||
|
||||
SK_TRACE_EVENT1("GrDefaultPathRenderer::onDrawPath",
|
||||
"points", SkStringPrintf("%i", path.countPoints()).c_str());
|
||||
|
||||
GrDrawTarget::AutoStateRestore asr(target);
|
||||
bool colorWritesWereDisabled = target->isColorWriteDisabled();
|
||||
// face culling doesn't make sense here
|
||||
GrAssert(GrDrawTarget::kBoth_DrawFace == target->getDrawFace());
|
||||
|
||||
GrMatrix viewM = target->getViewMatrix();
|
||||
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();
|
||||
@ -216,28 +334,25 @@ void GrDefaultPathRenderer::onDrawPath(GrDrawTarget* target,
|
||||
} else {
|
||||
tol = GrScalarDiv(tol, stretch);
|
||||
}
|
||||
GrScalar tolSqd = GrMul(tol, tol);
|
||||
|
||||
int subpathCnt;
|
||||
int maxPts = GrPathUtils::worstCasePointCount(path, &subpathCnt, tol);
|
||||
|
||||
GrVertexLayout layout = 0;
|
||||
for (int s = 0; s < GrDrawTarget::kNumStages; ++s) {
|
||||
if ((1 << s) & stages) {
|
||||
layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(s);
|
||||
}
|
||||
// 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) {
|
||||
this->createGeom(tol, stages);
|
||||
}
|
||||
|
||||
// add 4 to hold the bounding rect
|
||||
GrDrawTarget::AutoReleaseGeometry arg(target, layout, maxPts + 4, 0);
|
||||
GrAssert(NULL != fTarget);
|
||||
GrDrawTarget::AutoStateRestore asr(fTarget);
|
||||
bool colorWritesWereDisabled = fTarget->isColorWriteDisabled();
|
||||
// face culling doesn't make sense here
|
||||
GrAssert(GrDrawTarget::kBoth_DrawFace == fTarget->getDrawFace());
|
||||
|
||||
GrPoint* base = (GrPoint*) arg.vertices();
|
||||
GrPoint* vert = base;
|
||||
GrPoint* subpathBase = base;
|
||||
|
||||
SkAutoSTMalloc<8, uint16_t> subpathVertCount(subpathCnt);
|
||||
|
||||
// TODO: use primitve restart if available rather than multiple draws
|
||||
GrPrimitiveType type;
|
||||
int passCount = 0;
|
||||
const GrStencilSettings* passes[3];
|
||||
@ -245,7 +360,7 @@ void GrDefaultPathRenderer::onDrawPath(GrDrawTarget* target,
|
||||
bool reverse = false;
|
||||
bool lastPassIsBounds;
|
||||
|
||||
if (kHairLine_PathFill == fill) {
|
||||
if (kHairLine_PathFill == fFill) {
|
||||
type = kLineStrip_PrimitiveType;
|
||||
passCount = 1;
|
||||
if (stencilOnly) {
|
||||
@ -257,7 +372,7 @@ void GrDefaultPathRenderer::onDrawPath(GrDrawTarget* target,
|
||||
drawFace[0] = GrDrawTarget::kBoth_DrawFace;
|
||||
} else {
|
||||
type = kTriangleFan_PrimitiveType;
|
||||
if (single_pass_path(*target, path, fill)) {
|
||||
if (single_pass_path(*fTarget, *fPath, fFill)) {
|
||||
passCount = 1;
|
||||
if (stencilOnly) {
|
||||
passes[0] = &gDirectToStencil;
|
||||
@ -267,7 +382,7 @@ void GrDefaultPathRenderer::onDrawPath(GrDrawTarget* target,
|
||||
drawFace[0] = GrDrawTarget::kBoth_DrawFace;
|
||||
lastPassIsBounds = false;
|
||||
} else {
|
||||
switch (fill) {
|
||||
switch (fFill) {
|
||||
case kInverseEvenOdd_PathFill:
|
||||
reverse = true;
|
||||
// fallthrough
|
||||
@ -327,140 +442,62 @@ void GrDefaultPathRenderer::onDrawPath(GrDrawTarget* target,
|
||||
}
|
||||
break;
|
||||
default:
|
||||
GrAssert(!"Unknown path fill!");
|
||||
GrAssert(!"Unknown path fFill!");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GrPoint pts[4];
|
||||
|
||||
bool first = true;
|
||||
int subpath = 0;
|
||||
|
||||
SkPath::Iter iter(path, false);
|
||||
|
||||
{
|
||||
SK_TRACE_EVENT0("GrDefaultPathRenderer::onDrawPath::assembleVerts");
|
||||
for (;;) {
|
||||
|
||||
GrPathCmd cmd = (GrPathCmd)iter.next(pts);
|
||||
switch (cmd) {
|
||||
case kMove_PathCmd:
|
||||
if (!first) {
|
||||
subpathVertCount[subpath] = vert-subpathBase;
|
||||
subpathBase = vert;
|
||||
++subpath;
|
||||
}
|
||||
*vert = pts[0];
|
||||
vert++;
|
||||
break;
|
||||
case kLine_PathCmd:
|
||||
*vert = pts[1];
|
||||
vert++;
|
||||
break;
|
||||
case kQuadratic_PathCmd: {
|
||||
GrPathUtils::generateQuadraticPoints(pts[0], pts[1], pts[2],
|
||||
tolSqd, &vert,
|
||||
GrPathUtils::quadraticPointCount(pts, tol));
|
||||
break;
|
||||
}
|
||||
case kCubic_PathCmd: {
|
||||
GrPathUtils::generateCubicPoints(pts[0], pts[1], pts[2], pts[3],
|
||||
tolSqd, &vert,
|
||||
GrPathUtils::cubicPointCount(pts, tol));
|
||||
break;
|
||||
}
|
||||
case kClose_PathCmd:
|
||||
break;
|
||||
case kEnd_PathCmd:
|
||||
subpathVertCount[subpath] = vert-subpathBase;
|
||||
++subpath; // this could be only in debug
|
||||
goto FINISHED;
|
||||
}
|
||||
first = false;
|
||||
}
|
||||
}
|
||||
FINISHED:
|
||||
GrAssert(subpath == subpathCnt);
|
||||
GrAssert((vert - base) <= maxPts);
|
||||
|
||||
if (translate) {
|
||||
int count = vert - base;
|
||||
for (int i = 0; i < count; i++) {
|
||||
base[i].offset(translate->fX, translate->fY);
|
||||
}
|
||||
}
|
||||
|
||||
// if we're stenciling we will follow with a pass that draws
|
||||
// a bounding rect to set the color. We're stenciling when
|
||||
// passCount > 1.
|
||||
const int& boundVertexStart = maxPts;
|
||||
GrPoint* boundsVerts = base + boundVertexStart;
|
||||
if (lastPassIsBounds) {
|
||||
GrRect bounds;
|
||||
if (reverse) {
|
||||
GrAssert(NULL != target->getRenderTarget());
|
||||
// draw over the whole world.
|
||||
bounds.setLTRB(0, 0,
|
||||
GrIntToScalar(target->getRenderTarget()->width()),
|
||||
GrIntToScalar(target->getRenderTarget()->height()));
|
||||
GrMatrix vmi;
|
||||
if (target->getViewInverse(&vmi)) {
|
||||
vmi.mapRect(&bounds);
|
||||
}
|
||||
} else {
|
||||
bounds.setBounds((GrPoint*)base, vert - base);
|
||||
}
|
||||
boundsVerts[0].setRectFan(bounds.fLeft, bounds.fTop, bounds.fRight,
|
||||
bounds.fBottom);
|
||||
}
|
||||
|
||||
{
|
||||
SK_TRACE_EVENT1("GrDefaultPathRenderer::onDrawPath::renderPasses",
|
||||
"verts", SkStringPrintf("%i", vert - base).c_str());
|
||||
for (int p = 0; p < passCount; ++p) {
|
||||
target->setDrawFace(drawFace[p]);
|
||||
fTarget->setDrawFace(drawFace[p]);
|
||||
if (NULL != passes[p]) {
|
||||
target->setStencil(*passes[p]);
|
||||
fTarget->setStencil(*passes[p]);
|
||||
}
|
||||
|
||||
if (lastPassIsBounds && (p == passCount-1)) {
|
||||
if (!colorWritesWereDisabled) {
|
||||
target->disableState(GrDrawTarget::kNoColorWrites_StateBit);
|
||||
fTarget->disableState(GrDrawTarget::kNoColorWrites_StateBit);
|
||||
}
|
||||
target->drawNonIndexed(kTriangleFan_PrimitiveType,
|
||||
boundVertexStart, 4);
|
||||
|
||||
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();
|
||||
}
|
||||
GrDrawTarget::AutoGeometryPush agp(fTarget);
|
||||
fTarget->drawSimpleRect(bounds, NULL, stages);
|
||||
} else {
|
||||
if (passCount > 1) {
|
||||
target->enableState(GrDrawTarget::kNoColorWrites_StateBit);
|
||||
fTarget->enableState(GrDrawTarget::kNoColorWrites_StateBit);
|
||||
}
|
||||
int baseVertex = 0;
|
||||
for (int sp = 0; sp < subpathCnt; ++sp) {
|
||||
target->drawNonIndexed(type,
|
||||
baseVertex,
|
||||
subpathVertCount[sp]);
|
||||
baseVertex += subpathVertCount[sp];
|
||||
for (int sp = 0; sp < fSubpathCount; ++sp) {
|
||||
fTarget->drawNonIndexed(type, baseVertex,
|
||||
fSubpathVertCount[sp]);
|
||||
baseVertex += fSubpathVertCount[sp];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GrDefaultPathRenderer::drawPath(GrDrawTarget* target,
|
||||
GrDrawTarget::StageBitfield stages,
|
||||
const GrPath& path,
|
||||
GrPathFill fill,
|
||||
const GrPoint* translate) {
|
||||
this->onDrawPath(target, stages, path, fill, translate, false);
|
||||
void GrDefaultPathRenderer::drawPath(GrDrawTarget::StageBitfield stages) {
|
||||
this->onDrawPath(stages, false);
|
||||
}
|
||||
|
||||
void GrDefaultPathRenderer::drawPathToStencil(GrDrawTarget* target,
|
||||
const GrPath& path,
|
||||
GrPathFill fill,
|
||||
const GrPoint* translate) {
|
||||
GrAssert(kInverseEvenOdd_PathFill != fill);
|
||||
GrAssert(kInverseWinding_PathFill != fill);
|
||||
this->onDrawPath(target, 0, path, fill, translate, true);
|
||||
void GrDefaultPathRenderer::drawPathToStencil() {
|
||||
GrAssert(kInverseEvenOdd_PathFill != fFill);
|
||||
GrAssert(kInverseWinding_PathFill != fFill);
|
||||
this->onDrawPath(0, true);
|
||||
}
|
||||
|
@ -33,7 +33,7 @@ typedef void (*TESSCB)();
|
||||
// limit the allowable vertex range to approximately half of the representable
|
||||
// IEEE exponent in order to avoid overflow when doing multiplies between
|
||||
// vertex components,
|
||||
const float kMaxVertexValue = 1e18;
|
||||
const float kMaxVertexValue = 1e18f;
|
||||
|
||||
static inline GrDrawTarget::Edge computeEdge(const GrPoint& p,
|
||||
const GrPoint& q,
|
||||
@ -352,16 +352,12 @@ static size_t computeEdgesAndIntersect(const GrMatrix& matrix,
|
||||
return edges->count();
|
||||
}
|
||||
|
||||
void GrTesselatedPathRenderer::drawPath(GrDrawTarget* target,
|
||||
GrDrawTarget::StageBitfield stages,
|
||||
const GrPath& path,
|
||||
GrPathFill fill,
|
||||
const GrPoint* translate) {
|
||||
GrDrawTarget::AutoStateRestore asr(target);
|
||||
void GrTesselatedPathRenderer::drawPath(GrDrawTarget::StageBitfield stages) {
|
||||
GrDrawTarget::AutoStateRestore asr(fTarget);
|
||||
// face culling doesn't make sense here
|
||||
GrAssert(GrDrawTarget::kBoth_DrawFace == target->getDrawFace());
|
||||
GrAssert(GrDrawTarget::kBoth_DrawFace == fTarget->getDrawFace());
|
||||
|
||||
GrMatrix viewM = target->getViewMatrix();
|
||||
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();
|
||||
@ -377,7 +373,7 @@ void GrTesselatedPathRenderer::drawPath(GrDrawTarget* target,
|
||||
GrScalar tolSqd = GrMul(tol, tol);
|
||||
|
||||
int subpathCnt;
|
||||
int maxPts = GrPathUtils::worstCasePointCount(path, &subpathCnt, tol);
|
||||
int maxPts = GrPathUtils::worstCasePointCount(*fPath, &subpathCnt, tol);
|
||||
|
||||
GrVertexLayout layout = 0;
|
||||
for (int s = 0; s < GrDrawTarget::kNumStages; ++s) {
|
||||
@ -386,7 +382,7 @@ void GrTesselatedPathRenderer::drawPath(GrDrawTarget* target,
|
||||
}
|
||||
}
|
||||
|
||||
bool inverted = IsFillInverted(fill);
|
||||
bool inverted = IsFillInverted(fFill);
|
||||
if (inverted) {
|
||||
maxPts += 4;
|
||||
subpathCnt++;
|
||||
@ -402,7 +398,7 @@ void GrTesselatedPathRenderer::drawPath(GrDrawTarget* target,
|
||||
SkAutoSTMalloc<8, uint16_t> subpathVertCount(subpathCnt);
|
||||
|
||||
GrPoint pts[4];
|
||||
SkPath::Iter iter(path, false);
|
||||
SkPath::Iter iter(*fPath, false);
|
||||
|
||||
bool first = true;
|
||||
int subpath = 0;
|
||||
@ -444,20 +440,20 @@ void GrTesselatedPathRenderer::drawPath(GrDrawTarget* target,
|
||||
first = false;
|
||||
}
|
||||
FINISHED:
|
||||
if (translate) {
|
||||
if (0 != fTranslate.fX || 0 != fTranslate.fY) {
|
||||
for (int i = 0; i < vert - base; i++) {
|
||||
base[i].offset(translate->fX, translate->fY);
|
||||
base[i].offset(fTranslate.fX, fTranslate.fY);
|
||||
}
|
||||
}
|
||||
|
||||
if (inverted) {
|
||||
GrRect bounds;
|
||||
GrAssert(NULL != target->getRenderTarget());
|
||||
GrAssert(NULL != fTarget->getRenderTarget());
|
||||
bounds.setLTRB(0, 0,
|
||||
GrIntToScalar(target->getRenderTarget()->width()),
|
||||
GrIntToScalar(target->getRenderTarget()->height()));
|
||||
GrIntToScalar(fTarget->getRenderTarget()->width()),
|
||||
GrIntToScalar(fTarget->getRenderTarget()->height()));
|
||||
GrMatrix vmi;
|
||||
if (target->getViewInverse(&vmi)) {
|
||||
if (fTarget->getViewInverse(&vmi)) {
|
||||
vmi.mapRect(&bounds);
|
||||
}
|
||||
*vert++ = GrPoint::Make(bounds.fLeft, bounds.fTop);
|
||||
@ -476,22 +472,22 @@ FINISHED:
|
||||
return;
|
||||
}
|
||||
|
||||
if (subpathCnt == 1 && !inverted && path.isConvex()) {
|
||||
if (target->isAntialiasState()) {
|
||||
if (subpathCnt == 1 && !inverted && fPath->isConvex()) {
|
||||
if (fTarget->isAntialiasState()) {
|
||||
GrEdgeArray edges;
|
||||
GrMatrix inverse, matrix = target->getViewMatrix();
|
||||
target->getViewInverse(&inverse);
|
||||
GrMatrix inverse, matrix = fTarget->getViewMatrix();
|
||||
fTarget->getViewInverse(&inverse);
|
||||
|
||||
count = computeEdgesAndIntersect(matrix, inverse, base, count, &edges, 0.0f);
|
||||
size_t maxEdges = target->getMaxEdges();
|
||||
size_t maxEdges = fTarget->getMaxEdges();
|
||||
if (count == 0) {
|
||||
return;
|
||||
}
|
||||
if (count <= maxEdges) {
|
||||
// All edges fit; upload all edges and draw all verts as a fan
|
||||
target->setVertexSourceToArray(layout, base, count);
|
||||
target->setEdgeAAData(&edges[0], count);
|
||||
target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, count);
|
||||
fTarget->setVertexSourceToArray(layout, base, count);
|
||||
fTarget->setEdgeAAData(&edges[0], count);
|
||||
fTarget->drawNonIndexed(kTriangleFan_PrimitiveType, 0, count);
|
||||
} else {
|
||||
// Upload "maxEdges" edges and verts at a time, and draw as
|
||||
// separate fans
|
||||
@ -499,26 +495,26 @@ FINISHED:
|
||||
edges[i] = edges[0];
|
||||
base[i] = base[0];
|
||||
int size = GR_CT_MIN(count - i, maxEdges);
|
||||
target->setVertexSourceToArray(layout, &base[i], size);
|
||||
target->setEdgeAAData(&edges[i], size);
|
||||
target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, size);
|
||||
fTarget->setVertexSourceToArray(layout, &base[i], size);
|
||||
fTarget->setEdgeAAData(&edges[i], size);
|
||||
fTarget->drawNonIndexed(kTriangleFan_PrimitiveType, 0, size);
|
||||
}
|
||||
}
|
||||
target->setEdgeAAData(NULL, 0);
|
||||
fTarget->setEdgeAAData(NULL, 0);
|
||||
} else {
|
||||
target->setVertexSourceToArray(layout, base, count);
|
||||
target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, count);
|
||||
fTarget->setVertexSourceToArray(layout, base, count);
|
||||
fTarget->drawNonIndexed(kTriangleFan_PrimitiveType, 0, count);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (target->isAntialiasState()) {
|
||||
if (fTarget->isAntialiasState()) {
|
||||
// Run the tesselator once to get the boundaries.
|
||||
GrBoundaryTess btess(count, fill_type_to_glu_winding_rule(fill));
|
||||
GrBoundaryTess btess(count, fill_type_to_glu_winding_rule(fFill));
|
||||
btess.addVertices(base, subpathVertCount, subpathCnt);
|
||||
|
||||
GrMatrix inverse, matrix = target->getViewMatrix();
|
||||
if (!target->getViewInverse(&inverse)) {
|
||||
GrMatrix inverse, matrix = fTarget->getViewMatrix();
|
||||
if (!fTarget->getViewInverse(&inverse)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -553,7 +549,7 @@ FINISHED:
|
||||
}
|
||||
|
||||
// Draw the resulting polys and upload their edge data.
|
||||
target->enableState(GrDrawTarget::kEdgeAAConcave_StateBit);
|
||||
fTarget->enableState(GrDrawTarget::kEdgeAAConcave_StateBit);
|
||||
const GrPointArray& vertices = ptess.vertices();
|
||||
const GrIndexArray& indices = ptess.indices();
|
||||
const GrDrawTarget::Edge* edges = ptess.edges();
|
||||
@ -586,23 +582,23 @@ FINISHED:
|
||||
tri_edges[t++] = edge4;
|
||||
tri_edges[t++] = edge5;
|
||||
}
|
||||
target->setEdgeAAData(&tri_edges[0], t);
|
||||
target->setVertexSourceToArray(layout, &tri_verts[0], 3);
|
||||
target->drawNonIndexed(kTriangles_PrimitiveType, 0, 3);
|
||||
fTarget->setEdgeAAData(&tri_edges[0], t);
|
||||
fTarget->setVertexSourceToArray(layout, &tri_verts[0], 3);
|
||||
fTarget->drawNonIndexed(kTriangles_PrimitiveType, 0, 3);
|
||||
}
|
||||
target->setEdgeAAData(NULL, 0);
|
||||
target->disableState(GrDrawTarget::kEdgeAAConcave_StateBit);
|
||||
fTarget->setEdgeAAData(NULL, 0);
|
||||
fTarget->disableState(GrDrawTarget::kEdgeAAConcave_StateBit);
|
||||
return;
|
||||
}
|
||||
|
||||
GrPolygonTess ptess(count, fill_type_to_glu_winding_rule(fill));
|
||||
GrPolygonTess ptess(count, fill_type_to_glu_winding_rule(fFill));
|
||||
ptess.addVertices(base, subpathVertCount, subpathCnt);
|
||||
const GrPointArray& vertices = ptess.vertices();
|
||||
const GrIndexArray& indices = ptess.indices();
|
||||
if (indices.count() > 0) {
|
||||
target->setVertexSourceToArray(layout, vertices.begin(), vertices.count());
|
||||
target->setIndexSourceToArray(indices.begin(), indices.count());
|
||||
target->drawIndexed(kTriangles_PrimitiveType,
|
||||
fTarget->setVertexSourceToArray(layout, vertices.begin(), vertices.count());
|
||||
fTarget->setIndexSourceToArray(indices.begin(), indices.count());
|
||||
fTarget->drawIndexed(kTriangles_PrimitiveType,
|
||||
0,
|
||||
0,
|
||||
vertices.count(),
|
||||
@ -610,16 +606,12 @@ FINISHED:
|
||||
}
|
||||
}
|
||||
|
||||
bool GrTesselatedPathRenderer::canDrawPath(const GrDrawTarget* target,
|
||||
const SkPath& path,
|
||||
bool GrTesselatedPathRenderer::canDrawPath(const SkPath& path,
|
||||
GrPathFill fill) const {
|
||||
return kHairLine_PathFill != fill;
|
||||
}
|
||||
|
||||
void GrTesselatedPathRenderer::drawPathToStencil(GrDrawTarget* target,
|
||||
const SkPath& path,
|
||||
GrPathFill fill,
|
||||
const GrPoint* translate) {
|
||||
void GrTesselatedPathRenderer::drawPathToStencil() {
|
||||
GrAlwaysAssert(!"multipass stencil should not be needed");
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user