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();
|
void drawClipIntoStencil();
|
||||||
|
|
||||||
GrPathRenderer* getPathRenderer(const GrDrawTarget*, const GrPath&, GrPathFill);
|
GrPathRenderer* getPathRenderer(const GrPath&, GrPathFill);
|
||||||
|
|
||||||
struct OffscreenRecord;
|
struct OffscreenRecord;
|
||||||
|
|
||||||
|
@ -18,57 +18,46 @@
|
|||||||
#define GrPathRenderer_DEFINED
|
#define GrPathRenderer_DEFINED
|
||||||
|
|
||||||
#include "GrDrawTarget.h"
|
#include "GrDrawTarget.h"
|
||||||
|
#include "SkTemplates.h"
|
||||||
|
|
||||||
class SkPath;
|
class SkPath;
|
||||||
struct GrPoint;
|
struct GrPoint;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Base class for drawing paths into a GrDrawTarget.
|
* 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 {
|
class GR_API GrPathRenderer : public GrRefCnt {
|
||||||
public:
|
public:
|
||||||
GrPathRenderer(void);
|
GrPathRenderer(void);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if this path renderer is able to render the path.
|
* Returns true if this path renderer is able to render the path.
|
||||||
* Returning false allows the caller to fallback to another path renderer.
|
* 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 path The path to draw
|
||||||
* @param fill The fill rule to use
|
* @param fill The fill rule to use
|
||||||
*
|
*
|
||||||
* @return true if the path can be drawn by this object, false otherwise.
|
* @return true if the path can be drawn by this object, false otherwise.
|
||||||
*/
|
*/
|
||||||
virtual bool canDrawPath(const GrDrawTarget* target, const SkPath& path,
|
virtual bool canDrawPath(const SkPath& path, GrPathFill fill) const = 0;
|
||||||
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;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* For complex clips Gr uses the stencil buffer. The path renderer must be
|
* 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
|
* 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
|
* itself may require the stencil buffer to resolve the path fill rule.
|
||||||
* function queries whether the path render needs its own stencil
|
* This function queries whether the path render needs its own stencil
|
||||||
* pass. If this returns false then drawPath() should not modify the
|
* 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 target target that the path will be rendered to
|
||||||
* @param path the path that will be drawn
|
* @param path the path that will be drawn
|
||||||
@ -85,7 +74,59 @@ public:
|
|||||||
GrPathFill fill) const { return false; }
|
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
|
* are already initialized to zero. Fill will always be either
|
||||||
* kWinding_PathFill or kEvenOdd_PathFill.
|
* kWinding_PathFill or kEvenOdd_PathFill.
|
||||||
*
|
*
|
||||||
@ -95,27 +136,11 @@ public:
|
|||||||
* The default implementation assumes the path filling algorithm doesn't
|
* The default implementation assumes the path filling algorithm doesn't
|
||||||
* require a separate stencil pass and so crashes.
|
* require a separate stencil pass and so crashes.
|
||||||
*
|
*
|
||||||
*
|
* Only called between setPath / clearPath.
|
||||||
* @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).
|
|
||||||
*/
|
*/
|
||||||
virtual void drawPathToStencil(GrDrawTarget* target,
|
virtual void drawPathToStencil() {
|
||||||
const SkPath& path,
|
|
||||||
GrPathFill fill,
|
|
||||||
const GrPoint* translate) {
|
|
||||||
GrCrash("Unexpected call to 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
|
* This is called to install a custom path renderer in every GrContext at
|
||||||
@ -134,8 +159,56 @@ public:
|
|||||||
fCurveTolerance = SkScalarMul(fCurveTolerance, multiplier);
|
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:
|
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;
|
GrScalar fCurveTolerance;
|
||||||
|
const SkPath* fPath;
|
||||||
|
GrDrawTarget* fTarget;
|
||||||
|
GrPathFill fFill;
|
||||||
|
GrPoint fTranslate;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
@ -151,35 +224,37 @@ public:
|
|||||||
GrDefaultPathRenderer(bool separateStencilSupport,
|
GrDefaultPathRenderer(bool separateStencilSupport,
|
||||||
bool stencilWrapOpsSupport);
|
bool stencilWrapOpsSupport);
|
||||||
|
|
||||||
virtual bool canDrawPath(const GrDrawTarget* target,
|
virtual bool canDrawPath(const SkPath& path,
|
||||||
const SkPath& path,
|
|
||||||
GrPathFill fill) const { return true; }
|
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,
|
virtual bool requiresStencilPass(const GrDrawTarget* target,
|
||||||
const SkPath& path,
|
const SkPath& path,
|
||||||
GrPathFill fill) const;
|
GrPathFill fill) const;
|
||||||
virtual void drawPathToStencil(GrDrawTarget* target,
|
|
||||||
const SkPath& path,
|
virtual void drawPath(GrDrawTarget::StageBitfield stages);
|
||||||
GrPathFill fill,
|
virtual void drawPathToStencil();
|
||||||
const GrPoint* translate);
|
|
||||||
|
protected:
|
||||||
|
virtual void pathWillClear();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void onDrawPath(GrDrawTarget* target,
|
void onDrawPath(GrDrawTarget::StageBitfield stages, bool stencilOnly);
|
||||||
GrDrawTarget::StageBitfield stages,
|
|
||||||
const SkPath& path,
|
void createGeom(GrScalar srcSpaceTolSqd,
|
||||||
GrPathFill fill,
|
GrDrawTarget::StageBitfield stages);
|
||||||
const GrPoint* translate,
|
|
||||||
bool stencilOnly);
|
|
||||||
|
|
||||||
bool fSeparateStencil;
|
bool fSeparateStencil;
|
||||||
bool fStencilWrapOps;
|
bool fStencilWrapOps;
|
||||||
|
|
||||||
|
int fSubpathCount;
|
||||||
|
SkAutoSTMalloc<8, uint16_t> fSubpathVertCount;
|
||||||
|
GrScalar fPreviousSrcTol;
|
||||||
|
GrDrawTarget::StageBitfield fPreviousStages;
|
||||||
|
|
||||||
|
|
||||||
typedef GrPathRenderer INHERITED;
|
typedef GrPathRenderer INHERITED;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -39,7 +39,8 @@
|
|||||||
#define GrIntToScalar(a) SkIntToScalar(a)
|
#define GrIntToScalar(a) SkIntToScalar(a)
|
||||||
#define GrScalarHalf(a) SkScalarHalf(a)
|
#define GrScalarHalf(a) SkScalarHalf(a)
|
||||||
#define GrScalarAve(a,b) SkScalarAve(a,b)
|
#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 GrScalarDiv(a,b) SkScalarDiv(a, b)
|
||||||
#define GrScalarToFloat(a) SkScalarToFloat(a)
|
#define GrScalarToFloat(a) SkScalarToFloat(a)
|
||||||
#define GrFloatToScalar(a) SkScalarToFloat(a)
|
#define GrFloatToScalar(a) SkScalarToFloat(a)
|
||||||
|
@ -23,22 +23,14 @@ class GrTesselatedPathRenderer : public GrPathRenderer {
|
|||||||
public:
|
public:
|
||||||
GrTesselatedPathRenderer();
|
GrTesselatedPathRenderer();
|
||||||
|
|
||||||
virtual void drawPath(GrDrawTarget* target,
|
virtual void drawPath(GrDrawTarget::StageBitfield stages);
|
||||||
GrDrawTarget::StageBitfield stages,
|
virtual bool canDrawPath(const GrPath& path,
|
||||||
const GrPath& path,
|
|
||||||
GrPathFill fill,
|
|
||||||
const GrPoint* translate);
|
|
||||||
virtual bool canDrawPath(const GrDrawTarget* target,
|
|
||||||
const GrPath& path,
|
|
||||||
GrPathFill fill) const;
|
GrPathFill fill) const;
|
||||||
|
|
||||||
virtual bool requiresStencilPass(const GrDrawTarget* target,
|
virtual bool requiresStencilPass(const GrDrawTarget* target,
|
||||||
const GrPath& path,
|
const GrPath& path,
|
||||||
GrPathFill fill) const { return false; }
|
GrPathFill fill) const { return false; }
|
||||||
virtual void drawPathToStencil(GrDrawTarget* target,
|
virtual void drawPathToStencil();
|
||||||
const GrPath& path,
|
|
||||||
GrPathFill fill,
|
|
||||||
const GrPoint* translate);
|
|
||||||
virtual bool supportsAA(GrDrawTarget* target,
|
virtual bool supportsAA(GrDrawTarget* target,
|
||||||
const GrPath& path,
|
const GrPath& path,
|
||||||
GrPathFill fill);
|
GrPathFill fill);
|
||||||
|
@ -715,7 +715,7 @@ void GrContext::doOffscreenAAPass2(GrDrawTarget* target,
|
|||||||
OffscreenRecord* record) {
|
OffscreenRecord* record) {
|
||||||
SK_TRACE_EVENT0("GrContext::doOffscreenAAPass2");
|
SK_TRACE_EVENT0("GrContext::doOffscreenAAPass2");
|
||||||
GrAssert(NULL != record->fEntry0);
|
GrAssert(NULL != record->fEntry0);
|
||||||
|
GrDrawTarget::AutoGeometryPush agp(target);
|
||||||
GrIRect tileRect;
|
GrIRect tileRect;
|
||||||
tileRect.fLeft = boundRect.fLeft + tileX * record->fTileSizeX;
|
tileRect.fLeft = boundRect.fLeft + tileX * record->fTileSizeX;
|
||||||
tileRect.fTop = boundRect.fTop + tileY * record->fTileSizeY,
|
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) {
|
GrPathFill fill, const GrPoint* translate) {
|
||||||
|
|
||||||
GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
|
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) &&
|
if (!pr->supportsAA(target, path, fill) &&
|
||||||
this->doOffscreenAA(target, paint, kHairLine_PathFill == 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 tx = 0; tx < record.fTileCountX; ++tx) {
|
||||||
for (int ty = 0; ty < record.fTileCountY; ++ty) {
|
for (int ty = 0; ty < record.fTileCountY; ++ty) {
|
||||||
this->setupOffscreenAAPass1(target, bound, tx, ty, &record);
|
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->doOffscreenAAPass2(target, paint, bound, tx, ty, &record);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this->cleanupOffscreenAA(target, pr, &record);
|
this->cleanupOffscreenAA(target, pr, &record);
|
||||||
if (IsFillInverted(fill) && bound != clipIBounds) {
|
if (IsFillInverted(fill) && bound != clipIBounds) {
|
||||||
int stageMask = paint.getActiveStageMask();
|
|
||||||
GrDrawTarget::AutoDeviceCoordDraw adcd(target, stageMask);
|
GrDrawTarget::AutoDeviceCoordDraw adcd(target, stageMask);
|
||||||
GrRect rect;
|
GrRect rect;
|
||||||
if (clipIBounds.fTop < bound.fTop) {
|
if (clipIBounds.fTop < bound.fTop) {
|
||||||
@ -1389,11 +1390,8 @@ void GrContext::drawPath(const GrPaint& paint, const GrPath& path,
|
|||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
pr->drawPath(stageMask);
|
||||||
GrDrawTarget::StageBitfield enabledStages = paint.getActiveStageMask();
|
|
||||||
|
|
||||||
pr->drawPath(target, enabledStages, path, fill, translate);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
@ -1690,14 +1688,13 @@ const GrIndexBuffer* GrContext::getQuadIndexBuffer() const {
|
|||||||
return fGpu->getQuadIndexBuffer();
|
return fGpu->getQuadIndexBuffer();
|
||||||
}
|
}
|
||||||
|
|
||||||
GrPathRenderer* GrContext::getPathRenderer(const GrDrawTarget* target,
|
GrPathRenderer* GrContext::getPathRenderer(const GrPath& path,
|
||||||
const GrPath& path,
|
|
||||||
GrPathFill fill) {
|
GrPathFill fill) {
|
||||||
if (NULL != fCustomPathRenderer &&
|
if (NULL != fCustomPathRenderer &&
|
||||||
fCustomPathRenderer->canDrawPath(target, path, fill)) {
|
fCustomPathRenderer->canDrawPath(path, fill)) {
|
||||||
return fCustomPathRenderer;
|
return fCustomPathRenderer;
|
||||||
} else {
|
} else {
|
||||||
GrAssert(fDefaultPathRenderer.canDrawPath(target, path, fill));
|
GrAssert(fDefaultPathRenderer.canDrawPath(path, fill));
|
||||||
return &fDefaultPathRenderer;
|
return &fDefaultPathRenderer;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,9 +24,8 @@
|
|||||||
#include "GrPathRenderer.h"
|
#include "GrPathRenderer.h"
|
||||||
|
|
||||||
// probably makes no sense for this to be less than a page
|
// probably makes no sense for this to be less than a page
|
||||||
static const size_t VERTEX_POOL_VB_SIZE = 1 << 12;
|
static const size_t VERTEX_POOL_VB_SIZE = 1 << 18;
|
||||||
static const int VERTEX_POOL_VB_COUNT = 1;
|
static const int VERTEX_POOL_VB_COUNT = 4;
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
@ -454,6 +453,7 @@ bool GrGpu::setupClipAndFlushState(GrPrimitiveType type) {
|
|||||||
// with the existing clip.
|
// with the existing clip.
|
||||||
for (int c = firstElement; c < count; ++c) {
|
for (int c = firstElement; c < count; ++c) {
|
||||||
GrPathFill fill;
|
GrPathFill fill;
|
||||||
|
bool fillInverted;
|
||||||
// enabled at bottom of loop
|
// enabled at bottom of loop
|
||||||
this->disableState(kModifyStencilClip_StateBit);
|
this->disableState(kModifyStencilClip_StateBit);
|
||||||
|
|
||||||
@ -465,16 +465,20 @@ bool GrGpu::setupClipAndFlushState(GrPrimitiveType type) {
|
|||||||
|
|
||||||
GrPathRenderer* pr = NULL;
|
GrPathRenderer* pr = NULL;
|
||||||
const GrPath* clipPath = NULL;
|
const GrPath* clipPath = NULL;
|
||||||
|
GrPathRenderer::AutoClearPath arp;
|
||||||
if (kRect_ClipType == clip.getElementType(c)) {
|
if (kRect_ClipType == clip.getElementType(c)) {
|
||||||
canRenderDirectToStencil = true;
|
canRenderDirectToStencil = true;
|
||||||
fill = kEvenOdd_PathFill;
|
fill = kEvenOdd_PathFill;
|
||||||
|
fillInverted = false;
|
||||||
} else {
|
} else {
|
||||||
fill = clip.getPathFill(c);
|
fill = clip.getPathFill(c);
|
||||||
|
fillInverted = IsFillInverted(fill);
|
||||||
|
fill = NonInvertedFill(fill);
|
||||||
clipPath = &clip.getPath(c);
|
clipPath = &clip.getPath(c);
|
||||||
pr = this->getClipPathRenderer(*clipPath, NonInvertedFill(fill));
|
pr = this->getClipPathRenderer(*clipPath, fill);
|
||||||
canRenderDirectToStencil =
|
canRenderDirectToStencil =
|
||||||
!pr->requiresStencilPass(this, *clipPath,
|
!pr->requiresStencilPass(this, *clipPath, fill);
|
||||||
NonInvertedFill(fill));
|
arp.set(pr, this, clipPath, fill, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
GrSetOp op = firstElement == c ? kReplace_SetOp : clip.getOp(c);
|
GrSetOp op = firstElement == c ? kReplace_SetOp : clip.getOp(c);
|
||||||
@ -489,7 +493,7 @@ bool GrGpu::setupClipAndFlushState(GrPrimitiveType type) {
|
|||||||
GrStencilSettings::GetClipPasses(op,
|
GrStencilSettings::GetClipPasses(op,
|
||||||
canRenderDirectToStencil,
|
canRenderDirectToStencil,
|
||||||
clipBit,
|
clipBit,
|
||||||
IsFillInverted(fill),
|
fillInverted,
|
||||||
&passes, stencilSettings);
|
&passes, stencilSettings);
|
||||||
|
|
||||||
// draw the element to the client stencil bits if necessary
|
// draw the element to the client stencil bits if necessary
|
||||||
@ -509,12 +513,9 @@ bool GrGpu::setupClipAndFlushState(GrPrimitiveType type) {
|
|||||||
} else {
|
} else {
|
||||||
if (canRenderDirectToStencil) {
|
if (canRenderDirectToStencil) {
|
||||||
this->setStencil(gDrawToStencil);
|
this->setStencil(gDrawToStencil);
|
||||||
pr->drawPath(this, 0, *clipPath, NonInvertedFill(fill),
|
pr->drawPath(0);
|
||||||
NULL);
|
|
||||||
} else {
|
} else {
|
||||||
pr->drawPathToStencil(this, *clipPath,
|
pr->drawPathToStencil();
|
||||||
NonInvertedFill(fill),
|
|
||||||
NULL);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -530,8 +531,7 @@ bool GrGpu::setupClipAndFlushState(GrPrimitiveType type) {
|
|||||||
this->drawSimpleRect(clip.getRect(c), NULL, 0);
|
this->drawSimpleRect(clip.getRect(c), NULL, 0);
|
||||||
} else {
|
} else {
|
||||||
SET_RANDOM_COLOR
|
SET_RANDOM_COLOR
|
||||||
GrAssert(!IsFillInverted(fill));
|
pr->drawPath(0);
|
||||||
pr->drawPath(this, 0, *clipPath, fill, NULL);
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
SET_RANDOM_COLOR
|
SET_RANDOM_COLOR
|
||||||
@ -558,7 +558,7 @@ bool GrGpu::setupClipAndFlushState(GrPrimitiveType type) {
|
|||||||
GrPathRenderer* GrGpu::getClipPathRenderer(const GrPath& path,
|
GrPathRenderer* GrGpu::getClipPathRenderer(const GrPath& path,
|
||||||
GrPathFill fill) {
|
GrPathFill fill) {
|
||||||
if (NULL != fClientPathRenderer &&
|
if (NULL != fClientPathRenderer &&
|
||||||
fClientPathRenderer->canDrawPath(this, path, fill)) {
|
fClientPathRenderer->canDrawPath(path, fill)) {
|
||||||
return fClientPathRenderer;
|
return fClientPathRenderer;
|
||||||
} else {
|
} else {
|
||||||
if (NULL == fDefaultPathRenderer) {
|
if (NULL == fDefaultPathRenderer) {
|
||||||
@ -566,7 +566,7 @@ GrPathRenderer* GrGpu::getClipPathRenderer(const GrPath& path,
|
|||||||
new GrDefaultPathRenderer(this->supportsTwoSidedStencil(),
|
new GrDefaultPathRenderer(this->supportsTwoSidedStencil(),
|
||||||
this->supportsStencilWrapOps());
|
this->supportsStencilWrapOps());
|
||||||
}
|
}
|
||||||
GrAssert(fDefaultPathRenderer->canDrawPath(this, path, fill));
|
GrAssert(fDefaultPathRenderer->canDrawPath(path, fill));
|
||||||
return fDefaultPathRenderer;
|
return fDefaultPathRenderer;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,15 +11,49 @@
|
|||||||
#include SK_USER_TRACE_INCLUDE_FILE
|
#include SK_USER_TRACE_INCLUDE_FILE
|
||||||
|
|
||||||
GrPathRenderer::GrPathRenderer()
|
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,
|
GrDefaultPathRenderer::GrDefaultPathRenderer(bool separateStencilSupport,
|
||||||
bool stencilWrapOpsSupport)
|
bool stencilWrapOpsSupport)
|
||||||
: fSeparateStencil(separateStencilSupport)
|
: 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);
|
return !single_pass_path(*target, path, fill);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GrDefaultPathRenderer::onDrawPath(GrDrawTarget* target,
|
void GrDefaultPathRenderer::pathWillClear() {
|
||||||
GrDrawTarget::StageBitfield stages,
|
fSubpathVertCount.realloc(0);
|
||||||
const GrPath& path,
|
fTarget->resetVertexSource();
|
||||||
GrPathFill fill,
|
fPreviousSrcTol = -GR_Scalar1;
|
||||||
const GrPoint* translate,
|
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) {
|
bool stencilOnly) {
|
||||||
|
|
||||||
SK_TRACE_EVENT1("GrDefaultPathRenderer::onDrawPath",
|
SK_TRACE_EVENT1("GrDefaultPathRenderer::onDrawPath",
|
||||||
"points", SkStringPrintf("%i", path.countPoints()).c_str());
|
"points", SkStringPrintf("%i", path.countPoints()).c_str());
|
||||||
|
|
||||||
GrDrawTarget::AutoStateRestore asr(target);
|
GrMatrix viewM = fTarget->getViewMatrix();
|
||||||
bool colorWritesWereDisabled = target->isColorWriteDisabled();
|
|
||||||
// face culling doesn't make sense here
|
|
||||||
GrAssert(GrDrawTarget::kBoth_DrawFace == target->getDrawFace());
|
|
||||||
|
|
||||||
GrMatrix viewM = target->getViewMatrix();
|
|
||||||
// In order to tesselate the path we get a bound on how much the matrix can
|
// In order to tesselate the path we get a bound on how much the matrix can
|
||||||
// stretch when mapping to screen coordinates.
|
// stretch when mapping to screen coordinates.
|
||||||
GrScalar stretch = viewM.getMaxStretch();
|
GrScalar stretch = viewM.getMaxStretch();
|
||||||
@ -216,28 +334,25 @@ void GrDefaultPathRenderer::onDrawPath(GrDrawTarget* target,
|
|||||||
} else {
|
} else {
|
||||||
tol = GrScalarDiv(tol, stretch);
|
tol = GrScalarDiv(tol, stretch);
|
||||||
}
|
}
|
||||||
GrScalar tolSqd = GrMul(tol, tol);
|
// 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
|
||||||
int subpathCnt;
|
// us to change the vertex layout after reserveVertexSpace(). We won't
|
||||||
int maxPts = GrPathUtils::worstCasePointCount(path, &subpathCnt, tol);
|
// actually change the vertex data when the layout changes since all the
|
||||||
|
// stages reference the positions (rather than having separate tex coords)
|
||||||
GrVertexLayout layout = 0;
|
// and we don't ever have per-vert colors. In practice our call sites
|
||||||
for (int s = 0; s < GrDrawTarget::kNumStages; ++s) {
|
// won't change the stages in use inside a setPath / removePath pair. But
|
||||||
if ((1 << s) & stages) {
|
// it is a silly limitation of the GrDrawTarget design that should be fixed.
|
||||||
layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(s);
|
if (tol != fPreviousSrcTol ||
|
||||||
}
|
stages != fPreviousStages) {
|
||||||
|
this->createGeom(tol, stages);
|
||||||
}
|
}
|
||||||
|
|
||||||
// add 4 to hold the bounding rect
|
GrAssert(NULL != fTarget);
|
||||||
GrDrawTarget::AutoReleaseGeometry arg(target, layout, maxPts + 4, 0);
|
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;
|
GrPrimitiveType type;
|
||||||
int passCount = 0;
|
int passCount = 0;
|
||||||
const GrStencilSettings* passes[3];
|
const GrStencilSettings* passes[3];
|
||||||
@ -245,7 +360,7 @@ void GrDefaultPathRenderer::onDrawPath(GrDrawTarget* target,
|
|||||||
bool reverse = false;
|
bool reverse = false;
|
||||||
bool lastPassIsBounds;
|
bool lastPassIsBounds;
|
||||||
|
|
||||||
if (kHairLine_PathFill == fill) {
|
if (kHairLine_PathFill == fFill) {
|
||||||
type = kLineStrip_PrimitiveType;
|
type = kLineStrip_PrimitiveType;
|
||||||
passCount = 1;
|
passCount = 1;
|
||||||
if (stencilOnly) {
|
if (stencilOnly) {
|
||||||
@ -257,7 +372,7 @@ void GrDefaultPathRenderer::onDrawPath(GrDrawTarget* target,
|
|||||||
drawFace[0] = GrDrawTarget::kBoth_DrawFace;
|
drawFace[0] = GrDrawTarget::kBoth_DrawFace;
|
||||||
} else {
|
} else {
|
||||||
type = kTriangleFan_PrimitiveType;
|
type = kTriangleFan_PrimitiveType;
|
||||||
if (single_pass_path(*target, path, fill)) {
|
if (single_pass_path(*fTarget, *fPath, fFill)) {
|
||||||
passCount = 1;
|
passCount = 1;
|
||||||
if (stencilOnly) {
|
if (stencilOnly) {
|
||||||
passes[0] = &gDirectToStencil;
|
passes[0] = &gDirectToStencil;
|
||||||
@ -267,7 +382,7 @@ void GrDefaultPathRenderer::onDrawPath(GrDrawTarget* target,
|
|||||||
drawFace[0] = GrDrawTarget::kBoth_DrawFace;
|
drawFace[0] = GrDrawTarget::kBoth_DrawFace;
|
||||||
lastPassIsBounds = false;
|
lastPassIsBounds = false;
|
||||||
} else {
|
} else {
|
||||||
switch (fill) {
|
switch (fFill) {
|
||||||
case kInverseEvenOdd_PathFill:
|
case kInverseEvenOdd_PathFill:
|
||||||
reverse = true;
|
reverse = true;
|
||||||
// fallthrough
|
// fallthrough
|
||||||
@ -327,140 +442,62 @@ void GrDefaultPathRenderer::onDrawPath(GrDrawTarget* target,
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
GrAssert(!"Unknown path fill!");
|
GrAssert(!"Unknown path fFill!");
|
||||||
return;
|
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",
|
SK_TRACE_EVENT1("GrDefaultPathRenderer::onDrawPath::renderPasses",
|
||||||
"verts", SkStringPrintf("%i", vert - base).c_str());
|
"verts", SkStringPrintf("%i", vert - base).c_str());
|
||||||
for (int p = 0; p < passCount; ++p) {
|
for (int p = 0; p < passCount; ++p) {
|
||||||
target->setDrawFace(drawFace[p]);
|
fTarget->setDrawFace(drawFace[p]);
|
||||||
if (NULL != passes[p]) {
|
if (NULL != passes[p]) {
|
||||||
target->setStencil(*passes[p]);
|
fTarget->setStencil(*passes[p]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lastPassIsBounds && (p == passCount-1)) {
|
if (lastPassIsBounds && (p == passCount-1)) {
|
||||||
if (!colorWritesWereDisabled) {
|
if (!colorWritesWereDisabled) {
|
||||||
target->disableState(GrDrawTarget::kNoColorWrites_StateBit);
|
fTarget->disableState(GrDrawTarget::kNoColorWrites_StateBit);
|
||||||
}
|
}
|
||||||
target->drawNonIndexed(kTriangleFan_PrimitiveType,
|
GrRect bounds;
|
||||||
boundVertexStart, 4);
|
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 {
|
} else {
|
||||||
if (passCount > 1) {
|
if (passCount > 1) {
|
||||||
target->enableState(GrDrawTarget::kNoColorWrites_StateBit);
|
fTarget->enableState(GrDrawTarget::kNoColorWrites_StateBit);
|
||||||
}
|
}
|
||||||
int baseVertex = 0;
|
int baseVertex = 0;
|
||||||
for (int sp = 0; sp < subpathCnt; ++sp) {
|
for (int sp = 0; sp < fSubpathCount; ++sp) {
|
||||||
target->drawNonIndexed(type,
|
fTarget->drawNonIndexed(type, baseVertex,
|
||||||
baseVertex,
|
fSubpathVertCount[sp]);
|
||||||
subpathVertCount[sp]);
|
baseVertex += fSubpathVertCount[sp];
|
||||||
baseVertex += subpathVertCount[sp];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GrDefaultPathRenderer::drawPath(GrDrawTarget* target,
|
void GrDefaultPathRenderer::drawPath(GrDrawTarget::StageBitfield stages) {
|
||||||
GrDrawTarget::StageBitfield stages,
|
this->onDrawPath(stages, false);
|
||||||
const GrPath& path,
|
|
||||||
GrPathFill fill,
|
|
||||||
const GrPoint* translate) {
|
|
||||||
this->onDrawPath(target, stages, path, fill, translate, false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GrDefaultPathRenderer::drawPathToStencil(GrDrawTarget* target,
|
void GrDefaultPathRenderer::drawPathToStencil() {
|
||||||
const GrPath& path,
|
GrAssert(kInverseEvenOdd_PathFill != fFill);
|
||||||
GrPathFill fill,
|
GrAssert(kInverseWinding_PathFill != fFill);
|
||||||
const GrPoint* translate) {
|
this->onDrawPath(0, true);
|
||||||
GrAssert(kInverseEvenOdd_PathFill != fill);
|
|
||||||
GrAssert(kInverseWinding_PathFill != fill);
|
|
||||||
this->onDrawPath(target, 0, path, fill, translate, true);
|
|
||||||
}
|
}
|
||||||
|
@ -33,7 +33,7 @@ typedef void (*TESSCB)();
|
|||||||
// limit the allowable vertex range to approximately half of the representable
|
// limit the allowable vertex range to approximately half of the representable
|
||||||
// IEEE exponent in order to avoid overflow when doing multiplies between
|
// IEEE exponent in order to avoid overflow when doing multiplies between
|
||||||
// vertex components,
|
// vertex components,
|
||||||
const float kMaxVertexValue = 1e18;
|
const float kMaxVertexValue = 1e18f;
|
||||||
|
|
||||||
static inline GrDrawTarget::Edge computeEdge(const GrPoint& p,
|
static inline GrDrawTarget::Edge computeEdge(const GrPoint& p,
|
||||||
const GrPoint& q,
|
const GrPoint& q,
|
||||||
@ -352,16 +352,12 @@ static size_t computeEdgesAndIntersect(const GrMatrix& matrix,
|
|||||||
return edges->count();
|
return edges->count();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GrTesselatedPathRenderer::drawPath(GrDrawTarget* target,
|
void GrTesselatedPathRenderer::drawPath(GrDrawTarget::StageBitfield stages) {
|
||||||
GrDrawTarget::StageBitfield stages,
|
GrDrawTarget::AutoStateRestore asr(fTarget);
|
||||||
const GrPath& path,
|
|
||||||
GrPathFill fill,
|
|
||||||
const GrPoint* translate) {
|
|
||||||
GrDrawTarget::AutoStateRestore asr(target);
|
|
||||||
// face culling doesn't make sense here
|
// 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
|
// In order to tesselate the path we get a bound on how much the matrix can
|
||||||
// stretch when mapping to screen coordinates.
|
// stretch when mapping to screen coordinates.
|
||||||
GrScalar stretch = viewM.getMaxStretch();
|
GrScalar stretch = viewM.getMaxStretch();
|
||||||
@ -377,7 +373,7 @@ void GrTesselatedPathRenderer::drawPath(GrDrawTarget* target,
|
|||||||
GrScalar tolSqd = GrMul(tol, tol);
|
GrScalar tolSqd = GrMul(tol, tol);
|
||||||
|
|
||||||
int subpathCnt;
|
int subpathCnt;
|
||||||
int maxPts = GrPathUtils::worstCasePointCount(path, &subpathCnt, tol);
|
int maxPts = GrPathUtils::worstCasePointCount(*fPath, &subpathCnt, tol);
|
||||||
|
|
||||||
GrVertexLayout layout = 0;
|
GrVertexLayout layout = 0;
|
||||||
for (int s = 0; s < GrDrawTarget::kNumStages; ++s) {
|
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) {
|
if (inverted) {
|
||||||
maxPts += 4;
|
maxPts += 4;
|
||||||
subpathCnt++;
|
subpathCnt++;
|
||||||
@ -402,7 +398,7 @@ void GrTesselatedPathRenderer::drawPath(GrDrawTarget* target,
|
|||||||
SkAutoSTMalloc<8, uint16_t> subpathVertCount(subpathCnt);
|
SkAutoSTMalloc<8, uint16_t> subpathVertCount(subpathCnt);
|
||||||
|
|
||||||
GrPoint pts[4];
|
GrPoint pts[4];
|
||||||
SkPath::Iter iter(path, false);
|
SkPath::Iter iter(*fPath, false);
|
||||||
|
|
||||||
bool first = true;
|
bool first = true;
|
||||||
int subpath = 0;
|
int subpath = 0;
|
||||||
@ -444,20 +440,20 @@ void GrTesselatedPathRenderer::drawPath(GrDrawTarget* target,
|
|||||||
first = false;
|
first = false;
|
||||||
}
|
}
|
||||||
FINISHED:
|
FINISHED:
|
||||||
if (translate) {
|
if (0 != fTranslate.fX || 0 != fTranslate.fY) {
|
||||||
for (int i = 0; i < vert - base; i++) {
|
for (int i = 0; i < vert - base; i++) {
|
||||||
base[i].offset(translate->fX, translate->fY);
|
base[i].offset(fTranslate.fX, fTranslate.fY);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (inverted) {
|
if (inverted) {
|
||||||
GrRect bounds;
|
GrRect bounds;
|
||||||
GrAssert(NULL != target->getRenderTarget());
|
GrAssert(NULL != fTarget->getRenderTarget());
|
||||||
bounds.setLTRB(0, 0,
|
bounds.setLTRB(0, 0,
|
||||||
GrIntToScalar(target->getRenderTarget()->width()),
|
GrIntToScalar(fTarget->getRenderTarget()->width()),
|
||||||
GrIntToScalar(target->getRenderTarget()->height()));
|
GrIntToScalar(fTarget->getRenderTarget()->height()));
|
||||||
GrMatrix vmi;
|
GrMatrix vmi;
|
||||||
if (target->getViewInverse(&vmi)) {
|
if (fTarget->getViewInverse(&vmi)) {
|
||||||
vmi.mapRect(&bounds);
|
vmi.mapRect(&bounds);
|
||||||
}
|
}
|
||||||
*vert++ = GrPoint::Make(bounds.fLeft, bounds.fTop);
|
*vert++ = GrPoint::Make(bounds.fLeft, bounds.fTop);
|
||||||
@ -476,22 +472,22 @@ FINISHED:
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (subpathCnt == 1 && !inverted && path.isConvex()) {
|
if (subpathCnt == 1 && !inverted && fPath->isConvex()) {
|
||||||
if (target->isAntialiasState()) {
|
if (fTarget->isAntialiasState()) {
|
||||||
GrEdgeArray edges;
|
GrEdgeArray edges;
|
||||||
GrMatrix inverse, matrix = target->getViewMatrix();
|
GrMatrix inverse, matrix = fTarget->getViewMatrix();
|
||||||
target->getViewInverse(&inverse);
|
fTarget->getViewInverse(&inverse);
|
||||||
|
|
||||||
count = computeEdgesAndIntersect(matrix, inverse, base, count, &edges, 0.0f);
|
count = computeEdgesAndIntersect(matrix, inverse, base, count, &edges, 0.0f);
|
||||||
size_t maxEdges = target->getMaxEdges();
|
size_t maxEdges = fTarget->getMaxEdges();
|
||||||
if (count == 0) {
|
if (count == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (count <= maxEdges) {
|
if (count <= maxEdges) {
|
||||||
// All edges fit; upload all edges and draw all verts as a fan
|
// All edges fit; upload all edges and draw all verts as a fan
|
||||||
target->setVertexSourceToArray(layout, base, count);
|
fTarget->setVertexSourceToArray(layout, base, count);
|
||||||
target->setEdgeAAData(&edges[0], count);
|
fTarget->setEdgeAAData(&edges[0], count);
|
||||||
target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, count);
|
fTarget->drawNonIndexed(kTriangleFan_PrimitiveType, 0, count);
|
||||||
} else {
|
} else {
|
||||||
// Upload "maxEdges" edges and verts at a time, and draw as
|
// Upload "maxEdges" edges and verts at a time, and draw as
|
||||||
// separate fans
|
// separate fans
|
||||||
@ -499,26 +495,26 @@ FINISHED:
|
|||||||
edges[i] = edges[0];
|
edges[i] = edges[0];
|
||||||
base[i] = base[0];
|
base[i] = base[0];
|
||||||
int size = GR_CT_MIN(count - i, maxEdges);
|
int size = GR_CT_MIN(count - i, maxEdges);
|
||||||
target->setVertexSourceToArray(layout, &base[i], size);
|
fTarget->setVertexSourceToArray(layout, &base[i], size);
|
||||||
target->setEdgeAAData(&edges[i], size);
|
fTarget->setEdgeAAData(&edges[i], size);
|
||||||
target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, size);
|
fTarget->drawNonIndexed(kTriangleFan_PrimitiveType, 0, size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
target->setEdgeAAData(NULL, 0);
|
fTarget->setEdgeAAData(NULL, 0);
|
||||||
} else {
|
} else {
|
||||||
target->setVertexSourceToArray(layout, base, count);
|
fTarget->setVertexSourceToArray(layout, base, count);
|
||||||
target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, count);
|
fTarget->drawNonIndexed(kTriangleFan_PrimitiveType, 0, count);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (target->isAntialiasState()) {
|
if (fTarget->isAntialiasState()) {
|
||||||
// Run the tesselator once to get the boundaries.
|
// 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);
|
btess.addVertices(base, subpathVertCount, subpathCnt);
|
||||||
|
|
||||||
GrMatrix inverse, matrix = target->getViewMatrix();
|
GrMatrix inverse, matrix = fTarget->getViewMatrix();
|
||||||
if (!target->getViewInverse(&inverse)) {
|
if (!fTarget->getViewInverse(&inverse)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -553,7 +549,7 @@ FINISHED:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Draw the resulting polys and upload their edge data.
|
// 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 GrPointArray& vertices = ptess.vertices();
|
||||||
const GrIndexArray& indices = ptess.indices();
|
const GrIndexArray& indices = ptess.indices();
|
||||||
const GrDrawTarget::Edge* edges = ptess.edges();
|
const GrDrawTarget::Edge* edges = ptess.edges();
|
||||||
@ -586,23 +582,23 @@ FINISHED:
|
|||||||
tri_edges[t++] = edge4;
|
tri_edges[t++] = edge4;
|
||||||
tri_edges[t++] = edge5;
|
tri_edges[t++] = edge5;
|
||||||
}
|
}
|
||||||
target->setEdgeAAData(&tri_edges[0], t);
|
fTarget->setEdgeAAData(&tri_edges[0], t);
|
||||||
target->setVertexSourceToArray(layout, &tri_verts[0], 3);
|
fTarget->setVertexSourceToArray(layout, &tri_verts[0], 3);
|
||||||
target->drawNonIndexed(kTriangles_PrimitiveType, 0, 3);
|
fTarget->drawNonIndexed(kTriangles_PrimitiveType, 0, 3);
|
||||||
}
|
}
|
||||||
target->setEdgeAAData(NULL, 0);
|
fTarget->setEdgeAAData(NULL, 0);
|
||||||
target->disableState(GrDrawTarget::kEdgeAAConcave_StateBit);
|
fTarget->disableState(GrDrawTarget::kEdgeAAConcave_StateBit);
|
||||||
return;
|
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);
|
ptess.addVertices(base, subpathVertCount, subpathCnt);
|
||||||
const GrPointArray& vertices = ptess.vertices();
|
const GrPointArray& vertices = ptess.vertices();
|
||||||
const GrIndexArray& indices = ptess.indices();
|
const GrIndexArray& indices = ptess.indices();
|
||||||
if (indices.count() > 0) {
|
if (indices.count() > 0) {
|
||||||
target->setVertexSourceToArray(layout, vertices.begin(), vertices.count());
|
fTarget->setVertexSourceToArray(layout, vertices.begin(), vertices.count());
|
||||||
target->setIndexSourceToArray(indices.begin(), indices.count());
|
fTarget->setIndexSourceToArray(indices.begin(), indices.count());
|
||||||
target->drawIndexed(kTriangles_PrimitiveType,
|
fTarget->drawIndexed(kTriangles_PrimitiveType,
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
vertices.count(),
|
vertices.count(),
|
||||||
@ -610,16 +606,12 @@ FINISHED:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GrTesselatedPathRenderer::canDrawPath(const GrDrawTarget* target,
|
bool GrTesselatedPathRenderer::canDrawPath(const SkPath& path,
|
||||||
const SkPath& path,
|
|
||||||
GrPathFill fill) const {
|
GrPathFill fill) const {
|
||||||
return kHairLine_PathFill != fill;
|
return kHairLine_PathFill != fill;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GrTesselatedPathRenderer::drawPathToStencil(GrDrawTarget* target,
|
void GrTesselatedPathRenderer::drawPathToStencil() {
|
||||||
const SkPath& path,
|
|
||||||
GrPathFill fill,
|
|
||||||
const GrPoint* translate) {
|
|
||||||
GrAlwaysAssert(!"multipass stencil should not be needed");
|
GrAlwaysAssert(!"multipass stencil should not be needed");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user