Modifications to GrPatherRenderer(Chain) interfaces to support clip mask manager.

R=robertphillips@google.com
Review URL: https://codereview.appspot.com/6904069

git-svn-id: http://skia.googlecode.com/svn/trunk@6741 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
bsalomon@google.com 2012-12-10 19:10:17 +00:00
parent 6f92862028
commit 45a15f551b
21 changed files with 364 additions and 240 deletions

View File

@ -25,6 +25,7 @@
'<(skia_include_path)/gpu/GrKey.h',
'<(skia_include_path)/gpu/GrNoncopyable.h',
'<(skia_include_path)/gpu/GrPaint.h',
'<(skia_include_path)/gpu/GrPathRendererChain.h',
'<(skia_include_path)/gpu/GrPoint.h',
'<(skia_include_path)/gpu/GrRect.h',
'<(skia_include_path)/gpu/GrRefCnt.h',
@ -85,7 +86,6 @@
'<(skia_src_path)/gpu/GrPath.cpp',
'<(skia_src_path)/gpu/GrPath.h',
'<(skia_src_path)/gpu/GrPathRendererChain.cpp',
'<(skia_src_path)/gpu/GrPathRendererChain.h',
'<(skia_src_path)/gpu/GrPathRenderer.cpp',
'<(skia_src_path)/gpu/GrPathRenderer.h',
'<(skia_src_path)/gpu/GrPathUtils.cpp',

View File

@ -116,10 +116,21 @@ class SkTCopyOnFirstWrite {
public:
SkTCopyOnFirstWrite(const T& initial) : fObj(&initial) {}
// Constructor for delayed initialization.
SkTCopyOnFirstWrite() : fObj(NULL) {}
// Should only be called once, and only if the default constructor was used.
void init(const T& initial) {
SkASSERT(NULL == fObj);
SkASSERT(!fLazy.isValid());
fObj = &initial;
}
/**
* Returns a writable T*. The first time this is called the initial object is cloned.
*/
T* writable() {
SkASSERT(NULL != fObj);
if (!fLazy.isValid()) {
fLazy.set(*fObj);
fObj = fLazy.get();

View File

@ -15,6 +15,7 @@
#include "GrClipData.h"
#include "SkMatrix.h"
#include "GrPaint.h"
#include "GrPathRendererChain.h"
// not strictly needed but requires WK change in LayerTextureUpdaterCanvas to
// remove.
#include "GrRenderTarget.h"
@ -32,7 +33,6 @@ class GrIndexBuffer;
class GrIndexBufferAllocPool;
class GrInOrderDrawBuffer;
class GrPathRenderer;
class GrPathRendererChain;
class GrResourceEntry;
class GrResourceCache;
class GrStencilBuffer;
@ -851,11 +851,13 @@ public:
void addStencilBuffer(GrStencilBuffer* sb);
GrStencilBuffer* findStencilBuffer(int width, int height, int sampleCnt);
GrPathRenderer* getPathRenderer(const SkPath& path,
const SkStroke& stroke,
const GrDrawTarget* target,
bool antiAlias,
bool allowSW);
GrPathRenderer* getPathRenderer(
const SkPath& path,
const SkStroke& stroke,
const GrDrawTarget* target,
bool allowSW,
GrPathRendererChain::DrawType drawType = GrPathRendererChain::kColor_DrawType,
GrPathRendererChain::StencilSupport* stencilSupport = NULL);
#if GR_CACHE_STATS
void printCacheStats() const;

View File

@ -0,0 +1,83 @@
/*
* Copyright 2011 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef GrPathRendererChain_DEFINED
#define GrPathRendererChain_DEFINED
#include "GrRefCnt.h"
#include "SkTArray.h"
class GrContext;
class GrDrawTarget;
class GrPathRenderer;
class SkPath;
class SkStroke;
/**
* Keeps track of an ordered list of path renderers. When a path needs to be
* drawn this list is scanned to find the most preferred renderer. To add your
* path renderer to the list implement the GrPathRenderer::AddPathRenderers
* function.
*/
class GrPathRendererChain : public SkRefCnt {
public:
// See comments in GrPathRenderer.h
enum StencilSupport {
kNoSupport_StencilSupport,
kStencilOnly_StencilSupport,
kNoRestriction_StencilSupport,
};
SK_DECLARE_INST_COUNT(GrPathRendererChain)
GrPathRendererChain(GrContext* context);
~GrPathRendererChain();
// takes a ref and unrefs in destructor
GrPathRenderer* addPathRenderer(GrPathRenderer* pr);
/** Documents how the caller plans to use a GrPathRenderer to draw a path. It affects the PR
returned by getPathRenderer */
enum DrawType {
kColor_DrawType, // draw to the color buffer, no AA
kColorAntiAlias_DrawType, // draw to color buffer, with partial coverage AA
kStencilOnly_DrawType, // draw just to the stencil buffer
kStencilAndColor_DrawType, // draw the stencil and color buffer, no AA
kStencilAndColorAntiAlias_DrawType // draw the stencil and color buffer, with partial
// coverage AA.
};
/** Returns a GrPathRenderer compatible with the request if one is available. If the caller
is drawing the path to the stencil buffer then stencilSupport can be used to determine
whether the path can be rendered with arbitrary stencil rules or not. See comments on
StencilSupport in GrPathRenderer.h. */
GrPathRenderer* getPathRenderer(const SkPath& path,
const SkStroke& stroke,
const GrDrawTarget* target,
DrawType drawType,
StencilSupport* stencilSupport);
private:
GrPathRendererChain();
void init();
enum {
kPreAllocCount = 8,
};
bool fInit;
GrContext* fOwner;
SkSTArray<kPreAllocCount, GrPathRenderer*, true> fChain;
typedef SkRefCnt INHERITED;
};
#endif

View File

@ -12,17 +12,12 @@
#include "GrAAConvexPathRenderer.h"
#include "GrSoftwarePathRenderer.h"
void GrPathRenderer::AddPathRenderers(GrContext* ctx,
GrPathRendererChain::UsageFlags flags,
GrPathRendererChain* chain) {
void GrPathRenderer::AddPathRenderers(GrContext* ctx, GrPathRendererChain* chain) {
if (GrPathRenderer* pr = GrStencilAndCoverPathRenderer::Create(ctx)) {
chain->addPathRenderer(pr)->unref();
}
if (!(GrPathRendererChain::kNonAAOnly_UsageFlag & flags)) {
if (GrPathRenderer* pr = GrAAHairLinePathRenderer::Create(ctx)) {
chain->addPathRenderer(pr)->unref();
}
chain->addPathRenderer(SkNEW(GrAAConvexPathRenderer))->unref();
if (GrPathRenderer* pr = GrAAHairLinePathRenderer::Create(ctx)) {
chain->addPathRenderer(pr)->unref();
}
chain->addPathRenderer(SkNEW(GrAAConvexPathRenderer))->unref();
}

View File

@ -70,7 +70,11 @@ bool path_needs_SW_renderer(GrContext* context,
path.writable()->toggleInverseFillType();
}
// last (false) parameter disallows use of the SW path renderer
return NULL == context->getPathRenderer(*path, stroke, gpu, doAA, false);
GrPathRendererChain::DrawType type = doAA ?
GrPathRendererChain::kColorAntiAlias_DrawType :
GrPathRendererChain::kColor_DrawType;
return NULL == context->getPathRenderer(*path, stroke, gpu, false, type);
}
}
@ -313,10 +317,14 @@ bool GrClipMaskManager::drawClipShape(GrTexture* target, const SkClipStack::Elem
}
SkStroke stroke;
stroke.setDoFill(true);
GrPathRendererChain::DrawType type = element->isAA() ?
GrPathRendererChain::kColorAntiAlias_DrawType :
GrPathRendererChain::kColor_DrawType;
GrPathRenderer* pr = this->getContext()->getPathRenderer(*path,
stroke,
fGpu,
element->isAA(), false);
false,
type);
if (NULL == pr) {
return false;
}
@ -580,10 +588,9 @@ bool GrClipMaskManager::createStencilClipMask(InitialState initialState,
drawState->setState(GrDrawState::kHWAntialias_StateBit, element->isAA());
}
// Can the clip element be drawn directly to the stencil buffer
// with a non-inverted fill rule without extra passes to
// resolve in/out status?
bool canRenderDirectToStencil = false;
// This will be used to determine whether the clip shape can be rendered into the
// stencil with arbitrary stencil settings.
GrPathRenderer::StencilSupport stencilSupport;
SkStroke stroke;
stroke.setDoFill(true);
@ -591,29 +598,37 @@ bool GrClipMaskManager::createStencilClipMask(InitialState initialState,
SkRegion::Op op = element->getOp();
GrPathRenderer* pr = NULL;
SkPath clipPath;
SkTCopyOnFirstWrite<SkPath> clipPath;
if (Element::kRect_Type == element->getType()) {
canRenderDirectToStencil = true;
stencilSupport = GrPathRenderer::kNoRestriction_StencilSupport;
fill = SkPath::kEvenOdd_FillType;
fillInverted = false;
} else {
GrAssert(Element::kPath_Type == element->getType());
clipPath = element->getPath();
fill = clipPath.getFillType();
fillInverted = clipPath.isInverseFillType();
fill = SkPath::NonInverseFill(fill);
clipPath.setFillType(fill);
pr = this->getContext()->getPathRenderer(clipPath, stroke, fGpu, false, true);
clipPath.init(element->getPath());
fill = clipPath->getFillType();
fillInverted = clipPath->isInverseFillType();
if (fillInverted) {
clipPath.writable()->toggleInverseFillType();
fill = clipPath->getFillType();
}
pr = this->getContext()->getPathRenderer(*clipPath,
stroke,
fGpu,
false,
GrPathRendererChain::kStencilOnly_DrawType,
&stencilSupport);
if (NULL == pr) {
fGpu->setClip(oldClipData);
return false;
}
canRenderDirectToStencil = !pr->requiresStencilPass(clipPath, stroke, fGpu);
}
int passes;
GrStencilSettings stencilSettings[GrStencilSettings::kMaxStencilClipPasses];
bool canRenderDirectToStencil =
GrPathRenderer::kNoRestriction_StencilSupport == stencilSupport;
bool canDrawDirectToClip; // Given the renderer, the element,
// fill rule, and set operation can
// we render the element directly to
@ -642,9 +657,9 @@ bool GrClipMaskManager::createStencilClipMask(InitialState initialState,
GrAssert(Element::kPath_Type == element->getType());
if (canRenderDirectToStencil) {
*drawState->stencil() = gDrawToStencil;
pr->drawPath(clipPath, stroke, fGpu, false);
pr->drawPath(*clipPath, stroke, fGpu, false);
} else {
pr->drawPathToStencil(clipPath, stroke, fGpu);
pr->stencilPath(*clipPath, stroke, fGpu);
}
}
}
@ -661,7 +676,7 @@ bool GrClipMaskManager::createStencilClipMask(InitialState initialState,
} else {
GrAssert(Element::kPath_Type == element->getType());
SET_RANDOM_COLOR
pr->drawPath(clipPath, stroke, fGpu, false);
pr->drawPath(*clipPath, stroke, fGpu, false);
}
} else {
SET_RANDOM_COLOR

View File

@ -1112,7 +1112,10 @@ void GrContext::internalDrawPath(const GrPaint& paint, const SkPath& path, const
prAA = false;
}
GrPathRenderer* pr = this->getPathRenderer(path, stroke, target, prAA, true);
GrPathRendererChain::DrawType type = prAA ? GrPathRendererChain::kColorAntiAlias_DrawType :
GrPathRendererChain::kColor_DrawType;
GrPathRenderer* pr = this->getPathRenderer(path, stroke, target, true, type);
if (NULL == pr) {
#if GR_DEBUG
GrPrintf("Unable to find path renderer compatible with path.\n");
@ -1620,24 +1623,24 @@ GrDrawTarget* GrContext::prepareToDraw(const GrPaint* paint, BufferedDraw buffer
GrPathRenderer* GrContext::getPathRenderer(const SkPath& path,
const SkStroke& stroke,
const GrDrawTarget* target,
bool antiAlias,
bool allowSW) {
bool allowSW,
GrPathRendererChain::DrawType drawType,
GrPathRendererChain::StencilSupport* stencilSupport) {
if (NULL == fPathRendererChain) {
fPathRendererChain =
SkNEW_ARGS(GrPathRendererChain,
(this, GrPathRendererChain::kNone_UsageFlag));
fPathRendererChain = SkNEW_ARGS(GrPathRendererChain, (this));
}
GrPathRenderer* pr = fPathRendererChain->getPathRenderer(path,
stroke,
target,
antiAlias);
drawType,
stencilSupport);
if (NULL == pr && allowSW) {
if (NULL == fSoftwarePathRenderer) {
fSoftwarePathRenderer = SkNEW_ARGS(GrSoftwarePathRenderer, (this));
}
pr = fSoftwarePathRenderer;
}

View File

@ -162,10 +162,15 @@ static inline bool single_pass_path(const SkPath& path, const SkStroke& stroke)
#endif
}
bool GrDefaultPathRenderer::requiresStencilPass(const SkPath& path,
const SkStroke& stroke,
const GrDrawTarget* target) const {
return !single_pass_path(path, stroke);
GrPathRenderer::StencilSupport GrDefaultPathRenderer::onGetStencilSupport(
const SkPath& path,
const SkStroke& stroke,
const GrDrawTarget*) const {
if (single_pass_path(path, stroke)) {
return GrPathRenderer::kNoRestriction_StencilSupport;
} else {
return GrPathRenderer::kStencilOnly_StencilSupport;
}
}
static inline void append_countour_edge_indices(bool hairLine,
@ -508,9 +513,9 @@ bool GrDefaultPathRenderer::onDrawPath(const SkPath& path,
false);
}
void GrDefaultPathRenderer::drawPathToStencil(const SkPath& path,
const SkStroke& stroke,
GrDrawTarget* target) {
void GrDefaultPathRenderer::onStencilPath(const SkPath& path,
const SkStroke& stroke,
GrDrawTarget* target) {
GrAssert(SkPath::kInverseEvenOdd_FillType != path.getFillType());
GrAssert(SkPath::kInverseWinding_FillType != path.getFillType());
this->internalDrawPath(path, stroke, target, true);

View File

@ -12,48 +12,46 @@
#include "SkTemplates.h"
/**
* Subclass that renders the path using the stencil buffer to resolve fill
* rules (e.g. winding, even-odd)
* Subclass that renders the path using the stencil buffer to resolve fill rules
* (e.g. winding, even-odd)
*/
class GR_API GrDefaultPathRenderer : public GrPathRenderer {
public:
GrDefaultPathRenderer(bool separateStencilSupport,
bool stencilWrapOpsSupport);
GrDefaultPathRenderer(bool separateStencilSupport, bool stencilWrapOpsSupport);
virtual bool requiresStencilPass(const SkPath& path,
const SkStroke& stroke,
const GrDrawTarget* target) const SK_OVERRIDE;
virtual bool canDrawPath(const SkPath& path,
const SkStroke& stroke,
const GrDrawTarget* target,
virtual bool canDrawPath(const SkPath&,
const SkStroke&,
const GrDrawTarget*,
bool antiAlias) const SK_OVERRIDE;
virtual void drawPathToStencil(const SkPath& path,
const SkStroke& stroke,
GrDrawTarget* target) SK_OVERRIDE;
private:
virtual bool onDrawPath(const SkPath& path,
const SkStroke& stroke,
GrDrawTarget* target,
virtual StencilSupport onGetStencilSupport(const SkPath&,
const SkStroke&,
const GrDrawTarget*) const SK_OVERRIDE;
virtual bool onDrawPath(const SkPath&,
const SkStroke&,
GrDrawTarget*,
bool antiAlias) SK_OVERRIDE;
bool internalDrawPath(const SkPath& path,
const SkStroke& stroke,
GrDrawTarget* target,
virtual void onStencilPath(const SkPath&,
const SkStroke&,
GrDrawTarget*) SK_OVERRIDE;
bool internalDrawPath(const SkPath&,
const SkStroke&,
GrDrawTarget*,
bool stencilOnly);
bool createGeom(const SkPath& path,
const SkStroke& stroke,
bool createGeom(const SkPath&,
const SkStroke&,
SkScalar srcSpaceTol,
GrDrawTarget* target,
GrPrimitiveType* primType,
GrDrawTarget*,
GrPrimitiveType*,
int* vertexCnt,
int* indexCnt,
GrDrawTarget::AutoReleaseGeometry* arg);
GrDrawTarget::AutoReleaseGeometry*);
bool fSeparateStencil;
bool fStencilWrapOps;

View File

@ -12,72 +12,86 @@
#include "GrDrawTarget.h"
#include "GrPathRendererChain.h"
#include "GrStencil.h"
#include "SkStroke.h"
#include "SkTArray.h"
class SkPath;
class SkStroke;
struct GrPoint;
/**
* Base class for drawing paths into a GrDrawTarget.
*
* Derived classes can use stages GrPaint::kTotalStages through
* GrDrawState::kNumStages-1. The stages before GrPaint::kTotalStages
* are reserved for setting up the draw (i.e., textures and filter masks).
* Derived classes can use stages GrPaint::kTotalStages through GrDrawState::kNumStages-1. The
* stages before GrPaint::kTotalStages are reserved for setting up the draw (i.e., textures and
* filter masks).
*/
class GR_API GrPathRenderer : public GrRefCnt {
public:
SK_DECLARE_INST_COUNT(GrPathRenderer)
/**
* This is called to install custom path renderers in every GrContext at
* create time. The default implementation in GrCreatePathRenderer_none.cpp
* does not add any additional renderers. Link against another
* implementation to install your own. The first added is the most preferred
* path renderer, second is second most preferred, etc.
* This is called to install custom path renderers in every GrContext at create time. The
* default implementation in GrCreatePathRenderer_none.cpp does not add any additional
* renderers. Link against another implementation to install your own. The first added is the
* most preferred path renderer, second is second most preferred, etc.
*
* @param context the context that will use the path renderer
* @param flags flags indicating how path renderers will be used
* @param prChain the chain to add path renderers to.
*/
static void AddPathRenderers(GrContext* context,
GrPathRendererChain::UsageFlags flags,
GrPathRendererChain* prChain);
static void AddPathRenderers(GrContext* context, GrPathRendererChain* prChain);
GrPathRenderer();
/**
* 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
* 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 is passed as a param in case the answer depends upon draw state.
* A caller may wish to use a path renderer to draw a path into the stencil buffer. However,
* the path renderer itself may require use of the stencil buffer. Also a path renderer may
* use a GrEffect coverage stage that sets coverage to zero to eliminate pixels that are covered
* by bounding geometry but outside the path. These exterior pixels would still be rendered into
* the stencil.
*
* A GrPathRenderer can provide three levels of support for stenciling paths:
* 1) kNoRestriction: This is the most general. The caller sets up the GrDrawState on the target
* and calls drawPath(). The path is rendered exactly as the draw state
* indicates including support for simultaneous color and stenciling with
* arbitrary stenciling rules. Pixels partially covered by AA paths are
* affected by the stencil settings.
* 2) kStencilOnly: The path renderer cannot apply arbitrary stencil rules nor shade and stencil
* simultaneously. The path renderer does support the stencilPath() function
* which performs no color writes and writes a non-zero stencil value to pixels
* covered by the path.
* 3) kNoSupport: This path renderer cannot be used to stencil the path.
*/
typedef GrPathRendererChain::StencilSupport StencilSupport;
static const StencilSupport kNoSupport_StencilSupport =
GrPathRendererChain::kNoSupport_StencilSupport;
static const StencilSupport kStencilOnly_StencilSupport =
GrPathRendererChain::kStencilOnly_StencilSupport;
static const StencilSupport kNoRestriction_StencilSupport =
GrPathRendererChain::kNoRestriction_StencilSupport;
/**
* This function is to get the stencil support for a particular path. The path's fill must
* not be an inverse type.
*
* @param target target that the path will be rendered to
* @param path the path that will be drawn
* @param stroke the stroke information (width, join, cap).
*
* @return false if this path renderer can generate interior-only fragments
* without changing the stencil settings on the target. If it
* returns true the drawPathToStencil will be used when rendering
* clips.
*/
virtual bool requiresStencilPass(const SkPath& path,
StencilSupport getStencilSupport(const SkPath& path,
const SkStroke& stroke,
const GrDrawTarget* target) const {
return false;
GrAssert(!path.isInverseFillType());
return this->onGetStencilSupport(path, stroke, target);
}
/**
* Returns true if this path renderer is able to render the path.
* Returning false allows the caller to fallback to another path renderer
* This function is called when searching for a path renderer capable of
* rendering a path.
* Returns true if this path renderer is able to render the path. Returning false allows the
* caller to fallback to another path renderer This function is called when searching for a path
* renderer capable of rendering a path.
*
* @param path The path to draw
* @param stroke The stroke information (width, join, cap)
@ -91,55 +105,72 @@ public:
const GrDrawTarget* target,
bool antiAlias) const = 0;
/**
* 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).
* Draws the path into the draw target. If getStencilSupport() would return kNoRestriction then
* the subclass must respect the stencil settings of the target's draw state.
*
* @param path the path to draw.
* @param stroke the stroke information (width, join, cap)
* @param target target that the path will be rendered to
* @param antiAlias true if anti-aliasing is required.
*/
virtual bool drawPath(const SkPath& path,
const SkStroke& stroke,
GrDrawTarget* target,
bool antiAlias) {
bool drawPath(const SkPath& path,
const SkStroke& stroke,
GrDrawTarget* target,
bool antiAlias) {
GrAssert(this->canDrawPath(path, stroke, target, antiAlias));
return this->onDrawPath(path, stroke, target, antiAlias);
}
/**
* Draws the path to the stencil buffer. Assume the writable stencil bits
* are already initialized to zero. Fill will always be either
* kWinding_FillType or kEvenOdd_FillType.
*
* Only called if requiresStencilPass returns true for the same combo of
* target, path, and fill. Never called with an inverse fill.
*
* The default implementation assumes the path filling algorithm doesn't
* require a separate stencil pass and so crashes.
*
*/
virtual void drawPathToStencil(const SkPath& path,
const SkStroke& stroke,
GrDrawTarget* target) {
GrCrash("Unexpected call to drawPathToStencil.");
}
protected:
/**
* Draws the path into the draw target.
* Draws the path to the stencil buffer. Assume the writable stencil bits are already
* initialized to zero. The pixels inside the path will have non-zero stencil values afterwards.
*
* @param path the path to draw.
* @param stroke the stroke information (width, join, cap)
* @param target target that the path will be rendered to
* @param antiAlias whether antialiasing is enabled or not.
*/
void stencilPath(const SkPath& path, const SkStroke& stroke, GrDrawTarget* target) {
GrAssert(kNoSupport_StencilSupport != this->getStencilSupport(path, stroke, target));
this->onStencilPath(path, stroke, target);
}
protected:
/**
* Subclass overrides if it has any limitations of stenciling support.
*/
virtual StencilSupport onGetStencilSupport(const SkPath&,
const SkStroke&,
const GrDrawTarget*) const {
return kNoRestriction_StencilSupport;
}
/**
* Subclass implementation of drawPath()
*/
virtual bool onDrawPath(const SkPath& path,
const SkStroke& stroke,
GrDrawTarget* target,
bool antiAlias) = 0;
/**
* Subclass implementation of stencilPath(). Subclass must override iff it ever returns
* kStencilOnly in onGetStencilSupport().
*/
virtual void onStencilPath(const SkPath& path, const SkStroke& stroke, GrDrawTarget* target) {
GrDrawTarget::AutoStateRestore asr(target, GrDrawTarget::kPreserve_ASRInit);
GrDrawState* drawState = target->drawState();
GR_STATIC_CONST_SAME_STENCIL(kIncrementStencil,
kReplace_StencilOp,
kReplace_StencilOp,
kAlways_StencilFunc,
0xffff,
0xffff,
0xffff);
drawState->setStencil(kIncrementStencil);
drawState->enableState(GrDrawState::kNoColorWrites_StateBit);
this->drawPath(path, stroke, target, false);
}
private:
typedef GrRefCnt INHERITED;

View File

@ -15,10 +15,9 @@
SK_DEFINE_INST_COUNT(GrPathRendererChain)
GrPathRendererChain::GrPathRendererChain(GrContext* context, UsageFlags flags)
GrPathRendererChain::GrPathRendererChain(GrContext* context)
: fInit(false)
, fOwner(context)
, fFlags(flags) {
, fOwner(context) {
}
GrPathRendererChain::~GrPathRendererChain() {
@ -36,12 +35,41 @@ GrPathRenderer* GrPathRendererChain::addPathRenderer(GrPathRenderer* pr) {
GrPathRenderer* GrPathRendererChain::getPathRenderer(const SkPath& path,
const SkStroke& stroke,
const GrDrawTarget* target,
bool antiAlias) {
DrawType drawType,
StencilSupport* stencilSupport) {
if (!fInit) {
this->init();
}
bool antiAlias = (kColorAntiAlias_DrawType == drawType ||
kStencilAndColorAntiAlias_DrawType == drawType);
GR_STATIC_ASSERT(GrPathRenderer::kNoSupport_StencilSupport <
GrPathRenderer::kStencilOnly_StencilSupport);
GR_STATIC_ASSERT(GrPathRenderer::kStencilOnly_StencilSupport <
GrPathRenderer::kNoRestriction_StencilSupport);
GrPathRenderer::StencilSupport minStencilSupport;
if (kStencilOnly_DrawType == drawType) {
minStencilSupport = GrPathRenderer::kStencilOnly_StencilSupport;
} else if (kStencilAndColor_DrawType == drawType ||
kStencilAndColorAntiAlias_DrawType == drawType) {
minStencilSupport = GrPathRenderer::kNoRestriction_StencilSupport;
} else {
minStencilSupport = GrPathRenderer::kNoSupport_StencilSupport;
}
for (int i = 0; i < fChain.count(); ++i) {
if (fChain[i]->canDrawPath(path, stroke, target, antiAlias)) {
if (GrPathRenderer::kNoSupport_StencilSupport != minStencilSupport) {
GrPathRenderer::StencilSupport support = fChain[i]->getStencilSupport(path,
stroke,
target);
if (support < minStencilSupport) {
continue;
} else if (NULL != stencilSupport) {
*stencilSupport = support;
}
}
return fChain[i];
}
}
@ -53,7 +81,7 @@ void GrPathRendererChain::init() {
GrGpu* gpu = fOwner->getGpu();
bool twoSided = gpu->getCaps().twoSidedStencilSupport();
bool wrapOp = gpu->getCaps().stencilWrapOpsSupport();
GrPathRenderer::AddPathRenderers(fOwner, fFlags, this);
GrPathRenderer::AddPathRenderers(fOwner, this);
this->addPathRenderer(SkNEW_ARGS(GrDefaultPathRenderer,
(twoSided, wrapOp)))->unref();
fInit = true;

View File

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

View File

@ -325,7 +325,7 @@ void reduced_stack_walker(const SkClipStack& stack,
++numAAElements;
}
// Intersecting an inverse shape is the same as differencing the non-inverse shape.
// Replacing with a inverse shape the same as setting initialState=kAllIn and
// Replacing with an inverse shape is the same as setting initialState=kAllIn and
// differencing the non-inverse shape.
bool isReplace = SkRegion::kReplace_Op == newElement->getOp();
if (newElement->isInverseFilled() &&

View File

@ -28,6 +28,13 @@ bool GrSoftwarePathRenderer::canDrawPath(const SkPath& path,
return true;
}
GrPathRenderer::StencilSupport GrSoftwarePathRenderer::onGetStencilSupport(
const SkPath&,
const SkStroke&,
const GrDrawTarget*) const {
return GrPathRenderer::kNoSupport_StencilSupport;
}
namespace {
////////////////////////////////////////////////////////////////////////////////

View File

@ -24,14 +24,18 @@ public:
: fContext(context) {
}
virtual bool canDrawPath(const SkPath& path,
const SkStroke& stroke,
const GrDrawTarget* target,
virtual bool canDrawPath(const SkPath&,
const SkStroke&,
const GrDrawTarget*,
bool antiAlias) const SK_OVERRIDE;
protected:
virtual bool onDrawPath(const SkPath& path,
const SkStroke& stroke,
GrDrawTarget* target,
virtual StencilSupport onGetStencilSupport(const SkPath&,
const SkStroke&,
const GrDrawTarget*) const SK_OVERRIDE;
virtual bool onDrawPath(const SkPath&,
const SkStroke&,
GrDrawTarget*,
bool antiAlias) SK_OVERRIDE;
private:

View File

@ -42,15 +42,16 @@ bool GrStencilAndCoverPathRenderer::canDrawPath(const SkPath& path,
target->getDrawState().getStencil().isDisabled();
}
bool GrStencilAndCoverPathRenderer::requiresStencilPass(const SkPath& path,
const SkStroke& stroke,
const GrDrawTarget* target) const {
return true;
GrPathRenderer::StencilSupport GrStencilAndCoverPathRenderer::onGetStencilSupport(
const SkPath&,
const SkStroke& ,
const GrDrawTarget*) const {
return GrPathRenderer::kStencilOnly_StencilSupport;
}
void GrStencilAndCoverPathRenderer::drawPathToStencil(const SkPath& path,
const SkStroke& stroke,
GrDrawTarget* target) {
void GrStencilAndCoverPathRenderer::onStencilPath(const SkPath& path,
const SkStroke& stroke,
GrDrawTarget* target) {
GrAssert(!path.isInverseFillType());
SkAutoTUnref<GrPath> p(fGpu->createPath(path));
target->stencilPath(p, stroke, path.getFillType());

View File

@ -21,31 +21,31 @@ class GrGpu;
class GrStencilAndCoverPathRenderer : public GrPathRenderer {
public:
static GrPathRenderer* Create(GrContext* context);
static GrPathRenderer* Create(GrContext*);
virtual ~GrStencilAndCoverPathRenderer();
virtual bool canDrawPath(const SkPath& path,
const SkStroke& stroke,
const GrDrawTarget* target,
virtual bool canDrawPath(const SkPath&,
const SkStroke&,
const GrDrawTarget*,
bool antiAlias) const SK_OVERRIDE;
virtual bool requiresStencilPass(const SkPath& path,
const SkStroke& stroke,
const GrDrawTarget* target) const SK_OVERRIDE;
virtual void drawPathToStencil(const SkPath& path,
const SkStroke& stroke,
GrDrawTarget* target) SK_OVERRIDE;
protected:
virtual bool onDrawPath(const SkPath& path,
const SkStroke& stroke,
GrDrawTarget* target,
virtual StencilSupport onGetStencilSupport(const SkPath&,
const SkStroke&,
const GrDrawTarget*) const SK_OVERRIDE;
virtual bool onDrawPath(const SkPath&,
const SkStroke&,
GrDrawTarget*,
bool antiAlias) SK_OVERRIDE;
virtual void onStencilPath(const SkPath&,
const SkStroke&,
GrDrawTarget*) SK_OVERRIDE;
private:
GrStencilAndCoverPathRenderer(GrGpu* gpu);
GrStencilAndCoverPathRenderer(GrGpu*);
GrGpu* fGpu;

View File

@ -284,6 +284,9 @@ bool GrGLProgram::genEdgeCoverage(SkString* coverageVar,
GrCrash("Unknown Edge Type!");
break;
}
if (fDesc.fDiscardIfOutsideEdge) {
builder->fFSCode.appendf("\tif (edgeAlpha <= 0) {\n\t\tdiscard;\n\t}\n");
}
*coverageVar = "edgeAlpha";
return true;
} else {

View File

@ -108,7 +108,10 @@ public:
kDualSrcOutputCnt
};
// TODO: remove these two members when edge-aa can be rewritten as a GrEffect.
GrDrawState::VertexEdgeType fVertexEdgeType;
// should the FS discard if the edge-aa coverage is zero (to avoid stencil manipulation)
bool fDiscardIfOutsideEdge;
// stripped of bits that don't affect program generation
GrVertexLayout fVertexLayout;

View File

@ -553,9 +553,11 @@ void GrGpuGL::buildProgram(bool isPoints,
if (!skipCoverage && (desc->fVertexLayout &GrDrawTarget::kEdge_VertexLayoutBit)) {
desc->fVertexEdgeType = drawState.getVertexEdgeType();
desc->fDiscardIfOutsideEdge = drawState.getStencil().doesWrite();
} else {
// use canonical value when not set to avoid cache misses
// Use canonical values when edge-aa is not enabled to avoid program cache misses.
desc->fVertexEdgeType = GrDrawState::kHairLine_EdgeType;
desc->fDiscardIfOutsideEdge = false;
}
for (int s = 0; s < GrDrawState::kNumStages; ++s) {

View File

@ -92,8 +92,10 @@ bool GrGpuGL::programUnitTest() {
pdesc.fVertexLayout |= GrDrawTarget::kEdge_VertexLayoutBit;
if (this->getCaps().shaderDerivativeSupport()) {
pdesc.fVertexEdgeType = (GrDrawState::VertexEdgeType) random_int(&random, GrDrawState::kVertexEdgeTypeCnt);
pdesc.fDiscardIfOutsideEdge = random.nextBool();
} else {
pdesc.fVertexEdgeType = GrDrawState::kHairLine_EdgeType;
pdesc.fDiscardIfOutsideEdge = false;
}
} else {
}