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:
parent
6f92862028
commit
45a15f551b
@ -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',
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
|
83
include/gpu/GrPathRendererChain.h
Normal file
83
include/gpu/GrPathRendererChain.h
Normal 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
|
@ -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();
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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
|
@ -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() &&
|
||||
|
@ -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 {
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -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:
|
||||
|
@ -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());
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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;
|
||||
|
@ -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) {
|
||||
|
@ -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 {
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user